OSDN Git Service

Merge tag 'block-5.14-2021-07-08' of git://git.kernel.dk/linux-block
[uclinux-h8/linux.git] / drivers / scsi / scsi_lib.c
index 6cc7dad..c9a91a5 100644 (file)
@@ -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_DRV_OUT : REQ_OP_DRV_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);