scsi: Rework the code for caching Vital Product Data (VPD)

Introduce the scsi_get_vpd_buf() and scsi_update_vpd_page()
functions. The only functional change in this patch is that if updating
page 0x80 fails that it is attempted to update page 0x83.

Signed-off-by: Bart Van Assche <bart.vanassche@wdc.com>
Acked-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Shane Seymour <shane.seymour@hpe.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Johannes Thumshirn <jthumshirn@suse.de>
Cc: Shane M Seymour <shane.seymour@hpe.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Bart Van Assche 2017-08-29 08:50:12 -07:00 committed by Martin K. Petersen
parent 26e3e3cb05
commit 1e3f720a67

View File

@ -411,6 +411,63 @@ int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf,
}
EXPORT_SYMBOL_GPL(scsi_get_vpd_page);
/**
* scsi_get_vpd_buf - Get Vital Product Data from a SCSI device
* @sdev: The device to ask
* @page: Which Vital Product Data to return
* @len: Upon success, the VPD length will be stored in *@len.
*
* Returns %NULL upon failure.
*/
static unsigned char *scsi_get_vpd_buf(struct scsi_device *sdev, u8 page,
int *len)
{
unsigned char *vpd_buf;
int vpd_len = SCSI_VPD_PG_LEN, result;
retry_pg:
vpd_buf = kmalloc(vpd_len, GFP_KERNEL);
if (!vpd_buf)
return NULL;
result = scsi_vpd_inquiry(sdev, vpd_buf, page, vpd_len);
if (result < 0) {
kfree(vpd_buf);
return NULL;
}
if (result > vpd_len) {
vpd_len = result;
kfree(vpd_buf);
goto retry_pg;
}
*len = result;
return vpd_buf;
}
static void scsi_update_vpd_page(struct scsi_device *sdev, u8 page,
unsigned char __rcu **sdev_vpd_buf,
int *sdev_vpd_len)
{
unsigned char *vpd_buf;
int len;
vpd_buf = scsi_get_vpd_buf(sdev, page, &len);
if (!vpd_buf)
return;
mutex_lock(&sdev->inquiry_mutex);
rcu_swap_protected(*sdev_vpd_buf, vpd_buf,
lockdep_is_held(&sdev->inquiry_mutex));
*sdev_vpd_len = len;
mutex_unlock(&sdev->inquiry_mutex);
synchronize_rcu();
kfree(vpd_buf);
}
/**
* scsi_attach_vpd - Attach Vital Product Data to a SCSI device structure
* @sdev: The device to ask
@ -422,95 +479,26 @@ EXPORT_SYMBOL_GPL(scsi_get_vpd_page);
*/
void scsi_attach_vpd(struct scsi_device *sdev)
{
int result, i;
int vpd_len = SCSI_VPD_PG_LEN;
int pg80_supported = 0;
int pg83_supported = 0;
unsigned char __rcu *vpd_buf, *orig_vpd_buf = NULL;
int i, vpd_len;
unsigned char *vpd_buf;
if (!scsi_device_supports_vpd(sdev))
return;
retry_pg0:
vpd_buf = kmalloc(vpd_len, GFP_KERNEL);
/* Ask for all the pages supported by this device */
vpd_buf = scsi_get_vpd_buf(sdev, 0, &vpd_len);
if (!vpd_buf)
return;
/* Ask for all the pages supported by this device */
result = scsi_vpd_inquiry(sdev, vpd_buf, 0, vpd_len);
if (result < 0) {
kfree(vpd_buf);
return;
}
if (result > vpd_len) {
vpd_len = result;
kfree(vpd_buf);
goto retry_pg0;
}
for (i = 4; i < result; i++) {
for (i = 4; i < vpd_len; i++) {
if (vpd_buf[i] == 0x80)
pg80_supported = 1;
scsi_update_vpd_page(sdev, 0x80, &sdev->vpd_pg80,
&sdev->vpd_pg80_len);
if (vpd_buf[i] == 0x83)
pg83_supported = 1;
scsi_update_vpd_page(sdev, 0x83, &sdev->vpd_pg83,
&sdev->vpd_pg83_len);
}
kfree(vpd_buf);
vpd_len = SCSI_VPD_PG_LEN;
if (pg80_supported) {
retry_pg80:
vpd_buf = kmalloc(vpd_len, GFP_KERNEL);
if (!vpd_buf)
return;
result = scsi_vpd_inquiry(sdev, vpd_buf, 0x80, vpd_len);
if (result < 0) {
kfree(vpd_buf);
return;
}
if (result > vpd_len) {
vpd_len = result;
kfree(vpd_buf);
goto retry_pg80;
}
mutex_lock(&sdev->inquiry_mutex);
orig_vpd_buf = sdev->vpd_pg80;
sdev->vpd_pg80_len = result;
rcu_assign_pointer(sdev->vpd_pg80, vpd_buf);
mutex_unlock(&sdev->inquiry_mutex);
synchronize_rcu();
if (orig_vpd_buf) {
kfree(orig_vpd_buf);
orig_vpd_buf = NULL;
}
vpd_len = SCSI_VPD_PG_LEN;
}
if (pg83_supported) {
retry_pg83:
vpd_buf = kmalloc(vpd_len, GFP_KERNEL);
if (!vpd_buf)
return;
result = scsi_vpd_inquiry(sdev, vpd_buf, 0x83, vpd_len);
if (result < 0) {
kfree(vpd_buf);
return;
}
if (result > vpd_len) {
vpd_len = result;
kfree(vpd_buf);
goto retry_pg83;
}
mutex_lock(&sdev->inquiry_mutex);
orig_vpd_buf = sdev->vpd_pg83;
sdev->vpd_pg83_len = result;
rcu_assign_pointer(sdev->vpd_pg83, vpd_buf);
mutex_unlock(&sdev->inquiry_mutex);
synchronize_rcu();
if (orig_vpd_buf)
kfree(orig_vpd_buf);
}
}
/**