|
@@ -1026,55 +1026,39 @@ static int scsi_vpd_inquiry(struct scsi_device *sdev, unsigned char *buffer,
|
|
|
* responsible for calling kfree() on this pointer when it is no longer
|
|
|
* needed. If we cannot retrieve the VPD page this routine returns %NULL.
|
|
|
*/
|
|
|
-unsigned char *scsi_get_vpd_page(struct scsi_device *sdev, u8 page)
|
|
|
+int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf,
|
|
|
+ int buf_len)
|
|
|
{
|
|
|
int i, result;
|
|
|
- unsigned int len;
|
|
|
- const unsigned int init_vpd_len = 255;
|
|
|
- unsigned char *buf = kmalloc(init_vpd_len, GFP_KERNEL);
|
|
|
-
|
|
|
- if (!buf)
|
|
|
- return NULL;
|
|
|
|
|
|
/* Ask for all the pages supported by this device */
|
|
|
- result = scsi_vpd_inquiry(sdev, buf, 0, init_vpd_len);
|
|
|
+ result = scsi_vpd_inquiry(sdev, buf, 0, buf_len);
|
|
|
if (result)
|
|
|
goto fail;
|
|
|
|
|
|
/* If the user actually wanted this page, we can skip the rest */
|
|
|
if (page == 0)
|
|
|
- return buf;
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
- for (i = 0; i < buf[3]; i++)
|
|
|
+ for (i = 0; i < min((int)buf[3], buf_len - 4); i++)
|
|
|
if (buf[i + 4] == page)
|
|
|
goto found;
|
|
|
+
|
|
|
+ if (i < buf[3] && i > buf_len)
|
|
|
+ /* ran off the end of the buffer, give us benefit of doubt */
|
|
|
+ goto found;
|
|
|
/* The device claims it doesn't support the requested page */
|
|
|
goto fail;
|
|
|
|
|
|
found:
|
|
|
- result = scsi_vpd_inquiry(sdev, buf, page, 255);
|
|
|
+ result = scsi_vpd_inquiry(sdev, buf, page, buf_len);
|
|
|
if (result)
|
|
|
goto fail;
|
|
|
|
|
|
- /*
|
|
|
- * Some pages are longer than 255 bytes. The actual length of
|
|
|
- * the page is returned in the header.
|
|
|
- */
|
|
|
- len = ((buf[2] << 8) | buf[3]) + 4;
|
|
|
- if (len <= init_vpd_len)
|
|
|
- return buf;
|
|
|
-
|
|
|
- kfree(buf);
|
|
|
- buf = kmalloc(len, GFP_KERNEL);
|
|
|
- result = scsi_vpd_inquiry(sdev, buf, page, len);
|
|
|
- if (result)
|
|
|
- goto fail;
|
|
|
-
|
|
|
- return buf;
|
|
|
+ return 0;
|
|
|
|
|
|
fail:
|
|
|
- kfree(buf);
|
|
|
- return NULL;
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(scsi_get_vpd_page);
|
|
|
|