diff options
Diffstat (limited to 'drivers/scsi/scsi.c')
-rw-r--r-- | drivers/scsi/scsi.c | 42 |
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 | */ |
1029 | unsigned char *scsi_get_vpd_page(struct scsi_device *sdev, u8 page) | 1031 | int 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 | } |
1079 | EXPORT_SYMBOL_GPL(scsi_get_vpd_page); | 1065 | EXPORT_SYMBOL_GPL(scsi_get_vpd_page); |
1080 | 1066 | ||