diff options
Diffstat (limited to 'drivers/scsi/scsi.c')
-rw-r--r-- | drivers/scsi/scsi.c | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index b2526ad7b9a1..1d98ac960887 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c | |||
@@ -1030,6 +1030,93 @@ int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf, | |||
1030 | EXPORT_SYMBOL_GPL(scsi_get_vpd_page); | 1030 | EXPORT_SYMBOL_GPL(scsi_get_vpd_page); |
1031 | 1031 | ||
1032 | /** | 1032 | /** |
1033 | * scsi_attach_vpd - Attach Vital Product Data to a SCSI device structure | ||
1034 | * @sdev: The device to ask | ||
1035 | * | ||
1036 | * Attach the 'Device Identification' VPD page (0x83) and the | ||
1037 | * 'Unit Serial Number' VPD page (0x80) to a SCSI device | ||
1038 | * structure. This information can be used to identify the device | ||
1039 | * uniquely. | ||
1040 | */ | ||
1041 | void scsi_attach_vpd(struct scsi_device *sdev) | ||
1042 | { | ||
1043 | int result, i; | ||
1044 | int vpd_len = SCSI_VPD_PG_LEN; | ||
1045 | int pg80_supported = 0; | ||
1046 | int pg83_supported = 0; | ||
1047 | unsigned char *vpd_buf; | ||
1048 | |||
1049 | if (sdev->skip_vpd_pages) | ||
1050 | return; | ||
1051 | retry_pg0: | ||
1052 | vpd_buf = kmalloc(vpd_len, GFP_KERNEL); | ||
1053 | if (!vpd_buf) | ||
1054 | return; | ||
1055 | |||
1056 | /* Ask for all the pages supported by this device */ | ||
1057 | result = scsi_vpd_inquiry(sdev, vpd_buf, 0, vpd_len); | ||
1058 | if (result < 0) { | ||
1059 | kfree(vpd_buf); | ||
1060 | return; | ||
1061 | } | ||
1062 | if (result > vpd_len) { | ||
1063 | vpd_len = result; | ||
1064 | kfree(vpd_buf); | ||
1065 | goto retry_pg0; | ||
1066 | } | ||
1067 | |||
1068 | for (i = 4; i < result; i++) { | ||
1069 | if (vpd_buf[i] == 0x80) | ||
1070 | pg80_supported = 1; | ||
1071 | if (vpd_buf[i] == 0x83) | ||
1072 | pg83_supported = 1; | ||
1073 | } | ||
1074 | kfree(vpd_buf); | ||
1075 | vpd_len = SCSI_VPD_PG_LEN; | ||
1076 | |||
1077 | if (pg80_supported) { | ||
1078 | retry_pg80: | ||
1079 | vpd_buf = kmalloc(vpd_len, GFP_KERNEL); | ||
1080 | if (!vpd_buf) | ||
1081 | return; | ||
1082 | |||
1083 | result = scsi_vpd_inquiry(sdev, vpd_buf, 0x80, vpd_len); | ||
1084 | if (result < 0) { | ||
1085 | kfree(vpd_buf); | ||
1086 | return; | ||
1087 | } | ||
1088 | if (result > vpd_len) { | ||
1089 | vpd_len = result; | ||
1090 | kfree(vpd_buf); | ||
1091 | goto retry_pg80; | ||
1092 | } | ||
1093 | sdev->vpd_pg80_len = result; | ||
1094 | sdev->vpd_pg80 = vpd_buf; | ||
1095 | vpd_len = SCSI_VPD_PG_LEN; | ||
1096 | } | ||
1097 | |||
1098 | if (pg83_supported) { | ||
1099 | retry_pg83: | ||
1100 | vpd_buf = kmalloc(vpd_len, GFP_KERNEL); | ||
1101 | if (!vpd_buf) | ||
1102 | return; | ||
1103 | |||
1104 | result = scsi_vpd_inquiry(sdev, vpd_buf, 0x83, vpd_len); | ||
1105 | if (result < 0) { | ||
1106 | kfree(vpd_buf); | ||
1107 | return; | ||
1108 | } | ||
1109 | if (result > vpd_len) { | ||
1110 | vpd_len = result; | ||
1111 | kfree(vpd_buf); | ||
1112 | goto retry_pg83; | ||
1113 | } | ||
1114 | sdev->vpd_pg83_len = result; | ||
1115 | sdev->vpd_pg83 = vpd_buf; | ||
1116 | } | ||
1117 | } | ||
1118 | |||
1119 | /** | ||
1033 | * scsi_report_opcode - Find out if a given command opcode is supported | 1120 | * scsi_report_opcode - Find out if a given command opcode is supported |
1034 | * @sdev: scsi device to query | 1121 | * @sdev: scsi device to query |
1035 | * @buffer: scratch buffer (must be at least 20 bytes long) | 1122 | * @buffer: scratch buffer (must be at least 20 bytes long) |