aacraid: vpd page code 0x83 support
authorMahesh Rajashekhara <Mahesh.Rajashekhara@pmcs.com>
Thu, 26 Mar 2015 14:41:26 +0000 (10:41 -0400)
committerJames Bottomley <JBottomley@Odin.com>
Thu, 9 Apr 2015 23:51:29 +0000 (16:51 -0700)
Signed-off-by: Mahesh Rajashekhara <Mahesh.Rajashekhara@pmcs.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Murthy Bhat <Murthy.Bhat@pmcs.com>
Signed-off-by: James Bottomley <JBottomley@Odin.com>
drivers/scsi/aacraid/aachba.c

index aee3eaa0bd5d81180266639f612c71c8b03c857f..09027e9edfd5922eb5e4fa5e965ddea4b145cd46 100644 (file)
@@ -163,6 +163,48 @@ struct inquiry_data {
        u8 inqd_prl[4]; /* Product Revision Level */
 };
 
+/* Added for VPD 0x83 */
+typedef struct {
+       u8 CodeSet:4;   /* VPD_CODE_SET */
+       u8 Reserved:4;
+       u8 IdentifierType:4;    /* VPD_IDENTIFIER_TYPE */
+       u8 Reserved2:4;
+       u8 Reserved3;
+       u8 IdentifierLength;
+       u8 VendId[8];
+       u8 ProductId[16];
+       u8 SerialNumber[8];     /* SN in ASCII */
+
+} TVPD_ID_Descriptor_Type_1;
+
+typedef struct {
+       u8 CodeSet:4;   /* VPD_CODE_SET */
+       u8 Reserved:4;
+       u8 IdentifierType:4;    /* VPD_IDENTIFIER_TYPE */
+       u8 Reserved2:4;
+       u8 Reserved3;
+       u8 IdentifierLength;
+       struct TEU64Id {
+               u32 Serial;
+                /* The serial number supposed to be 40 bits,
+                 * bit we only support 32, so make the last byte zero. */
+               u8 Reserved;
+               u8 VendId[3];
+       } EU64Id;
+
+} TVPD_ID_Descriptor_Type_2;
+
+typedef struct {
+       u8 DeviceType:5;
+       u8 DeviceTypeQualifier:3;
+       u8 PageCode;
+       u8 Reserved;
+       u8 PageLength;
+       TVPD_ID_Descriptor_Type_1 IdDescriptorType1;
+       TVPD_ID_Descriptor_Type_2 IdDescriptorType2;
+
+} TVPD_Page83;
+
 /*
  *              M O D U L E   G L O B A L S
  */
@@ -890,14 +932,88 @@ static void get_container_serial_callback(void *context, struct fib * fibptr)
        get_serial_reply = (struct aac_get_serial_resp *) fib_data(fibptr);
        /* Failure is irrelevant, using default value instead */
        if (le32_to_cpu(get_serial_reply->status) == CT_OK) {
-               char sp[13];
-               /* EVPD bit set */
-               sp[0] = INQD_PDT_DA;
-               sp[1] = scsicmd->cmnd[2];
-               sp[2] = 0;
-               sp[3] = snprintf(sp+4, sizeof(sp)-4, "%08X",
-                 le32_to_cpu(get_serial_reply->uid));
-               scsi_sg_copy_from_buffer(scsicmd, sp, sizeof(sp));
+               /*Check to see if it's for VPD 0x83 or 0x80 */
+               if (scsicmd->cmnd[2] == 0x83) {
+                       /* vpd page 0x83 - Device Identification Page */
+                       int i;
+                       TVPD_Page83 VPDPage83Data;
+
+                       memset(((u8 *)&VPDPage83Data), 0,
+                              sizeof(VPDPage83Data));
+
+                       /* DIRECT_ACCESS_DEVIC */
+                       VPDPage83Data.DeviceType = 0;
+                       /* DEVICE_CONNECTED */
+                       VPDPage83Data.DeviceTypeQualifier = 0;
+                       /* VPD_DEVICE_IDENTIFIERS */
+                       VPDPage83Data.PageCode = 0x83;
+                       VPDPage83Data.Reserved = 0;
+                       VPDPage83Data.PageLength =
+                               sizeof(VPDPage83Data.IdDescriptorType1) +
+                               sizeof(VPDPage83Data.IdDescriptorType2);
+
+                       /* T10 Vendor Identifier Field Format */
+                       /* VpdCodeSetAscii */
+                       VPDPage83Data.IdDescriptorType1.CodeSet = 2;
+                       /* VpdIdentifierTypeVendorId */
+                       VPDPage83Data.IdDescriptorType1.IdentifierType = 1;
+                       VPDPage83Data.IdDescriptorType1.IdentifierLength =
+                               sizeof(VPDPage83Data.IdDescriptorType1) - 4;
+
+                       /* "ADAPTEC " for adaptec */
+                       memcpy(VPDPage83Data.IdDescriptorType1.VendId,
+                               "ADAPTEC ",
+                               sizeof(VPDPage83Data.IdDescriptorType1.VendId));
+                       memcpy(VPDPage83Data.IdDescriptorType1.ProductId,
+                               "ARRAY           ",
+                               sizeof(
+                               VPDPage83Data.IdDescriptorType1.ProductId));
+
+                       /* Convert to ascii based serial number.
+                        * The LSB is the the end.
+                        */
+                       for (i = 0; i < 8; i++) {
+                               u8 temp =
+                                       (u8)((get_serial_reply->uid >> ((7 - i) * 4)) & 0xF);
+                               if (temp  > 0x9) {
+                                       VPDPage83Data.IdDescriptorType1.SerialNumber[i] =
+                                                       'A' + (temp - 0xA);
+                               } else {
+                                       VPDPage83Data.IdDescriptorType1.SerialNumber[i] =
+                                                       '0' + temp;
+                               }
+                       }
+
+                       /* VpdCodeSetBinary */
+                       VPDPage83Data.IdDescriptorType2.CodeSet = 1;
+                       /* VpdIdentifierTypeEUI64 */
+                       VPDPage83Data.IdDescriptorType2.IdentifierType = 2;
+                       VPDPage83Data.IdDescriptorType2.IdentifierLength =
+                               sizeof(VPDPage83Data.IdDescriptorType2) - 4;
+
+                       VPDPage83Data.IdDescriptorType2.EU64Id.VendId[0] = 0xD0;
+                       VPDPage83Data.IdDescriptorType2.EU64Id.VendId[1] = 0;
+                       VPDPage83Data.IdDescriptorType2.EU64Id.VendId[2] = 0;
+
+                       VPDPage83Data.IdDescriptorType2.EU64Id.Serial =
+                                                       get_serial_reply->uid;
+                       VPDPage83Data.IdDescriptorType2.EU64Id.Reserved = 0;
+
+                       /* Move the inquiry data to the response buffer. */
+                       scsi_sg_copy_from_buffer(scsicmd, &VPDPage83Data,
+                                                sizeof(VPDPage83Data));
+               } else {
+                       /* It must be for VPD 0x80 */
+                       char sp[13];
+                       /* EVPD bit set */
+                       sp[0] = INQD_PDT_DA;
+                       sp[1] = scsicmd->cmnd[2];
+                       sp[2] = 0;
+                       sp[3] = snprintf(sp+4, sizeof(sp)-4, "%08X",
+                               le32_to_cpu(get_serial_reply->uid));
+                       scsi_sg_copy_from_buffer(scsicmd, sp,
+                                                sizeof(sp));
+               }
        }
 
        scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
