diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/scsi/aacraid/aachba.c | 138 | ||||
-rw-r--r-- | drivers/scsi/aacraid/aacraid.h | 14 |
2 files changed, 152 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 | ||
754 | static 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 | */ | ||
788 | static 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 | |||
840 | static 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 | |||
754 | static void set_sense(u8 *sense_buf, u8 sense_key, u8 sense_code, | 849 | static 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; |
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index f1d3b66af879..400d03403cd5 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h | |||
@@ -1567,6 +1567,20 @@ struct aac_get_name_resp { | |||
1567 | u8 data[16]; | 1567 | u8 data[16]; |
1568 | }; | 1568 | }; |
1569 | 1569 | ||
1570 | #define CT_CID_TO_32BITS_UID 165 | ||
1571 | struct aac_get_serial { | ||
1572 | __le32 command; /* VM_ContainerConfig */ | ||
1573 | __le32 type; /* CT_CID_TO_32BITS_UID */ | ||
1574 | __le32 cid; | ||
1575 | }; | ||
1576 | |||
1577 | struct aac_get_serial_resp { | ||
1578 | __le32 dummy0; | ||
1579 | __le32 dummy1; | ||
1580 | __le32 status; /* CT_OK */ | ||
1581 | __le32 uid; | ||
1582 | }; | ||
1583 | |||
1570 | /* | 1584 | /* |
1571 | * The following command is sent to shut down each container. | 1585 | * The following command is sent to shut down each container. |
1572 | */ | 1586 | */ |