Commit 1e3f720a authored by Bart Van Assche's avatar Bart Van Assche Committed by Martin K. Petersen

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: default avatarBart Van Assche <bart.vanassche@wdc.com>
Acked-by: default avatarHannes Reinecke <hare@suse.de>
Reviewed-by: default avatarShane 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: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 26e3e3cb
...@@ -412,105 +412,93 @@ int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf, ...@@ -412,105 +412,93 @@ int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf,
EXPORT_SYMBOL_GPL(scsi_get_vpd_page); EXPORT_SYMBOL_GPL(scsi_get_vpd_page);
/** /**
* scsi_attach_vpd - Attach Vital Product Data to a SCSI device structure * scsi_get_vpd_buf - Get Vital Product Data from a SCSI device
* @sdev: The device to ask * @sdev: The device to ask
* @page: Which Vital Product Data to return
* @len: Upon success, the VPD length will be stored in *@len.
* *
* Attach the 'Device Identification' VPD page (0x83) and the * Returns %NULL upon failure.
* 'Unit Serial Number' VPD page (0x80) to a SCSI device
* structure. This information can be used to identify the device
* uniquely.
*/ */
void scsi_attach_vpd(struct scsi_device *sdev) static unsigned char *scsi_get_vpd_buf(struct scsi_device *sdev, u8 page,
int *len)
{ {
int result, i; unsigned char *vpd_buf;
int vpd_len = SCSI_VPD_PG_LEN; int vpd_len = SCSI_VPD_PG_LEN, result;
int pg80_supported = 0;
int pg83_supported = 0;
unsigned char __rcu *vpd_buf, *orig_vpd_buf = NULL;
if (!scsi_device_supports_vpd(sdev)) retry_pg:
return;
retry_pg0:
vpd_buf = kmalloc(vpd_len, GFP_KERNEL); vpd_buf = kmalloc(vpd_len, GFP_KERNEL);
if (!vpd_buf) if (!vpd_buf)
return; return NULL;
/* Ask for all the pages supported by this device */ result = scsi_vpd_inquiry(sdev, vpd_buf, page, vpd_len);
result = scsi_vpd_inquiry(sdev, vpd_buf, 0, vpd_len);
if (result < 0) { if (result < 0) {
kfree(vpd_buf); kfree(vpd_buf);
return; return NULL;
} }
if (result > vpd_len) { if (result > vpd_len) {
vpd_len = result; vpd_len = result;
kfree(vpd_buf); kfree(vpd_buf);
goto retry_pg0; goto retry_pg;
} }
for (i = 4; i < result; i++) { *len = result;
if (vpd_buf[i] == 0x80)
pg80_supported = 1;
if (vpd_buf[i] == 0x83)
pg83_supported = 1;
}
kfree(vpd_buf);
vpd_len = SCSI_VPD_PG_LEN;
if (pg80_supported) { return vpd_buf;
retry_pg80: }
vpd_buf = kmalloc(vpd_len, GFP_KERNEL);
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) if (!vpd_buf)
return; 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); mutex_lock(&sdev->inquiry_mutex);
orig_vpd_buf = sdev->vpd_pg80; rcu_swap_protected(*sdev_vpd_buf, vpd_buf,
sdev->vpd_pg80_len = result; lockdep_is_held(&sdev->inquiry_mutex));
rcu_assign_pointer(sdev->vpd_pg80, vpd_buf); *sdev_vpd_len = len;
mutex_unlock(&sdev->inquiry_mutex); mutex_unlock(&sdev->inquiry_mutex);
synchronize_rcu(); synchronize_rcu();
if (orig_vpd_buf) {
kfree(orig_vpd_buf);
orig_vpd_buf = NULL;
}
vpd_len = SCSI_VPD_PG_LEN;
}
if (pg83_supported) { kfree(vpd_buf);
retry_pg83: }
vpd_buf = kmalloc(vpd_len, GFP_KERNEL);
if (!vpd_buf) /**
* scsi_attach_vpd - Attach Vital Product Data to a SCSI device structure
* @sdev: The device to ask
*
* Attach the 'Device Identification' VPD page (0x83) and the
* 'Unit Serial Number' VPD page (0x80) to a SCSI device
* structure. This information can be used to identify the device
* uniquely.
*/
void scsi_attach_vpd(struct scsi_device *sdev)
{
int i, vpd_len;
unsigned char *vpd_buf;
if (!scsi_device_supports_vpd(sdev))
return; return;
result = scsi_vpd_inquiry(sdev, vpd_buf, 0x83, vpd_len); /* Ask for all the pages supported by this device */
if (result < 0) { vpd_buf = scsi_get_vpd_buf(sdev, 0, &vpd_len);
kfree(vpd_buf); if (!vpd_buf)
return; return;
for (i = 4; i < vpd_len; i++) {
if (vpd_buf[i] == 0x80)
scsi_update_vpd_page(sdev, 0x80, &sdev->vpd_pg80,
&sdev->vpd_pg80_len);
if (vpd_buf[i] == 0x83)
scsi_update_vpd_page(sdev, 0x83, &sdev->vpd_pg83,
&sdev->vpd_pg83_len);
} }
if (result > vpd_len) {
vpd_len = result;
kfree(vpd_buf); 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);
}
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment