forked from Minki/linux
scsi: Add scsi_vpd_lun_id()
Add a function scsi_vpd_lun_id() to return a unique device identifcation based on the designation descriptors of VPD page 0x83. As devices might implement several descriptors the order of preference is: - NAA IEE Registered Extended - EUI-64 based 16-byte - EUI-64 based 12-byte - NAA IEEE Registered - NAA IEEE Extended A SCSI name string descriptor is preferred to all of them if the identification is longer than 16 bytes. The returned unique device identification will be formatted as a SCSI Name string to avoid clashes between different designator types. [mkp: Fixed up kernel doc comment from Johannes] Signed-off-by: Hannes Reinecke <hare@suse.de> Reviewed-by: Ewan Milne <emilne@redhat.com> Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
parent
e2d817db32
commit
9983bed390
@ -3154,3 +3154,143 @@ void sdev_enable_disk_events(struct scsi_device *sdev)
|
||||
atomic_dec(&sdev->disk_events_disable_depth);
|
||||
}
|
||||
EXPORT_SYMBOL(sdev_enable_disk_events);
|
||||
|
||||
/**
|
||||
* scsi_vpd_lun_id - return a unique device identification
|
||||
* @sdev: SCSI device
|
||||
* @id: buffer for the identification
|
||||
* @id_len: length of the buffer
|
||||
*
|
||||
* Copies a unique device identification into @id based
|
||||
* on the information in the VPD page 0x83 of the device.
|
||||
* The string will be formatted as a SCSI name string.
|
||||
*
|
||||
* Returns the length of the identification or error on failure.
|
||||
* If the identifier is longer than the supplied buffer the actual
|
||||
* identifier length is returned and the buffer is not zero-padded.
|
||||
*/
|
||||
int scsi_vpd_lun_id(struct scsi_device *sdev, char *id, size_t id_len)
|
||||
{
|
||||
u8 cur_id_type = 0xff;
|
||||
u8 cur_id_size = 0;
|
||||
unsigned char *d, *cur_id_str;
|
||||
unsigned char __rcu *vpd_pg83;
|
||||
int id_size = -EINVAL;
|
||||
|
||||
rcu_read_lock();
|
||||
vpd_pg83 = rcu_dereference(sdev->vpd_pg83);
|
||||
if (!vpd_pg83) {
|
||||
rcu_read_unlock();
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look for the correct descriptor.
|
||||
* Order of preference for lun descriptor:
|
||||
* - SCSI name string
|
||||
* - NAA IEEE Registered Extended
|
||||
* - EUI-64 based 16-byte
|
||||
* - EUI-64 based 12-byte
|
||||
* - NAA IEEE Registered
|
||||
* - NAA IEEE Extended
|
||||
* as longer descriptors reduce the likelyhood
|
||||
* of identification clashes.
|
||||
*/
|
||||
|
||||
/* The id string must be at least 20 bytes + terminating NULL byte */
|
||||
if (id_len < 21) {
|
||||
rcu_read_unlock();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(id, 0, id_len);
|
||||
d = vpd_pg83 + 4;
|
||||
while (d < vpd_pg83 + sdev->vpd_pg83_len) {
|
||||
/* Skip designators not referring to the LUN */
|
||||
if ((d[1] & 0x30) != 0x00)
|
||||
goto next_desig;
|
||||
|
||||
switch (d[1] & 0xf) {
|
||||
case 0x2:
|
||||
/* EUI-64 */
|
||||
if (cur_id_size > d[3])
|
||||
break;
|
||||
/* Prefer NAA IEEE Registered Extended */
|
||||
if (cur_id_type == 0x3 &&
|
||||
cur_id_size == d[3])
|
||||
break;
|
||||
cur_id_size = d[3];
|
||||
cur_id_str = d + 4;
|
||||
cur_id_type = d[1] & 0xf;
|
||||
switch (cur_id_size) {
|
||||
case 8:
|
||||
id_size = snprintf(id, id_len,
|
||||
"eui.%8phN",
|
||||
cur_id_str);
|
||||
break;
|
||||
case 12:
|
||||
id_size = snprintf(id, id_len,
|
||||
"eui.%12phN",
|
||||
cur_id_str);
|
||||
break;
|
||||
case 16:
|
||||
id_size = snprintf(id, id_len,
|
||||
"eui.%16phN",
|
||||
cur_id_str);
|
||||
break;
|
||||
default:
|
||||
cur_id_size = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x3:
|
||||
/* NAA */
|
||||
if (cur_id_size > d[3])
|
||||
break;
|
||||
cur_id_size = d[3];
|
||||
cur_id_str = d + 4;
|
||||
cur_id_type = d[1] & 0xf;
|
||||
switch (cur_id_size) {
|
||||
case 8:
|
||||
id_size = snprintf(id, id_len,
|
||||
"naa.%8phN",
|
||||
cur_id_str);
|
||||
break;
|
||||
case 16:
|
||||
id_size = snprintf(id, id_len,
|
||||
"naa.%16phN",
|
||||
cur_id_str);
|
||||
break;
|
||||
default:
|
||||
cur_id_size = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x8:
|
||||
/* SCSI name string */
|
||||
if (cur_id_size + 4 > d[3])
|
||||
break;
|
||||
/* Prefer others for truncated descriptor */
|
||||
if (cur_id_size && d[3] > id_len)
|
||||
break;
|
||||
cur_id_size = id_size = d[3];
|
||||
cur_id_str = d + 4;
|
||||
cur_id_type = d[1] & 0xf;
|
||||
if (cur_id_size >= id_len)
|
||||
cur_id_size = id_len - 1;
|
||||
memcpy(id, cur_id_str, cur_id_size);
|
||||
/* Decrease priority for truncated descriptor */
|
||||
if (cur_id_size != id_size)
|
||||
cur_id_size = 6;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
next_desig:
|
||||
d += d[3] + 4;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return id_size;
|
||||
}
|
||||
EXPORT_SYMBOL(scsi_vpd_lun_id);
|
||||
|
@ -415,6 +415,7 @@ static inline int scsi_execute_req(struct scsi_device *sdev,
|
||||
}
|
||||
extern void sdev_disable_disk_events(struct scsi_device *sdev);
|
||||
extern void sdev_enable_disk_events(struct scsi_device *sdev);
|
||||
extern int scsi_vpd_lun_id(struct scsi_device *, char *, size_t);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
extern int scsi_autopm_get_device(struct scsi_device *);
|
||||
|
Loading…
Reference in New Issue
Block a user