#include <sys/usb/usba/usbai_version.h>
#include <sys/scsi/scsi.h>
#include <sys/callb.h>
#include <sys/strsubr.h>
#include <sys/strsun.h>
#include <sys/usb/usba.h>
#include <sys/usb/usba/usba_private.h>
#include <sys/usb/usba/usba_ugen.h>
#include <sys/usb/clients/mass_storage/usb_bulkonly.h>
#include <sys/usb/scsa2usb/scsa2usb.h>
int scsa2usb_bulk_only_transport(scsa2usb_state_t *,
scsa2usb_cmd_t *);
static void scsa2usb_fill_in_cbw(scsa2usb_state_t *, scsa2usb_cmd_t *,
mblk_t *);
static void scsa2usb_bulk_only_reset_recovery(scsa2usb_state_t *);
static void scsa2usb_bulk_only_handle_error(scsa2usb_state_t *,
usb_bulk_req_t *);
int scsa2usb_bulk_only_get_max_lun(scsa2usb_state_t *);
static int scsa2usb_handle_status_start(scsa2usb_state_t *,
usb_bulk_req_t *);
static int scsa2usb_handle_csw_result(scsa2usb_state_t *, mblk_t *);
extern void scsa2usb_setup_next_xfer(scsa2usb_state_t *, scsa2usb_cmd_t *);
extern int scsa2usb_handle_data_start(scsa2usb_state_t *,
scsa2usb_cmd_t *, usb_bulk_req_t *);
extern void scsa2usb_handle_data_done(scsa2usb_state_t *, scsa2usb_cmd_t *,
usb_bulk_req_t *);
extern usb_bulk_req_t *scsa2usb_init_bulk_req(scsa2usb_state_t *,
size_t, uint_t, usb_req_attrs_t, usb_flags_t);
extern int scsa2usb_bulk_timeout(int);
extern int scsa2usb_clear_ept_stall(scsa2usb_state_t *, uint_t,
usb_pipe_handle_t, char *);
extern void scsa2usb_close_usb_pipes(scsa2usb_state_t *);
#ifdef DEBUG
extern void scsa2usb_print_cdb(scsa2usb_state_t *, scsa2usb_cmd_t *);
#endif
#ifdef SCSA2USB_BULK_ONLY_TEST
int scsa2usb_test_case_2 = 0;
int scsa2usb_test_case_3 = 0;
int scsa2usb_test_case_4 = 0;
int scsa2usb_test_case_7 = 0;
extern int scsa2usb_test_case_8;
int scsa2usb_test_case_9 = 0;
extern int scsa2usb_test_case_10;
int scsa2usb_test_case_13 = 0;
#endif
int
scsa2usb_bulk_only_transport(scsa2usb_state_t *scsa2usbp, scsa2usb_cmd_t *cmd)
{
int rval;
int nretry;
usb_bulk_req_t *req;
ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
Cmd_Phase:
req = scsa2usb_init_bulk_req(scsa2usbp, USB_BULK_CBWCMD_LEN,
SCSA2USB_BULK_PIPE_TIMEOUT, USB_ATTRS_PIPE_RESET, USB_FLAGS_SLEEP);
scsa2usb_fill_in_cbw(scsa2usbp, cmd, req->bulk_data);
SCSA2USB_PRINT_CDB(scsa2usbp, cmd);
mutex_exit(&scsa2usbp->scsa2usb_mutex);
ASSERT(req->bulk_timeout);
rval = usb_pipe_bulk_xfer(scsa2usbp->scsa2usb_bulkout_pipe, req,
USB_FLAGS_SLEEP);
mutex_enter(&scsa2usbp->scsa2usb_mutex);
USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
"scsa2usb_bulk_only_transport: "
"sent cmd = 0x%x Tag = 0x%x DataXferLen = 0x%lx rval = %d",
cmd->cmd_cdb[SCSA2USB_OPCODE], cmd->cmd_tag, cmd->cmd_xfercount,
rval);
if (rval != USB_SUCCESS) {
scsa2usb_bulk_only_handle_error(scsa2usbp, req);
return (TRAN_FATAL_ERROR);
}
SCSA2USB_FREE_MSG(req->bulk_data);
req->bulk_data = NULL;
req->bulk_timeout = scsa2usb_bulk_timeout(cmd->cmd_timeout);
cmd->cmd_resid_xfercount = cmd->cmd_xfercount;
if (cmd->cmd_xfercount) {
rval = scsa2usb_handle_data_start(scsa2usbp, cmd, req);
scsa2usb_handle_data_done(scsa2usbp, cmd, req);
if (rval != USB_SUCCESS) {
USB_DPRINTF_L2(DPRINT_MASK_SCSA,
scsa2usbp->scsa2usb_log_handle,
"data xfer phase, error = %d, cr = %d",
rval, req->bulk_completion_reason);
if (req->bulk_completion_reason == USB_CR_STALL) {
if (scsa2usbp->scsa2usb_cur_pkt) {
scsa2usbp->scsa2usb_cur_pkt->
pkt_reason = CMD_TRAN_ERR;
}
} else {
scsa2usb_bulk_only_handle_error(scsa2usbp, req);
return (TRAN_FATAL_ERROR);
}
}
SCSA2USB_FREE_MSG(req->bulk_data);
req->bulk_data = NULL;
}
for (nretry = 0; nretry < SCSA2USB_STATUS_RETRIES; nretry++) {
rval = scsa2usb_handle_status_start(scsa2usbp, req);
if ((rval != USB_SUCCESS) &&
(req->bulk_completion_reason == USB_CR_STALL)) {
scsa2usbp->scsa2usb_pkt_state =
SCSA2USB_PKT_PROCESS_CSW;
} else {
break;
}
}
if (rval == USB_SUCCESS) {
rval = scsa2usb_handle_csw_result(scsa2usbp, req->bulk_data);
} else {
scsa2usb_bulk_only_handle_error(scsa2usbp, req);
return (TRAN_FATAL_ERROR);
}
SCSA2USB_FREE_BULK_REQ(req);
if ((rval == USB_SUCCESS) &&
(scsa2usbp->scsa2usb_cur_pkt->pkt_reason == CMD_CMPLT) &&
(cmd->cmd_xfercount != 0) &&
!cmd->cmd_done) {
scsa2usb_setup_next_xfer(scsa2usbp, cmd);
goto Cmd_Phase;
}
return (rval == USB_SUCCESS ? TRAN_ACCEPT : TRAN_FATAL_ERROR);
}
static void
scsa2usb_fill_in_cbw(scsa2usb_state_t *scsa2usbp,
scsa2usb_cmd_t *cmd, mblk_t *mp)
{
int i;
int len;
uchar_t dir, *cdb = (uchar_t *)(&cmd->cmd_cdb);
ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
*mp->b_wptr++ = CBW_MSB(CBW_SIGNATURE); ;
*mp->b_wptr++ = CBW_MID1(CBW_SIGNATURE);
*mp->b_wptr++ = CBW_MID2(CBW_SIGNATURE);
*mp->b_wptr++ = CBW_LSB(CBW_SIGNATURE);
*mp->b_wptr++ = CBW_LSB(cmd->cmd_tag);
*mp->b_wptr++ = CBW_MID2(cmd->cmd_tag);
*mp->b_wptr++ = CBW_MID1(cmd->cmd_tag);
*mp->b_wptr++ = CBW_MSB(cmd->cmd_tag);
dir = cmd->cmd_dir;
len = cmd->cmd_xfercount;
#ifdef SCSA2USB_BULK_ONLY_TEST
if (scsa2usb_test_case_2 && (cdb[0] == SCMD_READ_CAPACITY)) {
scsa2usb_test_case_2 = len = 0;
USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
"TEST 2: Hn < Di cdb: 0x%x len: 0x%x", cdb[0], len);
}
if (scsa2usb_test_case_3 && (cmd->cmd_dir == CBW_DIR_OUT)) {
if (cdb[0] == SCMD_WRITE_G1) {
scsa2usb_test_case_3 = len = 0;
USB_DPRINTF_L1(DPRINT_MASK_SCSA,
scsa2usbp->scsa2usb_log_handle,
"TEST 3: Hn < Do cdb: 0x%x len:%x", cdb[0], len);
}
}
if (scsa2usb_test_case_4 && (cdb[0] == SCMD_READ_G1)) {
cdb[0] = 0x5e;
USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
"TEST 4: Hi > Dn: changed cdb to 0x%x", cdb[0]);
scsa2usb_test_case_4 = 0;
}
if (scsa2usb_test_case_7 && (cmd->cmd_cdb[0] == SCMD_READ_G1)) {
len -= 0x10;
USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
"TEST 7: Hi < Di cdb: 0x%x len: 0x%x", cdb[0], len);
scsa2usb_test_case_7 = 0;
}
if (scsa2usb_test_case_8 && (cdb[0] == SCMD_READ_G1)) {
dir = (dir == CBW_DIR_IN) ? CBW_DIR_OUT : dir;
USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
"TEST 8: Hi <> Do cdb: 0x%x dir: 0x%x", cdb[0], dir);
}
if (scsa2usb_test_case_9 && (cdb[0] == SCMD_WRITE_G1)) {
USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
"TEST 9: Ho <> Di (%x)", cdb[0]);
cdb[SCSA2USB_LEN_0] = cdb[SCSA2USB_LEN_1] = 0;
scsa2usb_test_case_9 = 0;
}
if (scsa2usb_test_case_10 && (cdb[0] == SCMD_WRITE_G1)) {
dir = (dir == CBW_DIR_OUT) ? CBW_DIR_IN : dir;
USB_DPRINTF_L1(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
"TEST 10: Ho <> Di cdb: 0x%x dir: 0x%x", cdb[0], dir);
}
if (scsa2usb_test_case_13) {
if ((cdb[0] == SCMD_WRITE_G1) || (cdb[0] == SCMD_READ_G1)) {
USB_DPRINTF_L1(DPRINT_MASK_SCSA,
scsa2usbp->scsa2usb_log_handle, "TEST 13: Ho < Do");
len -= 30;
scsa2usb_test_case_13 = 0;
}
}
#endif
*mp->b_wptr++ = CBW_MSB(len);
*mp->b_wptr++ = CBW_MID1(len);
*mp->b_wptr++ = CBW_MID2(len);
*mp->b_wptr++ = CBW_LSB(len);
*mp->b_wptr++ = dir;
*mp->b_wptr++ = cmd->cmd_pkt->pkt_address.a_lun;
*mp->b_wptr++ = cmd->cmd_actual_len;
for (i = 0; i < CBW_CDB_LEN; i++) {
*mp->b_wptr++ = *cdb++;
}
#ifdef DUMP_CWB
{
int len = mp->b_wptr - mp->b_rptr;
char *buf;
int i;
cmn_err(CE_CONT, "CWB: len=%d\n", len);
buf = kmem_zalloc(512, KM_SLEEP);
for (i = 0; i < len; i++) {
sprintf(&buf[strlen(buf)], "%02x ", mp->b_rptr[i]);
}
cmn_err(CE_CONT, "%s\n", buf);
kmem_free(buf, 512);
}
#endif
}
static void
scsa2usb_bulk_only_handle_error(scsa2usb_state_t *scsa2usbp,
usb_bulk_req_t *req)
{
struct scsi_pkt *pkt = scsa2usbp->scsa2usb_cur_pkt;
USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
"scsa2usb_bulk_only_handle_error: req = 0x%p, cr = 0x%x",
(void *)req, (req ? req->bulk_completion_reason : 0));
if (req) {
SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
switch (req->bulk_completion_reason) {
case USB_CR_STALL:
if (pkt) {
pkt->pkt_reason = CMD_TRAN_ERR;
}
break;
case USB_CR_TIMEOUT:
if (pkt) {
pkt->pkt_reason = CMD_TIMEOUT;
pkt->pkt_statistics |= STAT_TIMEOUT;
}
break;
case USB_CR_DEV_NOT_RESP:
if (pkt) {
pkt->pkt_reason = CMD_DEV_GONE;
pkt->pkt_state = STATE_GOT_BUS;
}
break;
default:
if (pkt) {
pkt->pkt_reason = CMD_TRAN_ERR;
}
}
scsa2usb_bulk_only_reset_recovery(scsa2usbp);
}
SCSA2USB_FREE_BULK_REQ(req);
}
static int
scsa2usb_handle_status_start(scsa2usb_state_t *scsa2usbp,
usb_bulk_req_t *req)
{
int rval;
USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
"scsa2usb_handle_status_start: req = 0x%p", (void *)req);
ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
#ifdef SCSA2USB_BULK_ONLY_TEST
req->bulk_attributes = 0;
#else
req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK;
#endif
req->bulk_len = CSW_LEN;
SCSA2USB_FREE_MSG(req->bulk_data);
req->bulk_data = allocb_wait(req->bulk_len,
BPRI_LO, STR_NOSIG, NULL);
mutex_exit(&scsa2usbp->scsa2usb_mutex);
ASSERT(req->bulk_timeout);
rval = usb_pipe_bulk_xfer(scsa2usbp->scsa2usb_bulkin_pipe, req,
USB_FLAGS_SLEEP);
mutex_enter(&scsa2usbp->scsa2usb_mutex);
USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
"scsa2usb_handle_status_start: END rval = 0x%x", rval);
if (rval != USB_SUCCESS) {
if (scsa2usbp->scsa2usb_pkt_state == SCSA2USB_PKT_PROCESS_CSW) {
scsa2usb_bulk_only_reset_recovery(scsa2usbp);
return (rval);
}
if (req->bulk_completion_reason == USB_CR_STALL) {
(void) scsa2usb_clear_ept_stall(scsa2usbp,
scsa2usbp->scsa2usb_bulkin_ept.bEndpointAddress,
scsa2usbp->scsa2usb_bulkin_pipe, "bulk-in");
}
}
return (rval);
}
static int
scsa2usb_handle_csw_result(scsa2usb_state_t *scsa2usbp, mblk_t *data)
{
int rval = USB_SUCCESS;
int residue;
char *msg = "CSW FAILED";
uint_t signature, tag, status;
usb_bulk_csw_t csw;
struct scsi_pkt *pkt = scsa2usbp->scsa2usb_cur_pkt;
scsa2usb_cmd_t *cmd = PKT2CMD(pkt);
ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
if (data == NULL) {
USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
"scsa2usb_handle_csw_result: data == NULL");
return (USB_FAILURE);
}
if (MBLKL(data) != CSW_LEN) {
USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
"scsa2usb_handle_csw_result: no enough data (%ld)",
(long)(MBLKL(data)));
return (USB_FAILURE);
}
bcopy(data->b_rptr, &csw, CSW_LEN);
status = csw.csw_bCSWStatus;
signature = SCSA2USB_MK_32BIT(csw.csw_dCSWSignature3,
csw.csw_dCSWSignature2, csw.csw_dCSWSignature1,
csw.csw_dCSWSignature0);
residue = SCSA2USB_MK_32BIT(csw.csw_dCSWDataResidue3,
csw.csw_dCSWDataResidue2, csw.csw_dCSWDataResidue1,
csw.csw_dCSWDataResidue0);
tag = SCSA2USB_MK_32BIT(csw.csw_dCSWTag3, csw.csw_dCSWTag2,
csw.csw_dCSWTag1, csw.csw_dCSWTag0);
USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
"CSW: Signature = 0x%x Status = 0%x Tag = 0x%x Residue = 0x%x",
signature, status, tag, residue);
if ((signature != CSW_SIGNATURE) || (tag != cmd->cmd_tag) ||
(status > CSW_STATUS_PHASE_ERROR)) {
USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
"CSW_ERR: Status = 0x%x, Tag = 0x%x xfercount = 0x%lx",
status, cmd->cmd_tag, cmd->cmd_total_xfercount);
return (USB_FAILURE);
}
switch (status) {
case CSW_STATUS_GOOD:
if (!cmd->cmd_done && residue &&
(residue == cmd->cmd_total_xfercount)) {
*(pkt->pkt_scbp) = STATUS_CHECK;
cmd->cmd_xfercount = 0;
cmd->cmd_done = 1;
} else {
msg = "CSW GOOD";
}
break;
case CSW_STATUS_FAILED:
*(pkt->pkt_scbp) = STATUS_CHECK;
cmd->cmd_done = 1;
break;
case CSW_STATUS_PHASE_ERROR:
USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
"scsa2usb_handle_csw_result: Phase Error");
scsa2usb_bulk_only_handle_error(scsa2usbp, NULL);
return (USB_FAILURE);
default:
USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
"scsa2usb_handle_csw_result: Invalid CSW");
scsa2usb_bulk_only_handle_error(scsa2usbp, NULL);
return (USB_SUCCESS);
}
if (residue || cmd->cmd_resid_xfercount) {
USB_DPRINTF_L2(DPRINT_MASK_SCSA,
scsa2usbp->scsa2usb_log_handle,
"total=0x%lx cmd_xfercount=0x%lx residue=0x%x "
"cmd_offset=0x%lx",
cmd->cmd_total_xfercount, cmd->cmd_xfercount,
residue, cmd->cmd_offset);
cmd->cmd_total_xfercount += cmd->cmd_xfercount -
cmd->cmd_resid_xfercount;
cmd->cmd_offset -= cmd->cmd_xfercount -
cmd->cmd_resid_xfercount;
if ((!(scsa2usbp->scsa2usb_attrs &
SCSA2USB_ATTRS_USE_CSW_RESIDUE)) ||
(residue < 0) ||
(residue > cmd->cmd_total_xfercount)) {
cmd->cmd_total_xfercount -=
cmd->cmd_xfercount - cmd->cmd_resid_xfercount;
cmd->cmd_offset +=
cmd->cmd_xfercount - cmd->cmd_resid_xfercount;
} else {
cmd->cmd_total_xfercount -=
cmd->cmd_xfercount -
max(min(residue, cmd->cmd_xfercount),
cmd->cmd_resid_xfercount);
cmd->cmd_offset +=
cmd->cmd_xfercount -
max(min(residue, cmd->cmd_xfercount),
cmd->cmd_resid_xfercount);
if ((cmd->cmd_resid_xfercount == 0) &&
(residue == cmd->cmd_xfercount)) {
cmd->cmd_xfercount = 0;
cmd->cmd_done = 1;
}
}
pkt->pkt_resid = cmd->cmd_total_xfercount;
}
USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
"scsa2usb_handle_csw_result: %s, resid: 0x%lx",
msg, pkt->pkt_resid);
SCSA2USB_SET_PKT_DO_COMP_STATE(scsa2usbp);
return (rval);
}
static void
scsa2usb_bulk_only_reset_recovery(scsa2usb_state_t *scsa2usbp)
{
int rval;
usb_cr_t completion_reason;
usb_cb_flags_t cb_flags;
USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
"scsa2usb_bulk_only_reset_recovery: scsa2usbp = 0x%p",
(void *)scsa2usbp);
ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
if (!(SCSA2USB_DEVICE_ACCESS_OK(scsa2usbp))) {
return;
}
if (scsa2usbp->scsa2usb_cur_pkt) {
scsa2usbp->scsa2usb_cur_pkt->pkt_statistics |= STAT_DEV_RESET;
}
scsa2usbp->scsa2usb_pipe_state = SCSA2USB_PIPE_DEV_RESET;
mutex_exit(&scsa2usbp->scsa2usb_mutex);
rval = usb_pipe_sync_ctrl_xfer(scsa2usbp->scsa2usb_dip,
scsa2usbp->scsa2usb_default_pipe,
USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF,
(uint8_t)BULK_ONLY_RESET,
0,
scsa2usbp->scsa2usb_intfc_num,
0,
NULL, 0, &completion_reason, &cb_flags, 0);
mutex_enter(&scsa2usbp->scsa2usb_mutex);
USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
"\tbulk-only device-reset rval: %d", rval);
if (rval != USB_SUCCESS) {
goto exc_exit;
}
rval = scsa2usb_clear_ept_stall(scsa2usbp,
scsa2usbp->scsa2usb_bulkin_ept.bEndpointAddress,
scsa2usbp->scsa2usb_bulkin_pipe, "bulk-in");
USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
"\tbulk-in pipe clear stall: %d", rval);
if (rval != USB_SUCCESS) {
goto exc_exit;
}
rval = scsa2usb_clear_ept_stall(scsa2usbp,
scsa2usbp->scsa2usb_bulkout_ept.bEndpointAddress,
scsa2usbp->scsa2usb_bulkout_pipe, "bulk-out");
USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
"\tbulk-out pipe clear stall: %d", rval);
exc_exit:
scsa2usbp->scsa2usb_pipe_state &= ~SCSA2USB_PIPE_DEV_RESET;
}
int
scsa2usb_bulk_only_get_max_lun(scsa2usb_state_t *scsa2usbp)
{
int luns = 1, rval;
mblk_t *data = NULL;
usb_cr_t completion_reason;
usb_cb_flags_t cb_flags;
USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
"scsa2usb_bulk_only_get_max_lun:");
ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));
mutex_exit(&scsa2usbp->scsa2usb_mutex);
rval = usb_pipe_sync_ctrl_xfer(scsa2usbp->scsa2usb_dip,
scsa2usbp->scsa2usb_default_pipe,
BULK_ONLY_GET_MAXLUN_BMREQ,
BULK_ONLY_GET_MAXLUN_REQ,
0,
scsa2usbp->scsa2usb_intfc_num,
1,
&data, 0,
&completion_reason, &cb_flags, 0);
mutex_enter(&scsa2usbp->scsa2usb_mutex);
if (rval != USB_SUCCESS) {
USB_DPRINTF_L2(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
"get max lun failed, rval=%d cr=%d cb=0x%x data=0x%p",
rval, completion_reason, cb_flags, (void *)data);
} else {
if (MBLKL(data) != 1) {
USB_DPRINTF_L2(DPRINT_MASK_SCSA,
scsa2usbp->scsa2usb_log_handle,
"device reported incorrect luns (adjusting to 1)");
} else {
luns = *data->b_rptr + 1;
if ((luns >= SCSA2USB_MAX_LUNS) || (luns <= 0)) {
USB_DPRINTF_L2(DPRINT_MASK_SCSA,
scsa2usbp->scsa2usb_log_handle,
"device reported %d luns "
"(adjusting to 1)", luns);
luns = 1;
}
}
}
SCSA2USB_FREE_MSG(data);
return (luns);
}