@@ -2309,9 +2425,10 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                          INQD_PDT_PROC : INQD_PDT_DA;
                        if (scsicmd->cmnd[2] == 0) {
                                /* supported vital product data pages */
-                               arr[3] = 2;
+                               arr[3] = 3;
                                arr[4] = 0x0;
                                arr[5] = 0x80;
+                               arr[6] = 0x83;
                                arr[1] = scsicmd->cmnd[2];
                                scsi_sg_copy_from_buffer(scsicmd, &inq_data,
                                                         sizeof(inq_data));
@@ -2327,7 +2444,16 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                                if (aac_wwn != 2)
                                        return aac_get_container_serial(
                                                scsicmd);
-                               /* SLES 10 SP1 special */
+                               scsicmd->result = DID_OK << 16 |
+                                 COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+                       } else if (scsicmd->cmnd[2] == 0x83) {
+                               /* vpd page 0x83 - Device Identification Page */
+                               char *sno = (char *)&inq_data;
+                               sno[3] = setinqserial(dev, &sno[4],
+                                                     scmd_id(scsicmd));
+                               if (aac_wwn != 2)
+                                       return aac_get_container_serial(
+                                               scsicmd);
                                scsicmd->result = DID_OK << 16 |
                                  COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
                        } else {
@@ -2482,6 +2608,18 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                                (fsa_dev_ptr[cid].block_size >> 8) &  0xff;
                        mpd.bd.block_length[2] =
                                fsa_dev_ptr[cid].block_size  & 0xff;
+
+                       mpd.mpc_buf[0] = scsicmd->cmnd[2];
+                       if (scsicmd->cmnd[2] == 0x1C) {
+                               /* page length */
+                               mpd.mpc_buf[1] = 0xa;
+                               /* Mode data length */
+                               mpd.hd.data_length = 23;
+                       } else {
+                               /* Mode data length */
+                               mpd.hd.data_length = 15;
+                       }
+
                        if (capacity > 0xffffff) {
                                mpd.bd.block_count[0] = 0xff;
                                mpd.bd.block_count[1] = 0xff;
@@ -2500,9 +2638,12 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                        mpd.mpc_buf[2] = ((aac_cache & 6) == 2)
                                ? 0 : 0x04; /* WCE */
                        mode_buf_length = sizeof(mpd);
-                       if (mode_buf_length > scsicmd->cmnd[4])
-                               mode_buf_length = scsicmd->cmnd[4];
                }
+
+               if (mode_buf_length > scsicmd->cmnd[4])
+                       mode_buf_length = scsicmd->cmnd[4];
+               else
+                       mode_buf_length = sizeof(mpd);
                scsi_sg_copy_from_buffer(scsicmd,
                                         (char *)&mpd,
                                         mode_buf_length);