Skip to content

Commit

Permalink
scsi-generic: grab device and port SAS addresses from backend
Browse files Browse the repository at this point in the history
This lets a SAS adapter expose them through its own configuration
mechanism.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
  • Loading branch information
bonzini committed Feb 9, 2016
1 parent 2ecab40 commit 9fd7e85
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 0 deletions.
1 change: 1 addition & 0 deletions hw/scsi/scsi-disk.c
Expand Up @@ -2573,6 +2573,7 @@ static void scsi_block_realize(SCSIDevice *dev, Error **errp)
s->features |= (1 << SCSI_DISK_F_NO_REMOVABLE_DEVOPS);

scsi_realize(&s->qdev, errp);
scsi_generic_read_device_identification(&s->qdev);
}

static bool scsi_block_is_passthrough(SCSIDiskState *s, uint8_t *buf)
Expand Down
92 changes: 92 additions & 0 deletions hw/scsi/scsi-generic.c
Expand Up @@ -355,6 +355,96 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
}
}

static int read_naa_id(const uint8_t *p, uint64_t *p_wwn)
{
int i;

if ((p[1] & 0xF) == 3) {
/* NAA designator type */
if (p[3] != 8) {
return -EINVAL;
}
*p_wwn = ldq_be_p(p + 4);
return 0;
}

if ((p[1] & 0xF) == 8) {
/* SCSI name string designator type */
if (p[3] < 20 || memcmp(&p[4], "naa.", 4)) {
return -EINVAL;
}
if (p[3] > 20 && p[24] != ',') {
return -EINVAL;
}
*p_wwn = 0;
for (i = 8; i < 24; i++) {
char c = toupper(p[i]);
c -= (c >= '0' && c <= '9' ? '0' : 'A' - 10);
*p_wwn = (*p_wwn << 4) | c;
}
return 0;
}

return -EINVAL;
}

void scsi_generic_read_device_identification(SCSIDevice *s)
{
uint8_t cmd[6];
uint8_t buf[250];
uint8_t sensebuf[8];
sg_io_hdr_t io_header;
int ret;
int i, len;

memset(cmd, 0, sizeof(cmd));
memset(buf, 0, sizeof(buf));
cmd[0] = INQUIRY;
cmd[1] = 1;
cmd[2] = 0x83;
cmd[4] = sizeof(buf);

memset(&io_header, 0, sizeof(io_header));
io_header.interface_id = 'S';
io_header.dxfer_direction = SG_DXFER_FROM_DEV;
io_header.dxfer_len = sizeof(buf);
io_header.dxferp = buf;
io_header.cmdp = cmd;
io_header.cmd_len = sizeof(cmd);
io_header.mx_sb_len = sizeof(sensebuf);
io_header.sbp = sensebuf;
io_header.timeout = 6000; /* XXX */

ret = blk_ioctl(s->conf.blk, SG_IO, &io_header);
if (ret < 0 || io_header.driver_status || io_header.host_status) {
return;
}

len = MIN((buf[2] << 8) | buf[3], sizeof(buf) - 4);
for (i = 0; i + 3 <= len; ) {
const uint8_t *p = &buf[i + 4];
uint64_t wwn;

if (i + (p[3] + 4) > len) {
break;
}

if ((p[1] & 0x10) == 0) {
/* Associated with the logical unit */
if (read_naa_id(p, &wwn) == 0) {
s->wwn = wwn;
}
} else if ((p[1] & 0x10) == 0x10) {
/* Associated with the target port */
if (read_naa_id(p, &wwn) == 0) {
s->port_wwn = wwn;
}
}

i += p[3] + 4;
}
}

static int get_stream_blocksize(BlockBackend *blk)
{
uint8_t cmd[6];
Expand Down Expand Up @@ -458,6 +548,8 @@ static void scsi_generic_realize(SCSIDevice *s, Error **errp)
}

DPRINTF("block size %d\n", s->blocksize);

scsi_generic_read_device_identification(s);
}

const SCSIReqOps scsi_generic_req_ops = {
Expand Down
1 change: 1 addition & 0 deletions include/hw/scsi/scsi.h
Expand Up @@ -273,6 +273,7 @@ void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense);
void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense);
void scsi_device_report_change(SCSIDevice *dev, SCSISense sense);
void scsi_device_unit_attention_reported(SCSIDevice *dev);
void scsi_generic_read_device_identification(SCSIDevice *dev);
int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed);
SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lun);

Expand Down

0 comments on commit 9fd7e85

Please sign in to comment.