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 | ||
