aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/scsi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/scsi.c')
-rw-r--r--drivers/scsi/scsi.c42
1 files changed, 14 insertions, 28 deletions
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index a60da5555577..1c08f6164658 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -1018,6 +1018,8 @@ static int scsi_vpd_inquiry(struct scsi_device *sdev, unsigned char *buffer,
1018 * scsi_get_vpd_page - Get Vital Product Data from a SCSI device 1018 * scsi_get_vpd_page - Get Vital Product Data from a SCSI device
1019 * @sdev: The device to ask 1019 * @sdev: The device to ask
1020 * @page: Which Vital Product Data to return 1020 * @page: Which Vital Product Data to return
1021 * @buf: where to store the VPD
1022 * @buf_len: number of bytes in the VPD buffer area
1021 * 1023 *
1022 * SCSI devices may optionally supply Vital Product Data. Each 'page' 1024 * SCSI devices may optionally supply Vital Product Data. Each 'page'
1023 * of VPD is defined in the appropriate SCSI document (eg SPC, SBC). 1025 * of VPD is defined in the appropriate SCSI document (eg SPC, SBC).
@@ -1026,55 +1028,39 @@ static int scsi_vpd_inquiry(struct scsi_device *sdev, unsigned char *buffer,
1026 * responsible for calling kfree() on this pointer when it is no longer 1028 * responsible for calling kfree() on this pointer when it is no longer
1027 * needed. If we cannot retrieve the VPD page this routine returns %NULL. 1029 * needed. If we cannot retrieve the VPD page this routine returns %NULL.
1028 */ 1030 */
1029unsigned char *scsi_get_vpd_page(struct scsi_device *sdev, u8 page) 1031int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf,
1032 int buf_len)
1030{ 1033{
1031 int i, result; 1034 int i, result;
1032 unsigned int len;
1033 const unsigned int init_vpd_len = 255;
1034 unsigned char *buf = kmalloc(init_vpd_len, GFP_KERNEL);
1035
1036 if (!buf)
1037 return NULL;
1038 1035
1039 /* Ask for all the pages supported by this device */ 1036 /* Ask for all the pages supported by this device */
1040 result = scsi_vpd_inquiry(sdev, buf, 0, init_vpd_len); 1037 result = scsi_vpd_inquiry(sdev, buf, 0, buf_len);
1041 if (result) 1038 if (result)
1042 goto fail; 1039 goto fail;
1043 1040
1044 /* If the user actually wanted this page, we can skip the rest */ 1041 /* If the user actually wanted this page, we can skip the rest */
1045 if (page == 0) 1042 if (page == 0)
1046 return buf; 1043 return -EINVAL;
1047 1044
1048 for (i = 0; i < buf[3]; i++) 1045 for (i = 0; i < min((int)buf[3], buf_len - 4); i++)
1049 if (buf[i + 4] == page) 1046 if (buf[i + 4] == page)
1050 goto found; 1047 goto found;
1048
1049 if (i < buf[3] && i > buf_len)
1050 /* ran off the end of the buffer, give us benefit of doubt */
1051 goto found;
1051 /* The device claims it doesn't support the requested page */ 1052 /* The device claims it doesn't support the requested page */
1052 goto fail; 1053 goto fail;
1053 1054
1054 found: 1055 found:
1055 result = scsi_vpd_inquiry(sdev, buf, page, 255); 1056 result = scsi_vpd_inquiry(sdev, buf, page, buf_len);
1056 if (result) 1057 if (result)
1057 goto fail; 1058 goto fail;
1058 1059
1059 /* 1060 return 0;
1060 * Some pages are longer than 255 bytes. The actual length of
1061 * the page is returned in the header.
1062 */
1063 len = ((buf[2] << 8) | buf[3]) + 4;
1064 if (len <= init_vpd_len)
1065 return buf;
1066
1067 kfree(buf);
1068 buf = kmalloc(len, GFP_KERNEL);
1069 result = scsi_vpd_inquiry(sdev, buf, page, len);
1070 if (result)
1071 goto fail;
1072
1073 return buf;
1074 1061
1075 fail: 1062 fail:
1076 kfree(buf); 1063 return -EINVAL;
1077 return NULL;
1078} 1064}
1079EXPORT_SYMBOL_GPL(scsi_get_vpd_page); 1065EXPORT_SYMBOL_GPL(scsi_get_vpd_page);
1080 1066