aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/scsi.c87
-rw-r--r--drivers/scsi/scsi_scan.c3
-rw-r--r--drivers/scsi/scsi_sysfs.c34
-rw-r--r--include/scsi/scsi_device.h7
4 files changed, 130 insertions, 1 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,
1030EXPORT_SYMBOL_GPL(scsi_get_vpd_page); 1030EXPORT_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 */
1041void 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;
1051retry_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) {
1078retry_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) {
1099retry_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)
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 4109530e92a0..27f96d5b7680 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -970,6 +970,9 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
970 } 970 }
971 } 971 }
972 972
973 if (sdev->scsi_level >= SCSI_3)
974 scsi_attach_vpd(sdev);
975
973 sdev->max_queue_depth = sdev->queue_depth; 976 sdev->max_queue_depth = sdev->queue_depth;
974 977
975 /* 978 /*
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 85098222a9e8..1392474c3499 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -412,6 +412,8 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work)
412 /* NULL queue means the device can't be used */ 412 /* NULL queue means the device can't be used */
413 sdev->request_queue = NULL; 413 sdev->request_queue = NULL;
414 414
415 kfree(sdev->vpd_pg83);
416 kfree(sdev->vpd_pg80);
415 kfree(sdev->inquiry); 417 kfree(sdev->inquiry);
416 kfree(sdev); 418 kfree(sdev);
417 419
@@ -751,8 +753,32 @@ store_queue_type_field(struct device *dev, struct device_attribute *attr,
751static DEVICE_ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field, 753static DEVICE_ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field,
752 store_queue_type_field); 754 store_queue_type_field);
753 755
756#define sdev_vpd_pg_attr(_page) \
757static ssize_t \
758show_vpd_##_page(struct file *filp, struct kobject *kobj, \
759 struct bin_attribute *bin_attr, \
760 char *buf, loff_t off, size_t count) \
761{ \
762 struct device *dev = container_of(kobj, struct device, kobj); \
763 struct scsi_device *sdev = to_scsi_device(dev); \
764 if (!sdev->vpd_##_page) \
765 return -EINVAL; \
766 return memory_read_from_buffer(buf, count, &off, \
767 sdev->vpd_##_page, \
768 sdev->vpd_##_page##_len); \
769} \
770static struct bin_attribute dev_attr_vpd_##_page = { \
771 .attr = {.name = __stringify(vpd_##_page), .mode = S_IRUGO }, \
772 .size = 0, \
773 .read = show_vpd_##_page, \
774};
775
776sdev_vpd_pg_attr(pg83);
777sdev_vpd_pg_attr(pg80);
778
754static ssize_t 779static ssize_t
755show_iostat_counterbits(struct device *dev, struct device_attribute *attr, char *buf) 780show_iostat_counterbits(struct device *dev, struct device_attribute *attr,
781 char *buf)
756{ 782{
757 return snprintf(buf, 20, "%d\n", (int)sizeof(atomic_t) * 8); 783 return snprintf(buf, 20, "%d\n", (int)sizeof(atomic_t) * 8);
758} 784}
@@ -936,8 +962,14 @@ static struct attribute *scsi_sdev_attrs[] = {
936 NULL 962 NULL
937}; 963};
938 964
965static struct bin_attribute *scsi_sdev_bin_attrs[] = {
966 &dev_attr_vpd_pg83,
967 &dev_attr_vpd_pg80,
968 NULL
969};
939static struct attribute_group scsi_sdev_attr_group = { 970static struct attribute_group scsi_sdev_attr_group = {
940 .attrs = scsi_sdev_attrs, 971 .attrs = scsi_sdev_attrs,
972 .bin_attrs = scsi_sdev_bin_attrs,
941 .is_visible = scsi_sdev_attr_is_visible, 973 .is_visible = scsi_sdev_attr_is_visible,
942}; 974};
943 975
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index ccabdc1c27ca..4e845b80efd3 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -113,6 +113,12 @@ struct scsi_device {
113 const char * vendor; /* [back_compat] point into 'inquiry' ... */ 113 const char * vendor; /* [back_compat] point into 'inquiry' ... */
114 const char * model; /* ... after scan; point to static string */ 114 const char * model; /* ... after scan; point to static string */
115 const char * rev; /* ... "nullnullnullnull" before scan */ 115 const char * rev; /* ... "nullnullnullnull" before scan */
116
117#define SCSI_VPD_PG_LEN 255
118 int vpd_pg83_len;
119 unsigned char *vpd_pg83;
120 int vpd_pg80_len;
121 unsigned char *vpd_pg80;
116 unsigned char current_tag; /* current tag */ 122 unsigned char current_tag; /* current tag */
117 struct scsi_target *sdev_target; /* used only for single_lun */ 123 struct scsi_target *sdev_target; /* used only for single_lun */
118 124
@@ -320,6 +326,7 @@ extern int scsi_add_device(struct Scsi_Host *host, uint channel,
320extern int scsi_register_device_handler(struct scsi_device_handler *scsi_dh); 326extern int scsi_register_device_handler(struct scsi_device_handler *scsi_dh);
321extern void scsi_remove_device(struct scsi_device *); 327extern void scsi_remove_device(struct scsi_device *);
322extern int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh); 328extern int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh);
329void scsi_attach_vpd(struct scsi_device *sdev);
323 330
324extern int scsi_device_get(struct scsi_device *); 331extern int scsi_device_get(struct scsi_device *);
325extern void scsi_device_put(struct scsi_device *); 332extern void scsi_device_put(struct scsi_device *);