/* * * Process the SCSI command * * Called with: * cdev -> Char dev file handle, * cdb -> SCSI Command buffer pointer, * struct vtl_ds -> general purpose data structure... Need better name * * Return: * SAM status returned in struct vtl_ds.sam_stat */ static void processCommand(int cdev, uint8_t *cdb, struct vtl_ds *dbuf_p, useconds_t pollInterval) { int err = 0; struct scsi_cmd _cmd; struct scsi_cmd *cmd; cmd = &_cmd; cmd->scb = cdb; cmd->scb_len = 16; /* fixme */ cmd->dbuf_p = dbuf_p; cmd->lu = &lunit; cmd->pollInterval = pollInterval; cmd->cdev = cdev; MHVTL_DBG_PRT_CDB(1, cmd); switch (cdb[0]) { case REPORT_LUNS: case REQUEST_SENSE: case MODE_SELECT: case INQUIRY: dbuf_p->sam_stat = SAM_STAT_GOOD; break; default: if (cmd->lu->online == 0) { sam_not_ready(E_OFFLINE, &dbuf_p->sam_stat); return; } if (check_reset(&dbuf_p->sam_stat)) return; } /* Skip main op code processing if pre-cmd returns non-zero */ if (cmd->lu->scsi_ops->ops[cdb[0]].pre_cmd_perform) err = cmd->lu->scsi_ops->ops[cdb[0]].pre_cmd_perform(cmd, NULL); if (!err) dbuf_p->sam_stat = cmd->lu->scsi_ops->ops[cdb[0]].cmd_perform(cmd); /* Post op code processing regardless */ if (cmd->lu->scsi_ops->ops[cdb[0]].post_cmd_perform) cmd->lu->scsi_ops->ops[cdb[0]].post_cmd_perform(cmd, NULL); return; }
/* * * Process the SCSI command * * Called with: * cdev -> Char dev file handle, * cdb -> SCSI Command buffer pointer, * struct vtl_ds -> general purpose data structure... Need better name * * Return: * SAM status returned in struct vtl_ds.sam_stat */ static void processCommand(int cdev, uint8_t *cdb, struct vtl_ds *dbuf_p, useconds_t pollInterval) { struct scsi_cmd _cmd; struct scsi_cmd *cmd; cmd = &_cmd; cmd->scb = cdb; cmd->scb_len = 16; /* fixme */ cmd->dbuf_p = dbuf_p; cmd->lu = &lunit; cmd->pollInterval = pollInterval; MHVTL_DBG_PRT_CDB(1, cmd); switch (cdb[0]) { case REPORT_LUNS: case REQUEST_SENSE: case MODE_SELECT: case INQUIRY: dbuf_p->sam_stat = SAM_STAT_GOOD; break; default: if (cmd->lu->online == 0) { mkSenseBuf(NOT_READY, E_OFFLINE, &dbuf_p->sam_stat); return; } if (check_reset(&dbuf_p->sam_stat)) return; } if (cmd->lu->scsi_ops->ops[cdb[0]].pre_cmd_perform) cmd->lu->scsi_ops->ops[cdb[0]].pre_cmd_perform(cmd, NULL); dbuf_p->sam_stat = cmd->lu->scsi_ops->ops[cdb[0]].cmd_perform(cmd); return; }
/* * Process the MODE_SELECT command */ uint8_t ssc_mode_select(struct scsi_cmd *cmd) { uint8_t *sam_stat = &cmd->dbuf_p->sam_stat; uint8_t *buf = cmd->dbuf_p->data; int block_descriptor_sz; int page_len; uint8_t *bdb = NULL; int i; int long_lba = 0; int count; int save_page; save_page = cmd->scb[1] & 0x01; switch (cmd->scb[0]) { case MODE_SELECT: cmd->dbuf_p->sz = cmd->scb[4]; break; case MODE_SELECT_10: cmd->dbuf_p->sz = get_unaligned_be16(&cmd->scb[7]); break; default: cmd->dbuf_p->sz = 0; } count = retrieve_CDB_data(cmd->cdev, cmd->dbuf_p); MHVTL_DBG(1, "MODE SELECT (%ld) **", (long)cmd->dbuf_p->serialNo); if (!(cmd->scb[1] & 0x10)) { /* Page Format: 1 - SPC, 0 - vendor uniq */ mkSenseBuf(ILLEGAL_REQUEST, E_INVALID_FIELD_IN_CDB, sam_stat); return SAM_STAT_CHECK_CONDITION; } switch (cmd->scb[0]) { case MODE_SELECT: block_descriptor_sz = buf[3]; if (block_descriptor_sz) bdb = &buf[4]; i = 4 + block_descriptor_sz; break; case MODE_SELECT_10: block_descriptor_sz = get_unaligned_be16(&buf[6]); long_lba = buf[4] & 1; if (block_descriptor_sz) bdb = &buf[8]; i = 8 + block_descriptor_sz; break; default: mkSenseBuf(ILLEGAL_REQUEST, E_INVALID_OP_CODE, sam_stat); return SAM_STAT_CHECK_CONDITION; } if (bdb) { if (long_lba) { mkSenseBuf(ILLEGAL_REQUEST, E_INVALID_FIELD_IN_CDB, sam_stat); MHVTL_DBG(1, "Warning can not " "handle long descriptor block (long_lba bit)"); return SAM_STAT_CHECK_CONDITION; } memcpy(modeBlockDescriptor, bdb, block_descriptor_sz); } /* Ignore mode pages if 'save page' bit not set */ if (!save_page) { MHVTL_DBG(1, "Save page bit not set. Ignoring page data"); return SAM_STAT_GOOD; } #ifdef MHVTL_DEBUG if (debug) hex_dump(buf, cmd->dbuf_p->sz); #endif MHVTL_DBG(3, "count: %d, i: %d", count, i); if (i == 4) { MHVTL_DBG(3, "Offset 0: %02x %02x %02x %02x", buf[0], buf[1], buf[2], buf[3]); } else { MHVTL_DBG(3, "Offset 0: %02x %02x %02x %02x %02x %02x %02x %02x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); } count -= i; while (i < count) { MHVTL_DBG(3, " %02d: %02x %02x %02x %02x %02x %02x %02x %02x", i, buf[i+0], buf[i+1], buf[i+2], buf[i+3], buf[i+4], buf[i+5], buf[i+6], buf[i+7]); MHVTL_DBG(3, " %02d: %02x %02x %02x %02x %02x %02x %02x %02x", i+8, buf[i+8], buf[i+9], buf[i+10], buf[i+11], buf[i+12], buf[i+13], buf[i+14], buf[i+15]); MHVTL_DBG(3, " %02d: %02x %02x %02x %02x %02x %02x %02x %02x", i+16, buf[i+16], buf[i+17], buf[i+18], buf[i+19], buf[i+20], buf[i+21], buf[i+22], buf[i+23]); MHVTL_DBG(3, " %02d: %02x %02x %02x %02x %02x %02x %02x %02x", i+24, buf[i+24], buf[i+25], buf[i+26], buf[i+27], buf[i+28], buf[i+29], buf[i+30], buf[i+31]); /* Default page len is, override if sub-pages */ page_len = buf[i + 1]; switch (buf[i]) { case MODE_DATA_COMPRESSION: set_mode_compression(cmd, &buf[i]); break; case MODE_DEVICE_CONFIGURATION: /* If this is '01' it's a subpage value * i.e. DEVICE CONFIGURATION EXTENSION * If it's 0x0e, it indicates a page length * for MODE DEVICE CONFIGURATION */ if (buf[i + 1] == 0x01) { if (set_device_configuration_extension(cmd, &buf[i])) return SAM_STAT_CHECK_CONDITION; /* Subpage 1 - override default page length */ page_len = get_unaligned_be16(&buf[i + 2]); } else set_device_configuration(cmd, &buf[i]); break; default: MHVTL_DBG_PRT_CDB(1, cmd); MHVTL_DBG(1, "Mode page 0x%02x not handled", buf[i]); break; } if (page_len == 0) { /* Something wrong with data structure */ page_len = cmd->dbuf_p->sz; MHVTL_LOG("Problem with mode select data structure"); } i += page_len; /* Next mode page */ } return SAM_STAT_GOOD; }