s390/Kconfig: sort config S390 select list once again
[linux-2.6-microblaze.git] / drivers / scsi / scsi_lib.c
index 03c6d06..4848ae3 100644 (file)
@@ -766,6 +766,9 @@ static void scsi_io_completion_action(struct scsi_cmnd *cmd, int result)
                                case 0x24: /* depopulation in progress */
                                        action = ACTION_DELAYED_RETRY;
                                        break;
+                               case 0x0a: /* ALUA state transition */
+                                       blk_stat = BLK_STS_AGAIN;
+                                       fallthrough;
                                default:
                                        action = ACTION_FAIL;
                                        break;
@@ -1455,7 +1458,7 @@ static void scsi_softirq_done(struct request *rq)
 }
 
 /**
- * scsi_dispatch_command - Dispatch a command to the low-level driver.
+ * scsi_dispatch_cmd - Dispatch a command to the low-level driver.
  * @cmd: command block we are dispatching.
  *
  * Return: nonzero return request was rejected and device's queue needs to be
@@ -1706,6 +1709,11 @@ out_put_budget:
                if (scsi_device_blocked(sdev))
                        ret = BLK_STS_DEV_RESOURCE;
                break;
+       case BLK_STS_AGAIN:
+               scsi_req(req)->result = DID_BUS_BUSY << 16;
+               if (req->rq_flags & RQF_DONTPREP)
+                       scsi_mq_uninit_cmd(cmd);
+               break;
        default:
                if (unlikely(!scsi_device_online(sdev)))
                        scsi_req(req)->result = DID_NO_CONNECT << 16;
@@ -2334,7 +2342,7 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
 EXPORT_SYMBOL(scsi_device_set_state);
 
 /**
- *     sdev_evt_emit - emit a single SCSI device uevent
+ *     scsi_evt_emit - emit a single SCSI device uevent
  *     @sdev: associated SCSI device
  *     @evt: event to emit
  *
@@ -2382,7 +2390,7 @@ static void scsi_evt_emit(struct scsi_device *sdev, struct scsi_event *evt)
 }
 
 /**
- *     sdev_evt_thread - send a uevent for each scsi event
+ *     scsi_evt_thread - send a uevent for each scsi event
  *     @work: work struct for scsi_device
  *
  *     Dispatch queued events to their associated scsi_device kobjects
@@ -2948,6 +2956,78 @@ void sdev_enable_disk_events(struct scsi_device *sdev)
 }
 EXPORT_SYMBOL(sdev_enable_disk_events);
 
+static unsigned char designator_prio(const unsigned char *d)
+{
+       if (d[1] & 0x30)
+               /* not associated with LUN */
+               return 0;
+
+       if (d[3] == 0)
+               /* invalid length */
+               return 0;
+
+       /*
+        * Order of preference for lun descriptor:
+        * - SCSI name string
+        * - NAA IEEE Registered Extended
+        * - EUI-64 based 16-byte
+        * - EUI-64 based 12-byte
+        * - NAA IEEE Registered
+        * - NAA IEEE Extended
+        * - EUI-64 based 8-byte
+        * - SCSI name string (truncated)
+        * - T10 Vendor ID
+        * as longer descriptors reduce the likelyhood
+        * of identification clashes.
+        */
+
+       switch (d[1] & 0xf) {
+       case 8:
+               /* SCSI name string, variable-length UTF-8 */
+               return 9;
+       case 3:
+               switch (d[4] >> 4) {
+               case 6:
+                       /* NAA registered extended */
+                       return 8;
+               case 5:
+                       /* NAA registered */
+                       return 5;
+               case 4:
+                       /* NAA extended */
+                       return 4;
+               case 3:
+                       /* NAA locally assigned */
+                       return 1;
+               default:
+                       break;
+               }
+               break;
+       case 2:
+               switch (d[3]) {
+               case 16:
+                       /* EUI64-based, 16 byte */
+                       return 7;
+               case 12:
+                       /* EUI64-based, 12 byte */
+                       return 6;
+               case 8:
+                       /* EUI64-based, 8 byte */
+                       return 3;
+               default:
+                       break;
+               }
+               break;
+       case 1:
+               /* T10 vendor ID */
+               return 1;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
 /**
  * scsi_vpd_lun_id - return a unique device identification
  * @sdev: SCSI device
@@ -2964,7 +3044,7 @@ EXPORT_SYMBOL(sdev_enable_disk_events);
  */
 int scsi_vpd_lun_id(struct scsi_device *sdev, char *id, size_t id_len)
 {
-       u8 cur_id_type = 0xff;
+       u8 cur_id_prio = 0;
        u8 cur_id_size = 0;
        const unsigned char *d, *cur_id_str;
        const struct scsi_vpd *vpd_pg83;
@@ -2977,20 +3057,6 @@ int scsi_vpd_lun_id(struct scsi_device *sdev, char *id, size_t id_len)
                return -ENXIO;
        }
 
-       /*
-        * Look for the correct descriptor.
-        * Order of preference for lun descriptor:
-        * - SCSI name string
-        * - NAA IEEE Registered Extended
-        * - EUI-64 based 16-byte
-        * - EUI-64 based 12-byte
-        * - NAA IEEE Registered
-        * - NAA IEEE Extended
-        * - T10 Vendor ID
-        * as longer descriptors reduce the likelyhood
-        * of identification clashes.
-        */
-
        /* The id string must be at least 20 bytes + terminating NULL byte */
        if (id_len < 21) {
                rcu_read_unlock();
@@ -2998,39 +3064,32 @@ int scsi_vpd_lun_id(struct scsi_device *sdev, char *id, size_t id_len)
        }
 
        memset(id, 0, id_len);
-       d = vpd_pg83->data + 4;
-       while (d < vpd_pg83->data + vpd_pg83->len) {
-               /* Skip designators not referring to the LUN */
-               if ((d[1] & 0x30) != 0x00)
-                       goto next_desig;
+       for (d = vpd_pg83->data + 4;
+            d < vpd_pg83->data + vpd_pg83->len;
+            d += d[3] + 4) {
+               u8 prio = designator_prio(d);
+
+               if (prio == 0 || cur_id_prio > prio)
+                       continue;
 
                switch (d[1] & 0xf) {
                case 0x1:
                        /* T10 Vendor ID */
                        if (cur_id_size > d[3])
                                break;
-                       /* Prefer anything */
-                       if (cur_id_type > 0x01 && cur_id_type != 0xff)
-                               break;
+                       cur_id_prio = prio;
                        cur_id_size = d[3];
                        if (cur_id_size + 4 > id_len)
                                cur_id_size = id_len - 4;
                        cur_id_str = d + 4;
-                       cur_id_type = d[1] & 0xf;
                        id_size = snprintf(id, id_len, "t10.%*pE",
                                           cur_id_size, cur_id_str);
                        break;
                case 0x2:
                        /* EUI-64 */
-                       if (cur_id_size > d[3])
-                               break;
-                       /* Prefer NAA IEEE Registered Extended */
-                       if (cur_id_type == 0x3 &&
-                           cur_id_size == d[3])
-                               break;
+                       cur_id_prio = prio;
                        cur_id_size = d[3];
                        cur_id_str = d + 4;
-                       cur_id_type = d[1] & 0xf;
                        switch (cur_id_size) {
                        case 8:
                                id_size = snprintf(id, id_len,
@@ -3048,17 +3107,14 @@ int scsi_vpd_lun_id(struct scsi_device *sdev, char *id, size_t id_len)
                                                   cur_id_str);
                                break;
                        default:
-                               cur_id_size = 0;
                                break;
                        }
                        break;
                case 0x3:
                        /* NAA */
-                       if (cur_id_size > d[3])
-                               break;
+                       cur_id_prio = prio;
                        cur_id_size = d[3];
                        cur_id_str = d + 4;
-                       cur_id_type = d[1] & 0xf;
                        switch (cur_id_size) {
                        case 8:
                                id_size = snprintf(id, id_len,
@@ -3071,32 +3127,29 @@ int scsi_vpd_lun_id(struct scsi_device *sdev, char *id, size_t id_len)
                                                   cur_id_str);
                                break;
                        default:
-                               cur_id_size = 0;
                                break;
                        }
                        break;
                case 0x8:
                        /* SCSI name string */
-                       if (cur_id_size + 4 > d[3])
+                       if (cur_id_size > d[3])
                                break;
                        /* Prefer others for truncated descriptor */
-                       if (cur_id_size && d[3] > id_len)
-                               break;
+                       if (d[3] > id_len) {
+                               prio = 2;
+                               if (cur_id_prio > prio)
+                                       break;
+                       }
+                       cur_id_prio = prio;
                        cur_id_size = id_size = d[3];
                        cur_id_str = d + 4;
-                       cur_id_type = d[1] & 0xf;
                        if (cur_id_size >= id_len)
                                cur_id_size = id_len - 1;
                        memcpy(id, cur_id_str, cur_id_size);
-                       /* Decrease priority for truncated descriptor */
-                       if (cur_id_size != id_size)
-                               cur_id_size = 6;
                        break;
                default:
                        break;
                }
-next_desig:
-               d += d[3] + 4;
        }
        rcu_read_unlock();