#include <stdio.h>
#include <sys/types.h>
#include <sys/scsi/impl/uscsi.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <libintl.h>
#include "transport.h"
#include "main.h"
#include "util.h"
#include "mmc.h"
char rqbuf[RQBUFLEN];
uchar_t uscsi_status, rqstatus, rqresid;
static struct uscsi_cmd uscmd;
static char ucdb[16];
static uint_t total_retries;
struct uscsi_cmd *
get_uscsi_cmd(void)
{
(void) memset(&uscmd, 0, sizeof (uscmd));
(void) memset(ucdb, 0, 16);
uscmd.uscsi_cdb = ucdb;
return (&uscmd);
}
int
uscsi(int fd, struct uscsi_cmd *scmd)
{
int ret, global_rqsense;
int retries, max_retries;
if (!(scmd->uscsi_flags & USCSI_RQENABLE)) {
scmd->uscsi_flags |= USCSI_RQENABLE;
scmd->uscsi_rqlen = RQBUFLEN;
scmd->uscsi_rqbuf = rqbuf;
global_rqsense = 1;
} else {
global_rqsense = 0;
}
if ((device_type != CD_RW) && ((scmd->uscsi_cdb[0] == WRITE_10_CMD) ||
(scmd->uscsi_cdb[0] == READ_INFO_CMD) || (scmd->uscsi_cdb[0] ==
SYNC_CACHE_CMD) || (scmd->uscsi_cdb[0] == CLOSE_TRACK_CMD))) {
max_retries = 500;
} else {
max_retries = 40;
}
for (retries = 0; retries < max_retries; retries++) {
scmd->uscsi_status = 0;
if (global_rqsense)
(void) memset(rqbuf, 0, RQBUFLEN);
if (debug && verbose) {
int i;
(void) printf("cmd:[");
for (i = 0; i < scmd->uscsi_cdblen; i++)
(void) printf("0x%02x ",
(uchar_t)scmd->uscsi_cdb[i]);
(void) printf("]\n");
}
raise_priv();
ret = ioctl(fd, USCSICMD, scmd);
lower_priv();
if ((ret == 0) && (scmd->uscsi_status == 2)) {
ret = -1;
errno = EIO;
}
if (global_rqsense && (ret < 0) && (scmd->uscsi_status == 2)) {
if ((SENSE_KEY(rqbuf) == 2) && (ASC(rqbuf) == 4) &&
((ASCQ(rqbuf) == 0) || (ASCQ(rqbuf) == 1) ||
(ASCQ(rqbuf) == 4)) || (ASCQ(rqbuf) == 7)) {
total_retries++;
(void) sleep(3);
continue;
}
if (debug) {
if ((SENSE_KEY(rqbuf) == 5) && (ASC(rqbuf) ==
0x21) && (ASCQ(rqbuf) == 2)) {
(void) printf(gettext(
"Buffer underrun occurred! trying to recover...\n"));
}
}
if ((SENSE_KEY(rqbuf) == 2) && (ASC(rqbuf) == 4) &&
(ASCQ(rqbuf) == 8)) {
total_retries++;
if ((device_type != CD_RW) &&
((scmd->uscsi_cdb[0] == CLOSE_TRACK_CMD) ||
((scmd->uscsi_cdb[0] == READ_INFO_CMD) &&
simulation)))
(void) sleep(3);
else
ms_delay(500);
continue;
}
if ((SENSE_KEY(rqbuf) == 6) && ((ASC(rqbuf) == 0x28) ||
(ASC(rqbuf) == 0x29))) {
(void) sleep(3);
total_retries++;
continue;
}
if ((SENSE_KEY(rqbuf) == 5) &&
(device_type == DVD_PLUS ||
device_type == DVD_PLUS_W)) {
if (scmd->uscsi_cdb[0] == MODE_SELECT_10_CMD &&
ASC(rqbuf) == 0x26) {
ret = 1;
break;
}
if (scmd->uscsi_cdb[0] == REZERO_UNIT_CMD &&
ASC(rqbuf) == 0x20) {
ret = 1;
break;
}
}
if ((SENSE_KEY(rqbuf) == 0) && (ASC(rqbuf) == 0) &&
(ASCQ(rqbuf) == 0)) {
ret = 0;
break;
}
if (debug) {
(void) printf("cmd: 0x%02x ret:%i status:%02x "
" sense: %02x ASC: %02x ASCQ:%02x\n",
(uchar_t)scmd->uscsi_cdb[0], ret,
scmd->uscsi_status,
(uchar_t)SENSE_KEY(rqbuf),
(uchar_t)ASC(rqbuf), (uchar_t)ASCQ(rqbuf));
}
}
break;
}
if ((ret < 0) && (global_rqsense)) {
uscsi_status = scmd->uscsi_status;
rqstatus = scmd->uscsi_rqstatus;
rqresid = scmd->uscsi_rqresid;
}
if (debug && retries) {
(void) printf("total retries: %d\n", total_retries);
}
return (ret);
}