+#define CMD_READ_SAFE 0x01
+#define CMD_WRITE_SAFE 0x02
+#define CMD_WARNED 0x04
+#define safe_for_read(cmd) [cmd] = CMD_READ_SAFE
+#define safe_for_write(cmd) [cmd] = CMD_WRITE_SAFE
+
+static int verify_command(struct file *file, unsigned char *cmd)
+{
+ static unsigned char cmd_type[256] = {
+
+ /* Basic read-only commands */
+ safe_for_read(TEST_UNIT_READY),
+ safe_for_read(REQUEST_SENSE),
+ safe_for_read(READ_6),
+ safe_for_read(READ_10),
+ safe_for_read(READ_12),
+ safe_for_read(READ_16),
+ safe_for_read(READ_BUFFER),
+ safe_for_read(READ_LONG),
+ safe_for_read(INQUIRY),
+ safe_for_read(MODE_SENSE),
+ safe_for_read(MODE_SENSE_10),
+ safe_for_read(LOG_SENSE),
+ safe_for_read(START_STOP),
+ safe_for_read(GPCMD_VERIFY_10),
+ safe_for_read(VERIFY_16),
+
+ /* Audio CD commands */
+ safe_for_read(GPCMD_PLAY_CD),
+ safe_for_read(GPCMD_PLAY_AUDIO_10),
+ safe_for_read(GPCMD_PLAY_AUDIO_MSF),
+ safe_for_read(GPCMD_PLAY_AUDIO_TI),
+ safe_for_read(GPCMD_PAUSE_RESUME),
+
+ /* CD/DVD data reading */
+ safe_for_read(GPCMD_READ_BUFFER_CAPACITY),
+ safe_for_read(GPCMD_READ_CD),
+ safe_for_read(GPCMD_READ_CD_MSF),
+ safe_for_read(GPCMD_READ_DISC_INFO),
+ safe_for_read(GPCMD_READ_CDVD_CAPACITY),
+ safe_for_read(GPCMD_READ_DVD_STRUCTURE),
+ safe_for_read(GPCMD_READ_HEADER),
+ safe_for_read(GPCMD_READ_TRACK_RZONE_INFO),
+ safe_for_read(GPCMD_READ_SUBCHANNEL),
+ safe_for_read(GPCMD_READ_TOC_PMA_ATIP),
+ safe_for_read(GPCMD_REPORT_KEY),
+ safe_for_read(GPCMD_SCAN),
+ safe_for_read(GPCMD_GET_CONFIGURATION),
+ safe_for_read(GPCMD_READ_FORMAT_CAPACITIES),
+ safe_for_read(GPCMD_GET_EVENT_STATUS_NOTIFICATION),
+ safe_for_read(GPCMD_GET_PERFORMANCE),
+ safe_for_read(GPCMD_SEEK),
+ safe_for_read(GPCMD_STOP_PLAY_SCAN),
+
+ /* Basic writing commands */
+ safe_for_write(WRITE_6),
+ safe_for_write(WRITE_10),
+ safe_for_write(WRITE_VERIFY),
+ safe_for_write(WRITE_12),
+ safe_for_write(WRITE_VERIFY_12),
+ safe_for_write(WRITE_16),
+ safe_for_write(WRITE_LONG),
+ safe_for_write(ERASE),
+ safe_for_write(GPCMD_MODE_SELECT_10),
+ safe_for_write(MODE_SELECT),
+ safe_for_write(LOG_SELECT),
+ safe_for_write(GPCMD_BLANK),
+ safe_for_write(GPCMD_CLOSE_TRACK),
+ safe_for_write(GPCMD_FLUSH_CACHE),
+ safe_for_write(GPCMD_FORMAT_UNIT),
+ safe_for_write(GPCMD_REPAIR_RZONE_TRACK),
+ safe_for_write(GPCMD_RESERVE_RZONE_TRACK),
+ safe_for_write(GPCMD_SEND_DVD_STRUCTURE),
+ safe_for_write(GPCMD_SEND_EVENT),
+ safe_for_write(GPCMD_SEND_KEY),
+ safe_for_write(GPCMD_SEND_OPC),
+ safe_for_write(GPCMD_SEND_CUE_SHEET),
+ safe_for_write(GPCMD_SET_SPEED),
+ safe_for_write(GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL),
+ safe_for_write(GPCMD_LOAD_UNLOAD),
+ safe_for_write(GPCMD_SET_STREAMING),
+ };
+ unsigned char type = cmd_type[cmd[0]];
+
+ /* Anybody who can open the device can do a read-safe command */
+ if (type & CMD_READ_SAFE)
+ return 0;
+
+ /* Write-safe commands just require a writable open.. */
+ if (type & CMD_WRITE_SAFE) {
+ if (file->f_mode & FMODE_WRITE)
+ return 0;
+ }
+
+ if (!type) {
+ cmd_type[cmd[0]] = CMD_WARNED;
+ printk(KERN_WARNING "scsi: unknown opcode 0x%02x\n", cmd[0]);
+ }
+
+ /* And root can do any command.. */
+ if (capable(CAP_SYS_RAWIO))
+ return 0;
+
+ /* Otherwise fail it with an "Operation not permitted" */
+ return -EPERM;
+}
+
+static int sg_io(struct file *file, request_queue_t *q,
+ struct gendisk *bd_disk, struct sg_io_hdr *hdr)