diff options
Diffstat (limited to 'drivers/scsi/scsi_lib.c')
-rw-r--r-- | drivers/scsi/scsi_lib.c | 119 |
1 files changed, 67 insertions, 52 deletions
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 532304d42f00..6b994baf87c2 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -211,20 +211,23 @@ int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, { struct request *req; struct scsi_request *rq; - int ret = DRIVER_ERROR << 24; + int ret; req = blk_get_request(sdev->request_queue, data_direction == DMA_TO_DEVICE ? REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, rq_flags & RQF_PM ? BLK_MQ_REQ_PM : 0); if (IS_ERR(req)) - return ret; - rq = scsi_req(req); + return PTR_ERR(req); - if (bufflen && blk_rq_map_kern(sdev->request_queue, req, - buffer, bufflen, GFP_NOIO)) - goto out; + rq = scsi_req(req); + if (bufflen) { + ret = blk_rq_map_kern(sdev->request_queue, req, + buffer, bufflen, GFP_NOIO); + if (ret) + goto out; + } rq->cmd_len = COMMAND_SIZE(cmd[0]); memcpy(rq->cmd, cmd, rq->cmd_len); rq->retries = retries; @@ -588,12 +591,7 @@ static blk_status_t scsi_result_to_blk_status(struct scsi_cmnd *cmd, int result) { switch (host_byte(result)) { case DID_OK: - /* - * Also check the other bytes than the status byte in result - * to handle the case when a SCSI LLD sets result to - * DRIVER_SENSE << 24 without setting SAM_STAT_CHECK_CONDITION. - */ - if (scsi_status_is_good(result) && (result & ~0xff) == 0) + if (scsi_status_is_good(result)) return BLK_STS_OK; return BLK_STS_IOERR; case DID_TRANSPORT_FAILFAST: @@ -787,7 +785,7 @@ static void scsi_io_completion_action(struct scsi_cmnd *cmd, int result) */ if (!level && __ratelimit(&_rs)) { scsi_print_result(cmd, NULL, FAILED); - if (driver_byte(result) == DRIVER_SENSE) + if (sense_valid) scsi_print_sense(cmd); scsi_print_command(cmd); } @@ -875,7 +873,7 @@ static int scsi_io_completion_nz_result(struct scsi_cmnd *cmd, int result, * if it can't fit). Treat SAM_STAT_CONDITION_MET and the related * intermediate statuses (both obsolete in SAM-4) as good. */ - if (status_byte(result) && scsi_status_is_good(result)) { + if ((result & 0xff) && scsi_status_is_good(result)) { result = 0; *blk_statp = BLK_STS_OK; } @@ -2093,9 +2091,7 @@ EXPORT_SYMBOL_GPL(scsi_mode_select); * @sshdr: place to put sense data (or NULL if no sense to be collected). * must be SCSI_SENSE_BUFFERSIZE big. * - * Returns zero if unsuccessful, or the header offset (either 4 - * or 8 depending on whether a six or ten byte command was - * issued) if successful. + * Returns zero if successful, or a negative error number on failure */ int scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, @@ -2142,58 +2138,60 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, len, sshdr, timeout, retries, NULL); + if (result < 0) + return result; /* This code looks awful: what it's doing is making sure an * ILLEGAL REQUEST sense return identifies the actual command * byte as the problem. MODE_SENSE commands can return * ILLEGAL REQUEST if the code page isn't supported */ - if (use_10_for_ms && !scsi_status_is_good(result) && - driver_byte(result) == DRIVER_SENSE) { + if (!scsi_status_is_good(result)) { if (scsi_sense_valid(sshdr)) { if ((sshdr->sense_key == ILLEGAL_REQUEST) && (sshdr->asc == 0x20) && (sshdr->ascq == 0)) { /* * Invalid command operation code */ - sdev->use_10_for_ms = 0; + if (use_10_for_ms) { + sdev->use_10_for_ms = 0; + goto retry; + } + } + if (scsi_status_is_check_condition(result) && + sshdr->sense_key == UNIT_ATTENTION && + retry_count) { + retry_count--; goto retry; } } + return -EIO; + } + if (unlikely(buffer[0] == 0x86 && buffer[1] == 0x0b && + (modepage == 6 || modepage == 8))) { + /* Initio breakage? */ + header_length = 0; + data->length = 13; + data->medium_type = 0; + data->device_specific = 0; + data->longlba = 0; + data->block_descriptor_length = 0; + } else if (use_10_for_ms) { + data->length = buffer[0]*256 + buffer[1] + 2; + data->medium_type = buffer[2]; + data->device_specific = buffer[3]; + data->longlba = buffer[4] & 0x01; + data->block_descriptor_length = buffer[6]*256 + + buffer[7]; + } else { + data->length = buffer[0] + 1; + data->medium_type = buffer[1]; + data->device_specific = buffer[2]; + data->block_descriptor_length = buffer[3]; } + data->header_length = header_length; - if (scsi_status_is_good(result)) { - if (unlikely(buffer[0] == 0x86 && buffer[1] == 0x0b && - (modepage == 6 || modepage == 8))) { - /* Initio breakage? */ - header_length = 0; - data->length = 13; - data->medium_type = 0; - data->device_specific = 0; - data->longlba = 0; - data->block_descriptor_length = 0; - } else if (use_10_for_ms) { - data->length = buffer[0]*256 + buffer[1] + 2; - data->medium_type = buffer[2]; - data->device_specific = buffer[3]; - data->longlba = buffer[4] & 0x01; - data->block_descriptor_length = buffer[6]*256 - + buffer[7]; - } else { - data->length = buffer[0] + 1; - data->medium_type = buffer[1]; - data->device_specific = buffer[2]; - data->block_descriptor_length = buffer[3]; - } - data->header_length = header_length; - } else if ((status_byte(result) == CHECK_CONDITION) && - scsi_sense_valid(sshdr) && - sshdr->sense_key == UNIT_ATTENTION && retry_count) { - retry_count--; - goto retry; - } - - return result; + return 0; } EXPORT_SYMBOL(scsi_mode_sense); @@ -3218,3 +3216,20 @@ int scsi_vpd_tpg_id(struct scsi_device *sdev, int *rel_id) return group_id; } EXPORT_SYMBOL(scsi_vpd_tpg_id); + +/** + * scsi_build_sense - build sense data for a command + * @scmd: scsi command for which the sense should be formatted + * @desc: Sense format (non-zero == descriptor format, + * 0 == fixed format) + * @key: Sense key + * @asc: Additional sense code + * @ascq: Additional sense code qualifier + * + **/ +void scsi_build_sense(struct scsi_cmnd *scmd, int desc, u8 key, u8 asc, u8 ascq) +{ + scsi_build_sense_buffer(desc, scmd->sense_buffer, key, asc, ascq); + scmd->result = SAM_STAT_CHECK_CONDITION; +} +EXPORT_SYMBOL_GPL(scsi_build_sense); |