extractedLnx/linux-2.6.36/drivers/scsi/scsi_debug.c_scsi_debug_queuecommand.c
static
int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
{
unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
int len, k;
unsigned int num;
unsigned long long lba;
u32 ei_lba;
int errsts = 0;
int target = SCpnt->device->id;
struct sdebug_dev_info *devip = NULL;
int inj_recovered = 0;
int inj_transport = 0;
int inj_dif = 0;
int inj_dix = 0;
int delay_override = 0;
int unmap = 0;
scsi_set_resid(SCpnt, 0);
if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
printk(KERN_INFO "scsi_debug: cmd ");
for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
printk("%02x ", (int)cmd[k]);
printk("\n");
}
if (target == SCpnt->device->host->hostt->this_id) {
printk(KERN_INFO "scsi_debug: initiator's id used as "
"target!\n");
return schedule_resp(SCpnt, NULL, done,
DID_NO_CONNECT << 16, 0);
}
if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
(SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
return schedule_resp(SCpnt, NULL, done,
DID_NO_CONNECT << 16, 0);
devip = devInfoReg(SCpnt->device);
if (NULL == devip)
return schedule_resp(SCpnt, NULL, done,
DID_NO_CONNECT << 16, 0);
if ((scsi_debug_every_nth != 0) &&
(++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
scsi_debug_cmnd_count = 0;
if (scsi_debug_every_nth < -1)
scsi_debug_every_nth = -1;
if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
return 0; /* ignore command causing timeout */
else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
inj_recovered = 1; /* to reads and writes below */
else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
inj_transport = 1; /* to reads and writes below */
else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts)
inj_dif = 1; /* to reads and writes below */
else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts)
inj_dix = 1; /* to reads and writes below */
}
if (devip->wlun) {
switch (*cmd) {
case INQUIRY:
case REQUEST_SENSE:
case TEST_UNIT_READY:
case REPORT_LUNS:
break; /* only allowable wlun commands */
default:
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
"not supported for wlun\n", *cmd);
mk_sense_buffer(devip, ILLEGAL_REQUEST,
INVALID_OPCODE, 0);
errsts = check_condition_result;
return schedule_resp(SCpnt, devip, done, errsts,
0);
}
}
switch (*cmd) {
case INQUIRY: /* mandatory, ignore unit attention */
delay_override = 1;
errsts = resp_inquiry(SCpnt, target, devip);
break;
case REQUEST_SENSE: /* mandatory, ignore unit attention */
delay_override = 1;
errsts = resp_requests(SCpnt, devip);
break;
case REZERO_UNIT: /* actually this is REWIND for SSC */
case START_STOP:
errsts = resp_start_stop(SCpnt, devip);
break;
case ALLOW_MEDIUM_REMOVAL:
errsts = check_readiness(SCpnt, 1, devip);
if (errsts)
break;
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
printk(KERN_INFO "scsi_debug: Medium removal %s\n",
cmd[4] ? "inhibited" : "enabled");
break;
case SEND_DIAGNOSTIC: /* mandatory */
errsts = check_readiness(SCpnt, 1, devip);
break;
case TEST_UNIT_READY: /* mandatory */
delay_override = 1;
errsts = check_readiness(SCpnt, 0, devip);
break;
case RESERVE:
errsts = check_readiness(SCpnt, 1, devip);
break;
case RESERVE_10:
errsts = check_readiness(SCpnt, 1, devip);
break;
case RELEASE:
errsts = check_readiness(SCpnt, 1, devip);
break;
case RELEASE_10:
errsts = check_readiness(SCpnt, 1, devip);
break;
case READ_CAPACITY:
errsts = resp_readcap(SCpnt, devip);
break;
case SERVICE_ACTION_IN:
if (cmd[1] == SAI_READ_CAPACITY_16)
errsts = resp_readcap16(SCpnt, devip);
else if (cmd[1] == SAI_GET_LBA_STATUS) {
if (scsi_debug_unmap_max_desc == 0) {
mk_sense_buffer(devip, ILLEGAL_REQUEST,
INVALID_COMMAND_OPCODE, 0);
errsts = check_condition_result;
} else
errsts = resp_get_lba_status(SCpnt, devip);
} else {
mk_sense_buffer(devip, ILLEGAL_REQUEST,
INVALID_OPCODE, 0);
errsts = check_condition_result;
}
break;
case MAINTENANCE_IN:
if (MI_REPORT_TARGET_PGS != cmd[1]) {
mk_sense_buffer(devip, ILLEGAL_REQUEST,
INVALID_OPCODE, 0);
errsts = check_condition_result;
break;
}
errsts = resp_report_tgtpgs(SCpnt, devip);
break;
case READ_16:
case READ_12:
case READ_10:
/* READ{10,12,16} and DIF Type 2 are natural enemies */
if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
cmd[1] & 0xe0) {
mk_sense_buffer(devip, ILLEGAL_REQUEST,
INVALID_COMMAND_OPCODE, 0);
errsts = check_condition_result;
break;
}
if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
(cmd[1] & 0xe0) == 0)
printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
/* fall through */
case READ_6:
read:
errsts = check_readiness(SCpnt, 0, devip);
if (errsts)
break;
if (scsi_debug_fake_rw)
break;
get_data_transfer_info(cmd, &lba, &num, &ei_lba);
errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
if (inj_recovered && (0 == errsts)) {
mk_sense_buffer(devip, RECOVERED_ERROR,
THRESHOLD_EXCEEDED, 0);
errsts = check_condition_result;
} else if (inj_transport && (0 == errsts)) {
mk_sense_buffer(devip, ABORTED_COMMAND,
TRANSPORT_PROBLEM, ACK_NAK_TO);
errsts = check_condition_result;
} else if (inj_dif && (0 == errsts)) {
mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
errsts = illegal_condition_result;
} else if (inj_dix && (0 == errsts)) {
mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
errsts = illegal_condition_result;
}
break;
case REPORT_LUNS: /* mandatory, ignore unit attention */
delay_override = 1;
errsts = resp_report_luns(SCpnt, devip);
break;
case VERIFY: /* 10 byte SBC-2 command */
errsts = check_readiness(SCpnt, 0, devip);
break;
case WRITE_16:
case WRITE_12:
case WRITE_10:
/* WRITE{10,12,16} and DIF Type 2 are natural enemies */
if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
cmd[1] & 0xe0) {
mk_sense_buffer(devip, ILLEGAL_REQUEST,
INVALID_COMMAND_OPCODE, 0);
errsts = check_condition_result;
break;
}
if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
(cmd[1] & 0xe0) == 0)
printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
/* fall through */
case WRITE_6:
write:
errsts = check_readiness(SCpnt, 0, devip);
if (errsts)
break;
if (scsi_debug_fake_rw)
break;
get_data_transfer_info(cmd, &lba, &num, &ei_lba);
errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
if (inj_recovered && (0 == errsts)) {
mk_sense_buffer(devip, RECOVERED_ERROR,
THRESHOLD_EXCEEDED, 0);
errsts = check_condition_result;
} else if (inj_dif && (0 == errsts)) {
mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
errsts = illegal_condition_result;
} else if (inj_dix && (0 == errsts)) {
mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
errsts = illegal_condition_result;
}
break;
case WRITE_SAME_16:
if (cmd[1] & 0x8)
unmap = 1;
/* fall through */
case WRITE_SAME:
errsts = check_readiness(SCpnt, 0, devip);
if (errsts)
break;
get_data_transfer_info(cmd, &lba, &num, &ei_lba);
errsts = resp_write_same(SCpnt, lba, num, devip, ei_lba, unmap);
break;
case UNMAP:
errsts = check_readiness(SCpnt, 0, devip);
if (errsts)
break;
if (scsi_debug_unmap_max_desc == 0) {
mk_sense_buffer(devip, ILLEGAL_REQUEST,
INVALID_COMMAND_OPCODE, 0);
errsts = check_condition_result;
} else
errsts = resp_unmap(SCpnt, devip);
break;
case MODE_SENSE:
case MODE_SENSE_10:
errsts = resp_mode_sense(SCpnt, target, devip);
break;
case MODE_SELECT:
errsts = resp_mode_select(SCpnt, 1, devip);
break;
case MODE_SELECT_10:
errsts = resp_mode_select(SCpnt, 0, devip);
break;
case LOG_SENSE:
errsts = resp_log_sense(SCpnt, devip);
break;
case SYNCHRONIZE_CACHE:
delay_override = 1;
errsts = check_readiness(SCpnt, 0, devip);
break;
case WRITE_BUFFER:
errsts = check_readiness(SCpnt, 1, devip);
break;
case XDWRITEREAD_10:
if (!scsi_bidi_cmnd(SCpnt)) {
mk_sense_buffer(devip, ILLEGAL_REQUEST,
INVALID_FIELD_IN_CDB, 0);
errsts = check_condition_result;
break;
}
errsts = check_readiness(SCpnt, 0, devip);
if (errsts)
break;
if (scsi_debug_fake_rw)
break;
get_data_transfer_info(cmd, &lba, &num, &ei_lba);
errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
if (errsts)
break;
errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
if (errsts)
break;
errsts = resp_xdwriteread(SCpnt, lba, num, devip);
break;
case VARIABLE_LENGTH_CMD:
if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION) {
if ((cmd[10] & 0xe0) == 0)
printk(KERN_ERR
"Unprotected RD/WR to DIF device\n");
if (cmd[9] == READ_32) {
BUG_ON(SCpnt->cmd_len < 32);
goto read;
}
if (cmd[9] == WRITE_32) {
BUG_ON(SCpnt->cmd_len < 32);
goto write;
}
}
mk_sense_buffer(devip, ILLEGAL_REQUEST,
INVALID_FIELD_IN_CDB, 0);
errsts = check_condition_result;
break;
default:
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
"supported\n", *cmd);
errsts = check_readiness(SCpnt, 1, devip);
if (errsts)
break; /* Unit attention takes precedence */
mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
errsts = check_condition_result;
break;
}
return schedule_resp(SCpnt, devip, done, errsts,
(delay_override ? 0 : scsi_debug_delay));
}
Generated by GNU enscript 1.6.4.