|
Packit Service |
35c908 |
/*
|
|
Packit Service |
35c908 |
* Copyright (c) 2008, Intel Corporation.
|
|
Packit Service |
35c908 |
*
|
|
Packit Service |
35c908 |
* This program is free software; you can redistribute it and/or modify it
|
|
Packit Service |
35c908 |
* under the terms and conditions of the GNU Lesser General Public License,
|
|
Packit Service |
35c908 |
* version 2.1, as published by the Free Software Foundation.
|
|
Packit Service |
35c908 |
*
|
|
Packit Service |
35c908 |
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
Packit Service |
35c908 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
Packit Service |
35c908 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
|
Packit Service |
35c908 |
* for more details.
|
|
Packit Service |
35c908 |
*
|
|
Packit Service |
35c908 |
* You should have received a copy of the GNU Lesser General Public License
|
|
Packit Service |
35c908 |
* along with this program; if not, write to the Free Software Foundation, Inc.,
|
|
Packit Service |
35c908 |
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
Packit Service |
35c908 |
*
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
#include <sys/ioctl.h>
|
|
Packit Service |
35c908 |
#include "utils.h"
|
|
Packit Service |
35c908 |
#include "api_lib.h"
|
|
Packit Service |
35c908 |
#include "adapt_impl.h"
|
|
Packit Service |
35c908 |
#include "fc_scsi.h"
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
/*
|
|
Packit Service |
35c908 |
* Perform INQUIRY of SCSI-generic device.
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
HBA_STATUS
|
|
Packit Service |
35c908 |
sg_issue_inquiry(const char *file, HBA_UINT8 cdb_byte1,
|
|
Packit Service |
35c908 |
HBA_UINT8 cdb_byte2, void *buf, HBA_UINT32 *lenp,
|
|
Packit Service |
35c908 |
HBA_UINT8 *statp, void *sense, HBA_UINT32 *sense_lenp)
|
|
Packit Service |
35c908 |
{
|
|
Packit Service |
35c908 |
struct sg_io_hdr hdr;
|
|
Packit Service |
35c908 |
struct scsi_inquiry cmd;
|
|
Packit Service |
35c908 |
size_t len;
|
|
Packit Service |
35c908 |
HBA_UINT32 slen;
|
|
Packit Service |
35c908 |
int fd;
|
|
Packit Service |
35c908 |
int rc;
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
len = *lenp;
|
|
Packit Service |
35c908 |
slen = *sense_lenp;
|
|
Packit Service |
35c908 |
if (slen > 255)
|
|
Packit Service |
35c908 |
slen = 255; /* must fit in an 8-bit field */
|
|
Packit Service |
35c908 |
if (len > 255)
|
|
Packit Service |
35c908 |
len = 255; /* sometimes must fit in 8-byte field */
|
|
Packit Service |
35c908 |
*lenp = 0;
|
|
Packit Service |
35c908 |
*statp = 0;
|
|
Packit Service |
35c908 |
fd = open(file, O_RDWR);
|
|
Packit Service |
35c908 |
if (fd < 0) {
|
|
Packit Service |
35c908 |
fprintf(stderr, "%s: open of %s failed, errno=0x%x\n",
|
|
Packit Service |
35c908 |
__func__, file, errno);
|
|
Packit Service |
35c908 |
return HBA_STATUS_ERROR;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
memset(&hdr, 0, sizeof(hdr));
|
|
Packit Service |
35c908 |
memset(&cmd, 0, sizeof(cmd));
|
|
Packit Service |
35c908 |
memset(buf, 0, len);
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
cmd.in_op = SCSI_OP_INQUIRY;
|
|
Packit Service |
35c908 |
cmd.in_flags = cdb_byte1;
|
|
Packit Service |
35c908 |
cmd.in_page_code = cdb_byte2;
|
|
Packit Service |
35c908 |
ua_net16_put(&cmd.in_alloc_len, len); /* field may actually be 8 bits */
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
hdr.interface_id = 'S';
|
|
Packit Service |
35c908 |
hdr.dxfer_direction = SG_DXFER_FROM_DEV;
|
|
Packit Service |
35c908 |
hdr.cmd_len = sizeof(cmd);
|
|
Packit Service |
35c908 |
hdr.mx_sb_len = slen;
|
|
Packit Service |
35c908 |
hdr.dxfer_len = len;
|
|
Packit Service |
35c908 |
hdr.dxferp = (unsigned char *) buf;
|
|
Packit Service |
35c908 |
hdr.cmdp = (unsigned char *) &cm;;
|
|
Packit Service |
35c908 |
hdr.sbp = (unsigned char *) sense;
|
|
Packit Service |
35c908 |
hdr.timeout = 3000; /* mS to wait for result */
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
rc = ioctl(fd, SG_IO, &hdr);
|
|
Packit Service |
35c908 |
if (rc < 0) {
|
|
Packit Service |
35c908 |
rc = errno;
|
|
Packit Service |
35c908 |
fprintf(stderr, "%s: SG_IO error. file %s, errno=0x%x\n",
|
|
Packit Service |
35c908 |
__func__, file, errno);
|
|
Packit Service |
35c908 |
close(fd);
|
|
Packit Service |
35c908 |
return HBA_STATUS_ERROR;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
close(fd);
|
|
Packit Service |
35c908 |
*lenp = len - hdr.resid;
|
|
Packit Service |
35c908 |
*sense_lenp = hdr.sb_len_wr;
|
|
Packit Service |
35c908 |
*statp = hdr.status;
|
|
Packit Service |
35c908 |
return HBA_STATUS_OK;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
static inline unsigned int
|
|
Packit Service |
35c908 |
sg_get_id_type(struct scsi_inquiry_desc *dp)
|
|
Packit Service |
35c908 |
{
|
|
Packit Service |
35c908 |
return dp->id_type_flags & SCSI_INQT_TYPE_MASK;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
/*
|
|
Packit Service |
35c908 |
* Get device ID information for HBA-API.
|
|
Packit Service |
35c908 |
* See the spec. We get the "best" information and leave the rest.
|
|
Packit Service |
35c908 |
* The buffer is left empty if nothing is gotten.
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
void
|
|
Packit Service |
35c908 |
sg_get_dev_id(const char *name, char *buf, size_t result_len)
|
|
Packit Service |
35c908 |
{
|
|
Packit Service |
35c908 |
struct scsi_inquiry_dev_id *idp;
|
|
Packit Service |
35c908 |
struct scsi_inquiry_desc *dp;
|
|
Packit Service |
35c908 |
struct scsi_inquiry_desc *best = NULL;
|
|
Packit Service |
35c908 |
char sense[252];
|
|
Packit Service |
35c908 |
HBA_UINT32 len;
|
|
Packit Service |
35c908 |
HBA_UINT32 slen;
|
|
Packit Service |
35c908 |
u_char scsi_stat;
|
|
Packit Service |
35c908 |
size_t rlen;
|
|
Packit Service |
35c908 |
size_t dlen;
|
|
Packit Service |
35c908 |
unsigned int type;
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
memset(buf, 0, result_len);
|
|
Packit Service |
35c908 |
len = result_len;
|
|
Packit Service |
35c908 |
slen = sizeof(sense);
|
|
Packit Service |
35c908 |
idp = (struct scsi_inquiry_dev_id *) buf;
|
|
Packit Service |
35c908 |
sg_issue_inquiry(name, SCSI_INQF_EVPD, SCSI_INQP_DEV_ID,
|
|
Packit Service |
35c908 |
buf, &len, &scsi_stat, sense, &slen);
|
|
Packit Service |
35c908 |
if (len < sizeof(*idp))
|
|
Packit Service |
35c908 |
return;
|
|
Packit Service |
35c908 |
if (idp->is_page_code != SCSI_INQP_DEV_ID)
|
|
Packit Service |
35c908 |
return;
|
|
Packit Service |
35c908 |
len -= sizeof(*idp);
|
|
Packit Service |
35c908 |
rlen = net16_get(&idp->is_page_len);
|
|
Packit Service |
35c908 |
if (rlen > len)
|
|
Packit Service |
35c908 |
rlen = len;
|
|
Packit Service |
35c908 |
dp = (struct scsi_inquiry_desc *) (idp + 1);
|
|
Packit Service |
35c908 |
for (; rlen >= sizeof(*dp);
|
|
Packit Service |
35c908 |
rlen -= dlen,
|
|
Packit Service |
35c908 |
dp = (struct scsi_inquiry_desc *) ((char *) dp + dlen)) {
|
|
Packit Service |
35c908 |
dlen = dp->id_designator_len + sizeof(*dp) -
|
|
Packit Service |
35c908 |
sizeof(dp->id_designator[0]);
|
|
Packit Service |
35c908 |
if (dlen > rlen)
|
|
Packit Service |
35c908 |
break;
|
|
Packit Service |
35c908 |
type = sg_get_id_type(dp);
|
|
Packit Service |
35c908 |
if (type > SCSI_DTYPE_NAA)
|
|
Packit Service |
35c908 |
continue;
|
|
Packit Service |
35c908 |
if (best == NULL)
|
|
Packit Service |
35c908 |
best = dp;
|
|
Packit Service |
35c908 |
else if (type == sg_get_id_type(best) &&
|
|
Packit Service |
35c908 |
(dp->id_designator_len < best->id_designator_len ||
|
|
Packit Service |
35c908 |
(dp->id_designator_len == best->id_designator_len &&
|
|
Packit Service |
35c908 |
memcmp(dp->id_designator, best->id_designator,
|
|
Packit Service |
35c908 |
best->id_designator_len) < 0))) {
|
|
Packit Service |
35c908 |
best = dp;
|
|
Packit Service |
35c908 |
} else if (type > sg_get_id_type(best))
|
|
Packit Service |
35c908 |
best = dp;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
if (best) {
|
|
Packit Service |
35c908 |
dp = best;
|
|
Packit Service |
35c908 |
dlen = dp->id_designator_len + sizeof(*dp) -
|
|
Packit Service |
35c908 |
sizeof(dp->id_designator[0]);
|
|
Packit Service |
35c908 |
if (dlen > result_len)
|
|
Packit Service |
35c908 |
dlen = 0; /* can't happen */
|
|
Packit Service |
35c908 |
else
|
|
Packit Service |
35c908 |
memmove(buf, dp, dlen); /* areas may overlap */
|
|
Packit Service |
35c908 |
memset(buf + dlen, 0, result_len - dlen);
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
/*
|
|
Packit Service |
35c908 |
* Read Capacity for HBA-API.
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
HBA_STATUS
|
|
Packit Service |
35c908 |
sg_issue_read_capacity(const char *file, void *resp, HBA_UINT32 *resp_lenp,
|
|
Packit Service |
35c908 |
HBA_UINT8 *statp, void *sense, HBA_UINT32 *sense_lenp)
|
|
Packit Service |
35c908 |
{
|
|
Packit Service |
35c908 |
struct sg_io_hdr hdr;
|
|
Packit Service |
35c908 |
struct scsi_rcap10 cmd;
|
|
Packit Service |
35c908 |
struct scsi_rcap16 cmd_16;
|
|
Packit Service |
35c908 |
size_t len;
|
|
Packit Service |
35c908 |
int fd;
|
|
Packit Service |
35c908 |
int rc;
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
len = *resp_lenp;
|
|
Packit Service |
35c908 |
*resp_lenp = 0;
|
|
Packit Service |
35c908 |
fd = open(file, O_RDWR);
|
|
Packit Service |
35c908 |
if (fd < 0) {
|
|
Packit Service |
35c908 |
fprintf(stderr, "%s: open of %s failed, errno=0x%x\n",
|
|
Packit Service |
35c908 |
__func__, file, errno);
|
|
Packit Service |
35c908 |
return errno;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
memset(&hdr, 0, sizeof(hdr));
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
/* If the response buffer size is enough to
|
|
Packit Service |
35c908 |
* accomodate READ CAPACITY(16) response issue
|
|
Packit Service |
35c908 |
* SCSI READ CAPACITY(16) else issue
|
|
Packit Service |
35c908 |
* SCSI READ CAPACITY(10)
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
if (len >= sizeof(struct scsi_rcap16_resp)) {
|
|
Packit Service |
35c908 |
memset(&cmd_16, 0, sizeof(cmd_16));
|
|
Packit Service |
35c908 |
cmd_16.rc_op = SCSI_OP_SA_IN_16;
|
|
Packit Service |
35c908 |
cmd_16.rc_sa = SCSI_SA_READ_CAP16;
|
|
Packit Service |
35c908 |
ua_net32_put(&cmd_16.rc_alloc_len, len);
|
|
Packit Service |
35c908 |
hdr.cmd_len = sizeof(cmd_16);
|
|
Packit Service |
35c908 |
hdr.cmdp = (unsigned char *) &cmd_16;
|
|
Packit Service |
35c908 |
} else {
|
|
Packit Service |
35c908 |
memset(&cmd, 0, sizeof(cmd));
|
|
Packit Service |
35c908 |
cmd.rc_op = SCSI_OP_READ_CAP10;
|
|
Packit Service |
35c908 |
hdr.cmd_len = sizeof(cmd);
|
|
Packit Service |
35c908 |
hdr.cmdp = (unsigned char *) &cm;;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
hdr.interface_id = 'S';
|
|
Packit Service |
35c908 |
hdr.dxfer_direction = SG_DXFER_FROM_DEV;
|
|
Packit Service |
35c908 |
hdr.mx_sb_len = *sense_lenp;
|
|
Packit Service |
35c908 |
hdr.dxfer_len = len;
|
|
Packit Service |
35c908 |
hdr.dxferp = (unsigned char *) resp;
|
|
Packit Service |
35c908 |
hdr.sbp = (unsigned char *) sense;
|
|
Packit Service |
35c908 |
hdr.timeout = UINT_MAX;
|
|
Packit Service |
35c908 |
hdr.timeout = 3000; /* mS to wait for result */
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
rc = ioctl(fd, SG_IO, &hdr);
|
|
Packit Service |
35c908 |
if (rc < 0) {
|
|
Packit Service |
35c908 |
rc = errno;
|
|
Packit Service |
35c908 |
fprintf(stderr, "%s: SG_IO error. file %s, errno=0x%x\n",
|
|
Packit Service |
35c908 |
__func__, file, errno);
|
|
Packit Service |
35c908 |
close(fd);
|
|
Packit Service |
35c908 |
return HBA_STATUS_ERROR;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
close(fd);
|
|
Packit Service |
35c908 |
*resp_lenp = len - hdr.resid;
|
|
Packit Service |
35c908 |
*sense_lenp = hdr.sb_len_wr;
|
|
Packit Service |
35c908 |
*statp = hdr.status;
|
|
Packit Service |
35c908 |
return HBA_STATUS_OK;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
/*
|
|
Packit Service |
35c908 |
* Report LUNs for HBA-API.
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
HBA_STATUS
|
|
Packit Service |
35c908 |
sg_issue_report_luns(const char *file, void *resp, HBA_UINT32 *resp_lenp,
|
|
Packit Service |
35c908 |
HBA_UINT8 *statp, void *sense, HBA_UINT32 *sense_lenp)
|
|
Packit Service |
35c908 |
{
|
|
Packit Service |
35c908 |
struct sg_io_hdr hdr;
|
|
Packit Service |
35c908 |
struct scsi_report_luns cmd;
|
|
Packit Service |
35c908 |
size_t len;
|
|
Packit Service |
35c908 |
int fd;
|
|
Packit Service |
35c908 |
int rc;
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
len = *resp_lenp;
|
|
Packit Service |
35c908 |
*resp_lenp = 0;
|
|
Packit Service |
35c908 |
fd = open(file, O_RDWR);
|
|
Packit Service |
35c908 |
if (fd < 0) {
|
|
Packit Service |
35c908 |
fprintf(stderr, "%s: open of %s failed, errno=0x%x\n",
|
|
Packit Service |
35c908 |
__func__, file, errno);
|
|
Packit Service |
35c908 |
return errno;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
memset(&hdr, 0, sizeof(hdr));
|
|
Packit Service |
35c908 |
memset(&cmd, 0, sizeof(cmd));
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
cmd.rl_op = SCSI_OP_REPORT_LUNS;
|
|
Packit Service |
35c908 |
ua_net32_put(&cmd.rl_alloc_len, len);
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
hdr.interface_id = 'S';
|
|
Packit Service |
35c908 |
hdr.dxfer_direction = SG_DXFER_FROM_DEV;
|
|
Packit Service |
35c908 |
hdr.cmd_len = sizeof(cmd);
|
|
Packit Service |
35c908 |
hdr.mx_sb_len = *sense_lenp;
|
|
Packit Service |
35c908 |
hdr.dxfer_len = len;
|
|
Packit Service |
35c908 |
hdr.dxferp = (unsigned char *) resp;
|
|
Packit Service |
35c908 |
hdr.cmdp = (unsigned char *) &cm;;
|
|
Packit Service |
35c908 |
hdr.sbp = (unsigned char *) sense;
|
|
Packit Service |
35c908 |
hdr.timeout = UINT_MAX;
|
|
Packit Service |
35c908 |
hdr.timeout = 3000; /* mS to wait for result */
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
rc = ioctl(fd, SG_IO, &hdr);
|
|
Packit Service |
35c908 |
if (rc < 0) {
|
|
Packit Service |
35c908 |
rc = errno;
|
|
Packit Service |
35c908 |
fprintf(stderr, "%s: SG_IO error. file %s, errno=0x%x\n",
|
|
Packit Service |
35c908 |
__func__, file, errno);
|
|
Packit Service |
35c908 |
close(fd);
|
|
Packit Service |
35c908 |
return HBA_STATUS_ERROR;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
close(fd);
|
|
Packit Service |
35c908 |
*resp_lenp = len - hdr.resid;
|
|
Packit Service |
35c908 |
*sense_lenp = hdr.sb_len_wr;
|
|
Packit Service |
35c908 |
*statp = hdr.status;
|
|
Packit Service |
35c908 |
return HBA_STATUS_OK;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
|