diff options
Diffstat (limited to 'drivers/scsi/scsi.c')
-rw-r--r-- | drivers/scsi/scsi.c | 40 |
1 files changed, 12 insertions, 28 deletions
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index a60da5555577..513661f45e5f 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c | |||
@@ -1026,55 +1026,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 | 1026 | * 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. | 1027 | * needed. If we cannot retrieve the VPD page this routine returns %NULL. |
1028 | */ | 1028 | */ |
1029 | unsigned char *scsi_get_vpd_page(struct scsi_device *sdev, u8 page) | 1029 | int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf, |
1030 | int buf_len) | ||
1030 | { | 1031 | { |
1031 | int i, result; | 1032 | 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 | 1033 | ||
1039 | /* Ask for all the pages supported by this device */ | 1034 | /* Ask for all the pages supported by this device */ |
1040 | result = scsi_vpd_inquiry(sdev, buf, 0, init_vpd_len); | 1035 | result = scsi_vpd_inquiry(sdev, buf, 0, buf_len); |
1041 | if (result) | 1036 | if (result) |
1042 | goto fail; | 1037 | goto fail; |
1043 | 1038 | ||
1044 | /* If the user actually wanted this page, we can skip the rest */ | 1039 | /* If the user actually wanted this page, we can skip the rest */ |
1045 | if (page == 0) | 1040 | if (page == 0) |
1046 | return buf; | 1041 | return -EINVAL; |
1047 | 1042 | ||
1048 | for (i = 0; i < buf[3]; i++) | 1043 | for (i = 0; i < min((int)buf[3], buf_len - 4); i++) |
1049 | if (buf[i + 4] == page) | 1044 | if (buf[i + 4] == page) |
1050 | goto found; | 1045 | goto found; |
1046 | |||
1047 | if (i < buf[3] && i > buf_len) | ||
1048 | /* ran off the end of the buffer, give us benefit of doubt */ | ||
1049 | goto found; | ||
1051 | /* The device claims it doesn't support the requested page */ | 1050 | /* The device claims it doesn't support the requested page */ |
1052 | goto fail; | 1051 | goto fail; |
1053 | 1052 | ||
1054 | found: | 1053 | found: |
1055 | result = scsi_vpd_inquiry(sdev, buf, page, 255); | 1054 | result = scsi_vpd_inquiry(sdev, buf, page, buf_len); |
1056 | if (result) | 1055 | if (result) |
1057 | goto fail; | 1056 | goto fail; |
1058 | 1057 | ||
1059 | /* | 1058 | 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 | 1059 | ||
1075 | fail: | 1060 | fail: |
1076 | kfree(buf); | 1061 | return -EINVAL; |
1077 | return NULL; | ||
1078 | } | 1062 | } |
1079 | EXPORT_SYMBOL_GPL(scsi_get_vpd_page); | 1063 | EXPORT_SYMBOL_GPL(scsi_get_vpd_page); |
1080 | 1064 | ||