aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/aacraid/aachba.c
diff options
context:
space:
mode:
authorSalyzyn, Mark <mark_salyzyn@adaptec.com>2007-07-17 14:01:28 -0400
committerJames Bottomley <jejb@mulgrave.localdomain>2007-07-18 12:17:48 -0400
commit88e2f98e1b3eb27ae708daa3b37dd50f3f06c952 (patch)
tree766559a83169ef322c1dd3ea293ef42e8cc7833b /drivers/scsi/aacraid/aachba.c
parent9ad5204d68a3b48b92907d88d1c28d33fde6ba2a (diff)
[SCSI] aacraid: add vpd to inquiry
Report VPD inquiry page 0x80 with an unique array creation serial number (CUID). When an array is created, the metadata stored on the physical drives gets an unique serial number. This serial number remains constant through array morphing or migration to other controllers. This patch is a forward port and modification to survive morphing and migration operations, of a similar piece of (un-attributed author) code added to the SLES10 SP1 aacraid driver. To test the results of the patch, observe that /dev/disk/by-id/ entries will show up for the arrays resulting from the udev rules. Also, as per the udev rules, 'scsi_id -g -x -a -s /block/sd? -d /dev/sd?' will report the ID_SERIAL as constructed from the inquiry data. It was reported to me that the 'ADPT' leading the serial number was bad form, that the inquiry vendor field was enough to differentiate the storage uniquely. Subsequent search found that another Adaptec AAC based driver reported the 8 hex serial number only without such adornments, so dropped ADPT to match. Resubmitting the patch with this alteration. Signed-off-by: Mark Salyzyn <aacraid@adaptec.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/aacraid/aachba.c')
-rw-r--r--drivers/scsi/aacraid/aachba.c138
1 files changed, 138 insertions, 0 deletions
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index 80d42070edf0..a26baab09dbf 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -751,6 +751,101 @@ static void setinqstr(struct aac_dev *dev, void *data, int tindex)
751 inqstrcpy ("V1.0", str->prl); 751 inqstrcpy ("V1.0", str->prl);
752} 752}
753 753
754static void get_container_serial_callback(void *context, struct fib * fibptr)
755{
756 struct aac_get_serial_resp * get_serial_reply;
757 struct scsi_cmnd * scsicmd;
758
759 BUG_ON(fibptr == NULL);
760
761 scsicmd = (struct scsi_cmnd *) context;
762 if (!aac_valid_context(scsicmd, fibptr))
763 return;
764
765 get_serial_reply = (struct aac_get_serial_resp *) fib_data(fibptr);
766 /* Failure is irrelevant, using default value instead */
767 if (le32_to_cpu(get_serial_reply->status) == CT_OK) {
768 char sp[13];
769 /* EVPD bit set */
770 sp[0] = INQD_PDT_DA;
771 sp[1] = scsicmd->cmnd[2];
772 sp[2] = 0;
773 sp[3] = snprintf(sp+4, sizeof(sp)-4, "%08X",
774 le32_to_cpu(get_serial_reply->uid));
775 aac_internal_transfer(scsicmd, sp, 0, sizeof(sp));
776 }
777
778 scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
779
780 aac_fib_complete(fibptr);
781 aac_fib_free(fibptr);
782 scsicmd->scsi_done(scsicmd);
783}
784
785/**
786 * aac_get_container_serial - get container serial, none blocking.
787 */
788static int aac_get_container_serial(struct scsi_cmnd * scsicmd)
789{
790 int status;
791 struct aac_get_serial *dinfo;
792 struct fib * cmd_fibcontext;
793 struct aac_dev * dev;
794
795 dev = (struct aac_dev *)scsicmd->device->host->hostdata;
796
797 if (!(cmd_fibcontext = aac_fib_alloc(dev)))
798 return -ENOMEM;
799
800 aac_fib_init(cmd_fibcontext);
801 dinfo = (struct aac_get_serial *) fib_data(cmd_fibcontext);
802
803 dinfo->command = cpu_to_le32(VM_ContainerConfig);
804 dinfo->type = cpu_to_le32(CT_CID_TO_32BITS_UID);
805 dinfo->cid = cpu_to_le32(scmd_id(scsicmd));
806
807 status = aac_fib_send(ContainerCommand,
808 cmd_fibcontext,
809 sizeof (struct aac_get_serial),
810 FsaNormal,
811 0, 1,
812 (fib_callback) get_container_serial_callback,
813 (void *) scsicmd);
814
815 /*
816 * Check that the command queued to the controller
817 */
818 if (status == -EINPROGRESS) {
819 scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
820 return 0;
821 }
822
823 printk(KERN_WARNING "aac_get_container_serial: aac_fib_send failed with status: %d.\n", status);
824 aac_fib_complete(cmd_fibcontext);
825 aac_fib_free(cmd_fibcontext);
826 return -1;
827}
828
829/* Function: setinqserial
830 *
831 * Arguments: [1] pointer to void [1] int
832 *
833 * Purpose: Sets SCSI Unit Serial number.
834 * This is a fake. We should read a proper
835 * serial number from the container. <SuSE>But
836 * without docs it's quite hard to do it :-)
837 * So this will have to do in the meantime.</SuSE>
838 */
839
840static int setinqserial(struct aac_dev *dev, void *data, int cid)
841{
842 /*
843 * This breaks array migration.
844 */
845 return snprintf((char *)(data), sizeof(struct scsi_inq) - 4, "%08X%02X",
846 le32_to_cpu(dev->adapter_info.serial[0]), cid);
847}
848
754static void set_sense(u8 *sense_buf, u8 sense_key, u8 sense_code, 849static void set_sense(u8 *sense_buf, u8 sense_key, u8 sense_code,
755 u8 a_sense_code, u8 incorrect_length, 850 u8 a_sense_code, u8 incorrect_length,
756 u8 bit_pointer, u16 field_pointer, 851 u8 bit_pointer, u16 field_pointer,
@@ -1798,6 +1893,49 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
1798 dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", cid)); 1893 dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", cid));
1799 memset(&inq_data, 0, sizeof (struct inquiry_data)); 1894 memset(&inq_data, 0, sizeof (struct inquiry_data));
1800 1895
1896 if (scsicmd->cmnd[1] & 0x1 ) {
1897 char *arr = (char *)&inq_data;
1898
1899 /* EVPD bit set */
1900 arr[0] = (scmd_id(scsicmd) == host->this_id) ?
1901 INQD_PDT_PROC : INQD_PDT_DA;
1902 if (scsicmd->cmnd[2] == 0) {
1903 /* supported vital product data pages */
1904 arr[3] = 2;
1905 arr[4] = 0x0;
1906 arr[5] = 0x80;
1907 arr[1] = scsicmd->cmnd[2];
1908 aac_internal_transfer(scsicmd, &inq_data, 0,
1909 sizeof(inq_data));
1910 scsicmd->result = DID_OK << 16 |
1911 COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
1912 } else if (scsicmd->cmnd[2] == 0x80) {
1913 /* unit serial number page */
1914 arr[3] = setinqserial(dev, &arr[4],
1915 scmd_id(scsicmd));
1916 arr[1] = scsicmd->cmnd[2];
1917 aac_internal_transfer(scsicmd, &inq_data, 0,
1918 sizeof(inq_data));
1919 return aac_get_container_serial(scsicmd);
1920 } else {
1921 /* vpd page not implemented */
1922 scsicmd->result = DID_OK << 16 |
1923 COMMAND_COMPLETE << 8 |
1924 SAM_STAT_CHECK_CONDITION;
1925 set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
1926 ILLEGAL_REQUEST,
1927 SENCODE_INVALID_CDB_FIELD,
1928 ASENCODE_NO_SENSE, 0, 7, 2, 0);
1929 memcpy(scsicmd->sense_buffer,
1930 &dev->fsa_dev[cid].sense_data,
1931 (sizeof(dev->fsa_dev[cid].sense_data) >
1932 sizeof(scsicmd->sense_buffer))
1933 ? sizeof(scsicmd->sense_buffer)
1934 : sizeof(dev->fsa_dev[cid].sense_data));
1935 }
1936 scsicmd->scsi_done(scsicmd);
1937 return 0;
1938 }
1801 inq_data.inqd_ver = 2; /* claim compliance to SCSI-2 */ 1939 inq_data.inqd_ver = 2; /* claim compliance to SCSI-2 */
1802 inq_data.inqd_rdf = 2; /* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */ 1940 inq_data.inqd_rdf = 2; /* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */
1803 inq_data.inqd_len = 31; 1941 inq_data.inqd_len = 31;