a4091: Added detection of SCSI bus stuck busy to "a4091 -t"

a4091d: Added ^C abort to display
a4091d: Added decode of xs_control, xs_status, chan_flags, chan_tflags
a4091d: Added interrupt structude decode, change_periphtab list
a4091d: Added "a4091d -p" to decode periph struct at specified address
a4091d: Added default open of a4091.device target without generating I/O
a4091.device will not terminate with I/O still pending
Added support for TD_REMOVE, TD_ADDCHANGEINT, and TD_REMCHANGEINT
Improved OpenDevice() and I/O error codes to give better reason for failure
Replaced polled SCSI I/O timeout with more accurate and efficient processing
Added panic() requester for rare panic cases
Added option to disable SCSI target disconnect
Improved SCSI timeout handling to quiesce channel before reset hammer
Fixed (prev introduced) bug where SCSI timeout could lead to I/O hang
Adjusted SCSI EJECT / LOAD timeouts to be successful with more drive types
Improved accuracy of TD_CHANGESTATE immediately following TD_EJECT
This commit is contained in:
Chris Hooper 2022-09-26 02:45:43 -07:00
parent aff7e8d0c9
commit 110fc9b97a
20 changed files with 1068 additions and 399 deletions

View File

@ -51,7 +51,7 @@ CFLAGS += -D_KERNEL -DPORT_AMIGA
#CFLAGS += -DDEBUG_SIOP # Debug siop.c
#CFLAGS += -DDEBUG_RDB # Debug rdb_partitions.c
#CFLAGS += -DDEBUG_BOOTMENU # Debug bootmenu.c
#CFLAGS += -DNO_SERIAL_OUTPUT # Turn off serial debugging for the whole driver
#CFLAGS += -DNO_SERIAL_OUTPUT # Turn off serial debugging for the whole driver
CFLAGS += -DENABLE_SEEK # Not needed for modern drives (~500 bytes)
#CFLAGS += -mhard-float

40
a4091.c
View File

@ -1417,7 +1417,7 @@ dma_mem_to_mem_quad(volatile APTR src, volatile APTR dst, uint32_t len,
static void
show_dip(uint8_t switches, int bit)
{
printf(" SW %d %s ", bit + 1, (switches & BIT(7)) ? "Off" : "On");
printf(" SW %d %-3s ", bit + 1, (switches & BIT(bit)) ? "Off" : "On");
}
static int
@ -2222,8 +2222,8 @@ test_scsi_pins(void)
sbcl |= 0x20; // Not sure why, but STRCL_BSY might still be high
if ((sbcl == 0xff) && (sbdl == 0xff)) {
if (rc++ == 0)
printf("\n");
printf("All SCSI pins low (check term power D309A and F309A/F309B)\n");
printf("FAIL\n");
printf("\tAll SCSI pins low: check term power D309A and F309A/F309B\n");
return (rc);
}
@ -2231,8 +2231,8 @@ test_scsi_pins(void)
sstat1 = get_ncrreg8(REG_SSTAT1);
if (sstat1 & REG_SSTAT1_RST) {
if (rc++ == 0)
printf("\n");
printf("SCSI bus is in reset (check for SCTRL_RST short to GND)\n");
printf("FAIL\n");
printf("\tSCSI bus is in reset: check for SCTRL_RST short to GND\n");
return (rc);
}
@ -2242,12 +2242,22 @@ test_scsi_pins(void)
sstat1 = get_ncrreg8(REG_SSTAT1);
if ((sstat1 & REG_SSTAT1_RST) == 0) {
if (rc++ == 0)
printf("\n");
printf("SCSI bus cannot be reset (check for SCTRL_RST short to VCC)\n");
printf("FAIL\n");
printf("\tSCSI bus could not be reset: "
"check for SCTRL_RST short to VCC\n");
}
set_ncrreg8(REG_SCNTL1, 0);
Delay(1);
/* Check that bus is not stuck busy */
sbcl = get_ncrreg8(REG_SBCL);
if (sbcl & 0x20) {
if (rc++ == 0)
printf("FAIL\n");
printf("\tSCSI bus is stuck busy: check for SCTRL_BSY short to GND\n");
}
/* Set registers to manually drive SCSI data and control pins */
set_ncrreg8(REG_DCNTL, dcntl | REG_DCNTL_LLM);
set_ncrreg8(REG_CTEST4, ctest4 | REG_CTEST4_SLBE);
@ -2289,12 +2299,12 @@ test_scsi_pins(void)
if (diff != 0) {
pins_diff |= diff;
if (rc++ == 0)
printf("\n");
printf("FAIL\n");
if (rc <= 8) {
printf("SCSI data %03x != expected %03x (diff %03x",
printf("\tSCSI data %03x != expected %03x [diff %03x]",
din, dout, diff);
print_bits(scsi_data_pins, diff);
printf(")\n");
printf("\n");
}
}
}
@ -2302,17 +2312,17 @@ test_scsi_pins(void)
/* Note: Register state is inverted from SCSI pin state */
pins_diff &= ~(stuck_high | stuck_low);
if (stuck_high != 0) {
printf("Stuck low: %02x", stuck_high);
printf("Stuck low [%02x]", stuck_high);
print_bits(scsi_data_pins, stuck_high);
printf(" (check for short to GND)\n");
printf(": check for short to GND\n");
}
if (stuck_low != 0) {
printf("Stuck high: %02x", stuck_low);
printf("Stuck high [%02x]", stuck_low);
print_bits(scsi_data_pins, stuck_low);
printf(" (check for short to VCC)\n");
printf(": check for short to VCC\n");
}
if (pins_diff != 0) {
printf("Floating or bridged: %02x", pins_diff);
printf("Floating or bridged [%02x]", pins_diff);
print_bits(scsi_data_pins, pins_diff);
printf("\n");
}

526
a4091d.c
View File

@ -47,19 +47,93 @@ typedef struct device *device_t;
#define BIT(x) (1 << (x))
extern a4091_save_t *asave;
extern BOOL __check_abort_enabled; // 0 = Disable gcc clib2 ^C break handling
a4091_save_t *asave;
static int global_opened = 0;
struct IOExtTD *global_tio;
struct MsgPort *global_mp;
#define DEVICE_NAME "a4091.device"
static void
close_exit(void)
{
if (global_opened) {
global_opened = 0;
printf("^C abort\n");
CloseDevice((struct IORequest *) global_tio);
DeleteExtIO((struct IORequest *) global_tio);
DeletePort(global_mp);
}
exit(1);
}
static BOOL
is_user_abort(void)
{
if (SetSignal(0, 0) & SIGBREAKF_CTRL_C)
return (1);
return (0);
}
static void
usage(void)
{
printf("This tool is used to show " DEVICE_NAME " driver internal state.\n"
"It does not work on any other driver.\n"
"Usage: a4091d [<unit>]\n"
" a4091d -p <periph address>\n"
" a4091d -x <xs address>\n");
}
typedef const char * const bitdesc_t;
static bitdesc_t bits_periph_flags[] = {
"REMOVABLE", "MEDIA_LOADED", "WAITING", "OPEN",
"WAITDRAIN", "GROW_OPENINGS", "MODE_VALID", "RECOVERING",
"RECOVERING_ACTIVE", "KEEP_LABEL", "SENSE", "UNTAG",
};
static bitdesc_t bits_periph_cap[] = {
"ANEC", "TERMIOP", "RELADR", "WIDE32",
"WIDE16", "Bit5", "Bit6", "SYNC",
"LINKCMDS", "TQING", "SFTRESET", "CMD16",
"DT", "QAS", "IUS", "Bit15",
};
static bitdesc_t bits_xs_control[] = {
"NOSLEEP", "POLL", "DISCOVERY", "ASYNC",
"USERCMD", "SILENT", "IGNORE_NOT_READY", "IGNORE_MEDIA_CHANGE",
"IGNORE_ILLEGAL_REQUEST", "SILENT_NODEV", "RESET", "DATA_UIO",
"DATA_IN", "DATA_OUT", "TARGET", "ESCAPE",
"URGENT", "SIMPLE_TAG", "ORDERED_TAG", "HEAD_TAG",
"THAW_PERIPH", "FREEZE_PERIPH", "Bit22", "REQSENSE",
};
static bitdesc_t bits_chan_flags[] = {
"CHAN_OPENINGS", "CHAN_CANGROW", "CHAN_NOSETTLE", "CHAN_TACTIVE",
"CHAN_RESET_PEND",
};
static bitdesc_t bits_chan_tflags[] = {
"CHANT_SHUTDOWN", "CHANT_CALLBACK", "CHANT_KICK", "CHANT_GROWRES",
};
static void
print_bits(bitdesc_t *bits, uint nbits, uint value)
{
uint bit;
for (bit = 0; value != 0; value >>= 1, bit++) {
if (value & 1) {
if ((bit >= nbits) || (bits[bit] == NULL))
printf(" bit%d", bit);
else
printf(" %s", bits[bit]);
}
}
}
static const char *
iocmd_name(uint cmd)
{
@ -167,6 +241,8 @@ struct ioerr {
{ 33, "TDERR_BadDriveType" },
{ 34, "TDERR_DriveInUse" },
{ 35, "TDERR_PostReset" },
{ 36, "CDERR_BadDataType" }, // data on disk is wrong type
{ 37, "CDERR_InvalidState" }, // invalid cmd under current conditions
{ 40, "HFERR_SelfUnit" },
{ 41, "HFERR_DMA" },
{ 42, "HFERR_Phase" },
@ -174,8 +250,12 @@ struct ioerr {
{ 44, "HFERR_SelTimeout" },
{ 45, "HFERR_BadStatus" },
{ 46, "ERROR_INQUIRY_FAILED" },
{ 47, "ERROR_TIMEOUT" },
{ 48, "ERROR_BUS_RESET" },
{ 49, "ERROR_TRY_AGAIN" },
{ 56, "HFERR_NoBoard" },
{ 51, "ERROR_BAD_BOARD" },
{ 52, "ERROR_SENSE_CODE" },
};
static void
@ -400,23 +480,25 @@ decode_scsi_sense_key(int key)
return ("UNKNOWN");
}
#define SCSI_COND_MET 0x04
#define SCSI_TASK_ABORTED 0x40
#define SCSI_COND_MET 0x04
#define SCSI_INTERM_CNDMET 0x14
#define SCSI_TASK_ABORTED 0x40
static const char *
decode_xs_status(int status)
{
switch (status) {
case SCSI_OK: return ("OK"); // 0x00
case SCSI_CHECK: return ("CHECK"); // 0x02
case SCSI_COND_MET: return ("COND_MET"); // 0x04
case SCSI_BUSY: return ("BUSY"); // 0x08
case SCSI_INTERM: return ("INTERM"); // 0x10
case SCSI_RESV_CONFLICT: return ("RESV_CONFLICT"); // 0x18
case SCSI_TERMINATED: return ("TERMINATED"); // 0x22
case SCSI_QUEUE_FULL: return ("QUEUE_FULL"); // 0x28
case SCSI_ACA_ACTIVE: return ("ACA_ACTIVE"); // 0x30
case SCSI_TASK_ABORTED: return ("TASK_ABORTED"); // 0x40
case SCSI_OK: return ("OK"); // 0x00
case SCSI_CHECK: return ("CHECK"); // 0x02
case SCSI_COND_MET: return ("COND_MET"); // 0x04
case SCSI_BUSY: return ("BUSY"); // 0x08
case SCSI_INTERM: return ("INTERMEDIATE"); // 0x10
case SCSI_INTERM_CNDMET: return ("INTERM_COND_MET"); // 0x14
case SCSI_RESV_CONFLICT: return ("RESV_CONFLICT"); // 0x18
case SCSI_TERMINATED: return ("TERMINATED"); // 0x22
case SCSI_QUEUE_FULL: return ("QUEUE_FULL"); // 0x28
case SCSI_ACA_ACTIVE: return ("ACA_ACTIVE"); // 0x30
case SCSI_TASK_ABORTED: return ("TASK_ABORTED"); // 0x40
default: return ("UNKNOWN");
}
}
@ -1267,9 +1349,18 @@ print_xs(struct scsipi_xfer *xs, int indent_count)
printf("%s io_Length=%08x\n", indent, (uint) ior->io_Length);
printf("%s io_Data=%p\n", indent, ior->io_Data);
}
printf("%sxs_control=%d\n", indent, xs->xs_control);
printf("%sxs_status=%d\n", indent, xs->xs_status);
printf("%sxs_periph=%p\n", indent, xs->xs_periph);
printf("%sxs_control=%08x ", indent, xs->xs_control);
print_bits(bits_xs_control, ARRAY_SIZE(bits_xs_control),
xs->xs_control);
printf("\n");
printf("%sxs_status=%d %s\n", indent, xs->xs_status,
(xs->xs_status & XS_STS_DONE) ? "STS_DONE" : "");
printf("%sxs_periph=%p", indent, xs->xs_periph);
if (xs->xs_periph != NULL) {
printf(" %d.%d",
xs->xs_periph->periph_target, xs->xs_periph->periph_lun);
}
printf("\n");
printf("%sxs_retries=%d\n", indent, xs->xs_retries);
printf("%sxs_requeuecnt=%d\n", indent, xs->xs_requeuecnt);
printf("%stimeout=%d\n", indent, xs->timeout);
@ -1305,9 +1396,11 @@ decode_acb(struct siop_acb *acb)
if (acb->xs->xs_periph == NULL) {
printf(" %p <NO PERIPH>", acb->xs);
} else {
printf(" %p %d.%d", acb->xs,
acb->xs->xs_periph->periph_target,
acb->xs->xs_periph->periph_lun);
struct scsipi_xfer *xs = acb->xs;
printf(" %p %d.%d", xs,
xs->xs_periph->periph_target, xs->xs_periph->periph_lun);
if (xs->xs_callout.func != NULL)
printf(" [%d ticks]", xs->xs_callout.ticks);
}
}
printf(" flags=%x len=%02d", acb->flags, acb->clen);
@ -1344,26 +1437,77 @@ show_sc_list(int indent_count, struct siop_acb *acb)
printf("\n");
}
typedef const char * const bitdesc_t;
static const char * const scsi_periph_type_name[] = {
"T_DIRECT - direct access device", // 0x00
"T_SEQUENTIAL - sequential access device", // 0x01
"T_PRINTER - printer device", // 0x02
"T_PROCESSOR - processor device", // 0x03
"T_WORM - write once, read many device", // 0x04
"T_CDROM - cd-rom device", // 0x05
"T_SCANNER - scanner device", // 0x06
"T_OPTICAL - optical memory device", // 0x07
"T_CHANGER - medium changer device", // 0x08
"T_COMM - communication device", // 0x09
"T_IT8_1 - Defined by ASC IT8", // 0x0a
"T_IT8_2 - Graphic arts pre-press device", // 0x0b
"T_STORARRAY - storage array device", // 0x0c
"T_ENCLOSURE - enclosure services device", // 0x0d
"T_SIMPLE_DIRECT - Simplified direct-access device", // 0x0e
"T_OPTIC_CARD_RW - Optical card reader/writer device", // 0x0f
"", // 0x10
"T_OBJECT_STORED - Object-based Storage Device", // 0x11
"T_AUTOMATION_DRIVE - Automation drive interface", // 0x12
"", // 0x13
"", // 0x13
"", // 0x14
"", // 0x15
"", // 0x16
"", // 0x17
"", // 0x18
"", // 0x19
"", // 0x1a
"", // 0x1b
"", // 0x1c
"", // 0x1d
"T_WELL_KNOWN_LUN - Well known logical unit", // 0x1e
"T_NODEVICE - Unknown or no device type", // 0x1f
};
static bitdesc_t bits_periph_flags[] = {
"REMOVABLE", "MEDIA_LOADED", "WAITING", "OPEN",
"WAITDRAIN", "GROW_OPENINGS", "MODE_VALID", "RECOVERING",
"RECOVERING_ACTIVE", "KEEP_LABEL", "SENSE", "UNTAG",
static const char * const interrupt_type_name[] = {
"NT_UNKNOWN", // 0
"NT_TASK", // 1
"NT_INTERRUPT", // 2
"NT_DEVICE", // 3
"NT_MSGPORT", // 4
"NT_MESSAGE", // 5
"NT_FREEMSG", // 6
"NT_REPLYMSG", // 7
"NT_RESOURCE", // 8
"NT_LIBRARY", // 9
"NT_MEMORY", // 10
"NT_SOFTINT", // 11
"NT_FONT", // 12
"NT_PROCESS", // 13
"NT_SEMAPHORE", // 14
"NT_SIGNALSEM", // 15
"NT_BOOTNODE", // 16
"NT_KICKMEM", // 17
"NT_GRAPHICS", // 18
"NT_DEATHMESSAGE", // 19
};
static void
print_bits(bitdesc_t *bits, uint nbits, uint value)
show_interrupt(int indent, struct Interrupt *interrupt)
{
uint bit;
for (bit = 0; value != 0; value >>= 1, bit++) {
if (value & 1) {
if ((bit >= nbits) || (bits[bit] == NULL))
printf(" bit%d", bit);
else
printf(" %s", bits[bit]);
}
}
printf("%*sis_Node.ln_Type=%x %s\n",
indent, "", interrupt->is_Node.ln_Type,
interrupt->is_Node.ln_Type < ARRAY_SIZE(interrupt_type_name) ?
interrupt_type_name[interrupt->is_Node.ln_Type] : "");
printf("%*sis_Node.ln_Pri=%d\n", indent, "", interrupt->is_Node.ln_Pri);
printf("%*sis_Node.ln_Name=%p '%s'\n", indent, "",
interrupt->is_Node.ln_Name, interrupt->is_Node.ln_Name);
printf("%*sis_Code %p(%p)\n",
indent, "", interrupt->is_Code, interrupt->is_Data);
}
static void
@ -1375,6 +1519,110 @@ show_sc_tinfo(int indent_count, struct siop_tinfo *st)
st->lubusy, st->flags, st->period, st->offset);
}
static void
show_periph(struct scsipi_periph *periph)
{
int count = 0;
printf("Periph=%p\n", periph);
printf(" drv_state=%p\n", periph->drv_state);
printf(" periph_channel=%p\n", periph->periph_channel);
printf(" periph_changeintlist=");
struct IOStdReq *io;
for (io = (struct IOStdReq *)periph->periph_changeintlist.mlh_Head;
io->io_Message.mn_Node.ln_Succ != NULL;
io = (struct IOStdReq *)io->io_Message.mn_Node.ln_Succ) {
if (count++ == 0)
printf("\n");
printf(" ioRequest=%p\n", io);
printf(" io_Message=%p\n", &io->io_Message);
printf(" io_Device=%p\n", io->io_Device);
printf(" io_Unit=%p\n", io->io_Unit);
printf(" io_Command=%04x %s\n",
io->io_Command, iocmd_name(io->io_Command));
decode_io_command(8, (struct IOStdReq *) io);
printf(" io_Flags=%02x\n", io->io_Flags);
printf(" io_Error=%02x\n", io->io_Error);
printf(" io_Data=%p\n", io->io_Data);
if (io->io_Data != NULL) {
show_interrupt(8, io->io_Data);
}
}
if (count == 0)
printf("NONE\n");
printf(" periph_changeint=%p\n", periph->periph_changeint);
if (periph->periph_changeint != NULL)
show_interrupt(4, periph->periph_changeint);
printf(" periph_openings=%d\n", periph->periph_openings);
printf(" periph_sent=%d\n", periph->periph_sent);
printf(" periph_mode=%x\n", periph->periph_mode);
printf(" periph_period=%d\n", periph->periph_period);
printf(" periph_offset=%d\n", periph->periph_offset);
printf(" periph_type=%u %s\n", periph->periph_type,
periph->periph_type < ARRAY_SIZE(scsi_periph_type_name) ?
scsi_periph_type_name[periph->periph_type] : "");
printf(" periph_cap=0x%x ", periph->periph_cap);
print_bits(bits_periph_cap, ARRAY_SIZE(bits_periph_cap),
periph->periph_cap);
printf("\n");
printf(" periph_quirks=%x\n", periph->periph_quirks);
printf(" periph_flags=%x ", periph->periph_flags);
print_bits(bits_periph_flags, ARRAY_SIZE(bits_periph_flags),
periph->periph_flags);
printf("\n");
printf(" periph_dbflags=%x\n", periph->periph_dbflags);
printf(" periph_target=%d\n", periph->periph_target);
printf(" periph_lun=%d\n", periph->periph_lun);
printf(" periph_blkshift=%d (%u bytes)\n", periph->periph_blkshift,
1U << periph->periph_blkshift);
printf(" periph_changenum=%d\n", periph->periph_changenum);
printf(" periph_tur_active=%d\n", periph->periph_tur_active);
printf(" periph_version=%d\n", periph->periph_version);
// printf(" periph_freetags[]=\n", periph->periph_freetags[i]);
// printf(" periph_xferq=%p%s\n", xq, (xs == NULL) ? " EMPTY" : "");
#if 0
struct scsipi_channel *chan = periph->periph_channel;
struct scsipi_xfer_queue *xq;
/*
* periph_xferq is not being tracked in AmigaOS driver,
* so it is simulated here using the channel xferq.
*/
Forbid();
xq = &chan->chan_queue;
xs = TAILQ_FIRST(xq);
while ((xs != NULL) && (xs->xs_periph != periph)) {
/* Channel queue might have other XS than just this periph */
xs = TAILQ_NEXT(xs, channel_q);
}
printf(" periph_xferq=%p%s\n", xq, (xs == NULL) ? " EMPTY" : "");
while (xs != NULL) {
printf(" xs=%p\n", xs);
print_xs(xs, 6);
xs = TAILQ_NEXT(xs, channel_q);
while ((xs != NULL) && (xs->xs_periph != periph)) {
/* Channel queue might have other XS than just this periph */
xs = TAILQ_NEXT(xs, channel_q);
}
}
Permit();
#endif
if (periph->periph_callout.func == NULL) {
printf(" periph_callout NONE\n");
} else {
printf(" periph_callout ticks=%d\n", periph->periph_callout.ticks);
printf(" func=%p(%p)\n",
periph->periph_callout.func, periph->periph_callout.arg);
}
printf(" periph_xscheck=%p\n", periph->periph_xscheck);
Forbid();
if (periph->periph_xscheck != NULL)
print_xs(periph->periph_xscheck, 6);
Permit();
}
int
main(int argc, char *argv[])
{
@ -1382,10 +1630,12 @@ main(int argc, char *argv[])
int arg;
int pos = 0;
int rc = 0;
int open_and_wait = 0;
struct IOExtTD *tio;
struct MsgPort *mp;
struct IOStdReq *ior;
struct scsipi_xfer *xs = NULL;
struct scsipi_xfer *xs;
struct scsipi_periph *periph;
char *devname = DEVICE_NAME;
for (arg = 1; arg < argc; arg++) {
@ -1393,15 +1643,33 @@ main(int argc, char *argv[])
if (*ptr == '-') {
while (*(++ptr) != '\0') {
switch (*ptr) {
case 'p': {
if (++arg > argc) {
printf("-%c requires an argument\n", *ptr);
exit(1);
}
if ((sscanf(argv[arg], "%x%n",
(uint *) &periph, &pos) != 1) ||
(argv[arg][pos] != '\0')) {
printf("Invalid periph address '%s'\n", argv[arg]);
}
show_periph(periph);
exit(0);
}
case 'x':
if (++arg > argc) {
printf("-%c requires an argument\n", *ptr);
exit(1);
}
if ((sscanf(argv[arg], "%x%n", (uint *) &xs, &pos) != 1) ||
if ((sscanf(argv[arg], "%x%n",
(uint *) &xs, &pos) != 1) ||
(argv[arg][pos] != '\0')) {
printf("Invalid xs address '%s'\n", argv[arg]);
}
print_xs(xs, 1);
exit(0);
case 'w':
open_and_wait++;
break;
default:
printf("Invalid argument -%s\n", ptr);
@ -1419,16 +1687,13 @@ main(int argc, char *argv[])
}
}
if (xs != NULL) {
print_xs(xs, 1);
exit(0);
}
if (unitno == -1) {
usage();
exit(1);
}
__check_abort_enabled = 0; // Disable gcc clib2 ^C break handling
mp = CreatePort(NULL, 0);
if (mp == NULL) {
printf("Failed to create message port\n");
@ -1442,11 +1707,25 @@ main(int argc, char *argv[])
goto extio_fail;
}
if (OpenDevice(devname, unitno, (struct IORequest *) tio, 0)) {
printf("Open %s failed\n", devname);
rc = 1;
goto open_fail;
if (OpenDevice(devname, unitno, (struct IORequest *) tio, TDF_DEBUG_OPEN)) {
printf("Unit %d is not currently open; attemping a normal open.\n",
unitno);
if (OpenDevice(devname, unitno, (struct IORequest *) tio, 0)) {
printf("Open %s failed\n", devname);
rc = 1;
goto open_fail;
}
}
global_opened = 1;
global_mp = mp;
global_tio = tio;
if (open_and_wait) {
int i;
printf("Device open; press enter to proceed.\n");
scanf("%d", &i);
}
ior = &tio->iotd_Req;
struct MsgPort *rp = ior->io_Message.mn_ReplyPort;
struct Library *dp = &ior->io_Device->dd_Library;
@ -1472,6 +1751,8 @@ main(int argc, char *argv[])
dp->lib_IdString, (char *)dp->lib_IdString);
printf(" lib_Sum=%08x\n", (unsigned int) dp->lib_Sum);
printf(" lib_OpenCnt=%04x\n", dp->lib_OpenCnt);
if (is_user_abort())
close_exit();
struct Unit *u = ior->io_Unit;
printf(" io_Unit=%p\n", u);
@ -1496,68 +1777,16 @@ main(int argc, char *argv[])
printf(" iotd_Count=%08x\n", ior->io_Error);
printf(" iotd_SecLabel=%08x\n", ior->io_Error);
struct scsipi_periph *periph = (void *) u;
printf("Periph=%p\n", periph);
printf(" drv_state=%p\n", periph->drv_state);
printf(" periph_channel=%p\n", periph->periph_channel);
printf(" periph_openings=%d\n", periph->periph_openings);
printf(" periph_sent=%d\n", periph->periph_sent);
printf(" periph_mode=%x\n", periph->periph_mode);
printf(" periph_period=%d\n", periph->periph_period);
printf(" periph_offset=%d\n", periph->periph_offset);
printf(" periph_type=%u\n", periph->periph_type);
printf(" periph_cap=0x%x\n", periph->periph_cap);
printf(" periph_quirks=%x\n", periph->periph_quirks);
printf(" periph_flags=%x", periph->periph_flags);
print_bits(bits_periph_flags, ARRAY_SIZE(bits_periph_flags),
periph->periph_flags);
printf("\n");
printf(" periph_dbflags=%x\n", periph->periph_dbflags);
printf(" periph_target=%d\n", periph->periph_target);
printf(" periph_lun=%d\n", periph->periph_lun);
printf(" periph_blkshift=%d\n", periph->periph_blkshift);
printf(" periph_version=%d\n", periph->periph_version);
// printf(" periph_freetags[]=\n", periph->periph_freetags[i]);
// printf(" periph_xferq=%p%s\n", xq, (xs == NULL) ? " EMPTY" : "");
if (is_user_abort())
close_exit();
/*
* periph_xferq is not being tracked in AmigaOS driver,
* so it is simulated here using the channel xferq.
*/
Forbid();
periph = (void *) u;
struct scsipi_channel *chan = periph->periph_channel;
struct scsipi_xfer_queue *xq;
xq = &chan->chan_queue;
xs = TAILQ_FIRST(xq);
while ((xs != NULL) && (xs->xs_periph != periph)) {
/* Channel queue might have other XS than just this periph */
xs = TAILQ_NEXT(xs, channel_q);
}
printf(" periph_xferq=%p%s\n", xq, (xs == NULL) ? " EMPTY" : "");
while (xs != NULL) {
printf(" xs=%p\n", xs);
xs = TAILQ_NEXT(xs, channel_q);
while ((xs != NULL) && (xs->xs_periph != periph)) {
/* Channel queue might have other XS than just this periph */
xs = TAILQ_NEXT(xs, channel_q);
}
if (xs != NULL)
print_xs(xs, 6);
}
Permit();
show_periph(periph);
if (is_user_abort())
close_exit();
if (periph->periph_callout.func == NULL) {
printf(" periph_callout NONE\n");
} else {
printf(" periph_callout ticks=%d\n", periph->periph_callout.ticks);
printf(" func=%p(%p)\n",
periph->periph_callout.func, periph->periph_callout.arg);
}
printf(" periph_xscheck=%p\n", periph->periph_xscheck);
Forbid();
if (periph->periph_xscheck != NULL)
print_xs(periph->periph_xscheck, 6);
Permit();
printf("Chan %p\n", chan);
Forbid();
xs = chan->chan_xs_free;
@ -1578,6 +1807,10 @@ main(int argc, char *argv[])
print_xs(xs, 6);
}
Permit();
if (is_user_abort())
close_exit();
printf(" chan_active=%d\n", chan->chan_active);
struct scsipi_adapter *adapt = chan->chan_adapter;
printf(" chan_adapter=%p\n", adapt);
@ -1585,27 +1818,54 @@ main(int argc, char *argv[])
printf(" adapt_nchannels=%d\n", adapt->adapt_nchannels);
printf(" adapt_refcnt=%d\n", adapt->adapt_refcnt);
printf(" adapt_openings=%d\n", adapt->adapt_openings);
printf(" adapt_max_periph=%d\n", adapt->adapt_max_periph);
// printf(" adapt_max_periph=%d\n", adapt->adapt_max_periph);
printf(" adapt_flags=%d\n", adapt->adapt_flags);
printf(" adapt_runnings=%d\n", adapt->adapt_running);
printf(" adapt_asave=%p\n", adapt->adapt_asave);
printf(" chan_periphtab[]=%p\n", chan->chan_periphtab);
printf(" chan_flags=%d\n", chan->chan_flags);
for (int i = 0; i < SCSIPI_CHAN_PERIPH_BUCKETS; i++) {
LIST_FOREACH(periph, &chan->chan_periphtab[i], periph_hash) {
printf(" periph=%p %d.%d\n", periph,
periph->periph_target, periph->periph_lun);
}
}
printf(" chan_flags=%02x", chan->chan_flags);
print_bits(bits_chan_flags, ARRAY_SIZE(bits_chan_flags), chan->chan_flags);
printf("\n");
printf(" chan_openings=%d\n", chan->chan_openings);
printf(" chan_nluns=%d\n", chan->chan_nluns);
printf(" chan_id=%d (SCSI host ID)\n", chan->chan_id);
printf(" chan_tflags=%d\n", chan->chan_tflags);
printf(" chan_tflags=%d", chan->chan_tflags);
print_bits(bits_chan_tflags, ARRAY_SIZE(bits_chan_tflags),
chan->chan_tflags);
printf("\n");
if (is_user_abort())
close_exit();
Forbid();
xq = &chan->chan_queue;
struct scsipi_xfer_queue *xq = &chan->chan_queue;
xs = TAILQ_FIRST(xq);
printf(" chan_queue=%p%s\n", xq, (xs == NULL) ? " EMPTY" : "");
while (xs != NULL) {
printf(" xs=%p\n", xs);
printf(" xs=%p", xs);
if (xs->xs_periph != NULL) {
struct scsipi_periph *tperiph = xs->xs_periph;
printf(" periph %d.%d",
tperiph->periph_target, tperiph->periph_lun);
if (tperiph == periph)
printf(" (THIS)");
}
printf("\n");
print_xs(xs, 6);
xs = TAILQ_NEXT(xs, channel_q);
}
Permit();
if (is_user_abort())
close_exit();
Forbid();
xq = &chan->chan_complete;
xs = TAILQ_FIRST(xq);
@ -1620,42 +1880,49 @@ main(int argc, char *argv[])
if (asave != NULL) {
printf("Driver globals %p\n", asave);
printf(" as_SysBase=%p\n", asave->as_SysBase);
printf(" as_irq_count=%x\n", asave->as_irq_count);
printf(" as_svc_task=%p\n", asave->as_svc_task);
struct Interrupt *isr = asave->as_isr;
printf(" as_isr=%p is_Code=%p(%p)\n",
asave->as_isr, isr->is_Code, isr->is_Data);
printf(" is_Node.ln_Type=%x\n", isr->is_Node.ln_Type);
printf(" is_Node.ln_Pri=%x\n", isr->is_Node.ln_Pri);
printf(" is_Node.ln_Name=%p %.30s\n",
isr->is_Node.ln_Name, isr->is_Node.ln_Name);
printf(" as_timer_running=%x\n", asave->as_timer_running);
printf(" as_irq_signal=%x\n", asave->as_irq_signal);
printf(" as_irq_count=%x\n", asave->as_irq_count);
printf(" as_int_mask=%08x\n", asave->as_int_mask);
printf(" as_timer_mask=%08x\n", asave->as_timer_mask);
printf(" as_svc_task=%p\n", asave->as_svc_task);
printf(" as_isr=%p\n", asave->as_isr);
show_interrupt(4, asave->as_isr);
printf(" as_exiting=%x\n", asave->as_exiting);
printf(" as_device_self=%p\n", &asave->as_device_self);
printf(" as_device_private=%p\n", asave->as_device_private);
struct siop_softc *sc = asave->as_device_private;
printf(" sc_siop_si=%p\n", sc->sc_siop_si);
// printf(" sc_siop_si=%p\n", sc->sc_siop_si);
printf(" sc_istat=%u sc_dstate=%u sc_sstat0=%u sc_sstat1=%u\n",
sc->sc_istat, sc->sc_dstat, sc->sc_sstat0, sc->sc_sstat1);
printf(" sc_intcode=%lu\n", sc->sc_intcode);
printf(" sc_intcode=%04lx\n", sc->sc_intcode);
printf(" sc_adapter=%p\n", &sc->sc_adapter);
printf(" sc_channel=%p\n", &sc->sc_channel);
printf(" sc_scriptspa=%lx\n", sc->sc_scriptspa);
printf(" sc_siopp=%p\n", sc->sc_siopp);
printf(" sc_active=%lu sc_nosync=%lu\n",
sc->sc_active, sc->sc_nosync);
printf(" sc_active=%lu\n", sc->sc_active);
Forbid();
printf(" free_list=");
show_sc_list(6, sc->free_list.tqh_first);
printf(" ready_list=");
printf(" ready_list="); // Queue of xs to be issued
show_sc_list(6, sc->ready_list.tqh_first);
printf(" nexus_list=");
printf(" nexus_list="); // List of xs already issued on channel
show_sc_list(6, sc->nexus_list.tqh_first);
printf(" sc_nexus=%p", sc->sc_nexus);
Permit();
if (is_user_abort())
close_exit();
Forbid();
printf(" sc_nexus=%p", sc->sc_nexus); // Current active xs
decode_acb(sc->sc_nexus);
if ((sc->sc_active != 0) && (sc->sc_nexus->xs != NULL)) {
if ((sc->sc_active != 0) &&
(sc->sc_nexus != NULL) && (sc->sc_nexus->xs != NULL)) {
/* Do full decode of ACB */
print_xs(sc->sc_nexus->xs, 6);
}
Permit();
printf(" sc_acb[0]=%p\n", sc->sc_acb);
for (pos = 0; pos < ARRAY_SIZE(sc->sc_tinfo); pos++) {
printf(" sc_tinfo[%d] ", pos);
@ -1669,17 +1936,21 @@ main(int argc, char *argv[])
printf(" sc_flags=%02x sc_dien=%02x sc_minsync=%02x "
"sc_sien=%02x\n",
sc->sc_flags, sc->sc_dien, sc->sc_minsync, sc->sc_sien);
printf(" sc_nosync=%x sc_nodisconnect=%x\n",
sc->sc_nosync, sc->sc_nodisconnect);
for (pos = 0; pos < ARRAY_SIZE(sc->sc_sync); pos++) {
printf(" sc_sync[%d] state=%u sxfer=%u sbcl=%u\n",
pos, sc->sc_sync[pos].state, sc->sc_sync[pos].sxfer,
sc->sc_sync[pos].sbcl);
}
if (is_user_abort())
close_exit();
printf(" as_timerport[0]=%p as_timerport[1]=%p\n",
asave->as_timerport[0], asave->as_timerport[1]);
printf(" as_timerio[0]=%p as_timerio[1]=%p\n",
asave->as_timerio[0], asave->as_timerio[1]);
printf(" as_timer_running=%x\n", asave->as_timer_running);
callout_t *callout_head = *(asave->as_callout_head);
callout_t *cur;
printf(" as_callout_head=%p\n", callout_head);
@ -1696,5 +1967,6 @@ open_fail:
extio_fail:
DeletePort(mp);
global_opened = 0;
exit(rc);
}

View File

@ -120,7 +120,7 @@ device_private(device_t dev)
/* CDH: HACK */
static int
a4091_add_local_irq_handler(uint32_t dev_base)
a4091_add_local_irq_handler(void)
{
struct Task *task = FindTask(NULL);
if (task == NULL)
@ -359,7 +359,6 @@ init_chan(device_t self, UBYTE *boardnum)
adapt->adapt_dev = self;
adapt->adapt_nchannels = 1;
adapt->adapt_openings = 7;
adapt->adapt_max_periph = 1;
adapt->adapt_request = siop_scsipi_request;
adapt->adapt_asave = asave;
@ -379,6 +378,7 @@ init_chan(device_t self, UBYTE *boardnum)
/* Need to disable synchronous SCSI */
sc->sc_nosync = ~0;
}
sc->sc_nodisconnect = 0; /* Mask of targets not allowed to disconnect */
/*
* A4091 Rear-access DIP switches
@ -394,7 +394,7 @@ init_chan(device_t self, UBYTE *boardnum)
scsipi_channel_init(chan);
rc = a4091_add_local_irq_handler(dev_base);
rc = a4091_add_local_irq_handler();
if (rc != 0)
return (rc);
@ -424,14 +424,16 @@ scsipi_alloc_periph(int flags)
if (periph == NULL)
return (NULL);
#if 0
/*
* Start with one command opening. The periph driver
* will grow this if it knows it can take advantage of it.
*/
periph->periph_openings = 1;
#endif
for (i = 0; i < PERIPH_NTAGWORDS; i++)
periph->periph_freetags[i] = 0xffffffff;
periph->periph_freetags[i] = 0xffffffff;
#if 0
/* Not tracked for AmigaOS */
@ -449,7 +451,8 @@ scsipi_free_periph(struct scsipi_periph *periph)
int scsi_probe_device(struct scsipi_channel *chan, int target, int lun, struct scsipi_periph *periph, int *failed);
int
attach(device_t self, uint scsi_target, struct scsipi_periph **periph_p)
attach(device_t self, uint scsi_target, struct scsipi_periph **periph_p,
uint flags)
{
struct siop_softc *sc = device_private(self);
struct scsipi_channel *chan = &sc->sc_channel;
@ -459,7 +462,7 @@ attach(device_t self, uint scsi_target, struct scsipi_periph **periph_p)
int rc;
int failed = 0;
if ((scsi_target % 10) == chan->chan_id)
if (target == chan->chan_id)
return (ERROR_SELF_UNIT);
periph = scsipi_alloc_periph(0);
@ -474,6 +477,8 @@ attach(device_t self, uint scsi_target, struct scsipi_periph **periph_p)
periph->periph_dbflags = 0;
periph->periph_changenum = 1;
periph->periph_channel = chan;
periph->periph_changeint = NULL;
NewMinList(&periph->periph_changeintlist);
rc = scsi_probe_device(chan, target, lun, periph, &failed);
printf("scsi_probe_device(%d.%d) cont=%d failed=%d\n",
@ -495,11 +500,35 @@ attach(device_t self, uint scsi_target, struct scsipi_periph **periph_p)
void
detach(struct scsipi_periph *periph)
{
printf("detach(%p)\n", periph);
printf("detach(%p, %d)\n",
periph, periph->periph_target + periph->periph_lun * 10);
if (periph != NULL) {
int timeout = 6; // Seconds
struct scsipi_channel *chan = periph->periph_channel;
while (periph->periph_sent > 0) {
/* Need to wait for outstanding commands to complete */
timeout -= irq_and_timer_handler();
if (timeout == 0) {
printf("Detach timeout waiting for periph to quiesce\n");
return;
}
}
scsipi_remove_periph(chan, periph);
scsipi_free_periph(periph);
}
}
int
periph_still_attached(void)
{
uint i;
struct siop_softc *sc = asave->as_device_private;
struct scsipi_channel *chan = &sc->sc_channel;
for (i = 0; i < SCSIPI_CHAN_PERIPH_BUCKETS; i++)
if (LIST_FIRST(&chan->chan_periphtab[i]) != NULL) {
return (1);
}
return (0);
}

View File

@ -12,24 +12,28 @@ struct timerequest;
struct callout;
struct ConfigDev;
int attach(device_t self, uint scsi_target, struct scsipi_periph **periph);
int attach(device_t self, uint scsi_target, struct scsipi_periph **periph,
uint flags);
void detach(struct scsipi_periph *periph);
int periph_still_attached(void);
int init_chan(device_t self, UBYTE *boardnum);
void deinit_chan(device_t self);
typedef struct {
uint32_t as_addr;
struct ExecBase *as_SysBase;
int8_t as_timer_running;
uint8_t as_irq_signal;
uint32_t as_irq_count; // Total interrupts
uint32_t as_int_mask;
uint32_t as_timer_mask;
struct Task *as_svc_task;
struct Interrupt *as_isr; // My interrupt server
uint8_t as_irq_signal;
volatile uint8_t as_exiting;
struct device as_device_self;
struct siop_softc *as_device_private;
struct MsgPort *as_timerport[2];
struct timerequest *as_timerio[2];
int as_timer_running;
struct callout **as_callout_head;
struct ConfigDev *as_cd;
uint32_t romfile[2];

View File

@ -171,6 +171,68 @@ cmd_complete(void *ior, int8_t rc)
ReplyMsg(&ioreq->io_Message);
}
VOID
AddHeadMinList(struct MinList *list, struct MinNode *node)
{
struct MinNode *head;
head = list->mlh_Head;
list->mlh_Head = node;
node->mln_Succ = head;
node->mln_Pred = (struct MinNode *)list;
head->mln_Pred = node;
}
void
td_addchangeint(struct IORequest *ior)
{
struct scsipi_periph *periph = (struct scsipi_periph *)ior->io_Unit;
Forbid();
AddHeadMinList(&periph->periph_changeintlist,
(struct MinNode *) &ior->io_Message.mn_Node);
Permit();
ior->io_Error = 0; // Success
}
void
td_remchangeint(struct IORequest *ior)
{
struct IORequest *io;
struct scsipi_periph *periph = (struct scsipi_periph *)ior->io_Unit;
Forbid();
for (io = (struct IORequest *)periph->periph_changeintlist.mlh_Head;
io->io_Message.mn_Node.ln_Succ != NULL;
io = (struct IORequest *)io->io_Message.mn_Node.ln_Succ) {
if (io == ior) {
Remove(&io->io_Message.mn_Node);
io->io_Message.mn_Node.ln_Succ = NULL;
io->io_Message.mn_Node.ln_Pred = NULL;
ior->io_Error = 0;
break;
}
}
Permit();
if (io == NULL) {
ior->io_Error = IOERR_BADADDRESS;
} else {
ior->io_Error = 0; // Success
}
}
void
td_remove(struct IORequest *ior)
{
struct IOStdReq *io = (struct IOStdReq *) ior;
struct scsipi_periph *periph = (struct scsipi_periph *)io->io_Unit;
periph->periph_changeint = io->io_Data;
ior->io_Error = 0; // Success
}
static const UWORD nsd_supported_cmds[] = {
CMD_READ, CMD_WRITE, TD_SEEK, TD_FORMAT,
CMD_STOP, CMD_START,
@ -407,6 +469,7 @@ CMD_SEEK_continue:
((struct scsipi_periph *) ior->io_Unit)->periph_lun * 10 +
((struct scsipi_periph *) ior->io_Unit)->periph_target,
load ? "load" : eject ? "eject" : "invalid");
if (load || eject)
rc = sd_startstop(iotd->iotd_Req.io_Unit, ior, load, 1, immed);
else
@ -421,11 +484,13 @@ CMD_SEEK_continue:
case CMD_ATTACH: // Attach (open) a new SCSI device
PRINTF_CMD("CMD_ATTACH %"PRIu32"\n", iotd->iotd_Req.io_Offset);
rc = attach(&asave->as_device_self, iotd->iotd_Req.io_Offset,
(struct scsipi_periph **) &ior->io_Unit);
(struct scsipi_periph **) &ior->io_Unit,
iotd->iotd_Req.io_Length);
if (rc != 0) {
ior->io_Error = rc;
} else {
} else if ((iotd->iotd_Req.io_Length & TDF_DEBUG_OPEN) == 0) {
(void) sd_blocksize((struct scsipi_periph *) ior->io_Unit);
}
@ -455,6 +520,24 @@ CMD_SEEK_continue:
ReplyMsg(&ior->io_Message);
return (1);
case TD_ADDCHANGEINT: // TD_REMOVE done right
PRINTF_CMD("TD_ADDCHANGEINT\n");
td_addchangeint(ior);
/* Do not reply to this request */
break;
case TD_REMCHANGEINT: // Remove softint set by ADDCHANGEINT
PRINTF_CMD("TD_REMCHANGEINT\n");
td_remchangeint(ior);
ReplyMsg(&ior->io_Message);
break;
case TD_REMOVE: // Notify when media changes
PRINTF_CMD("TD_REMOVE\n");
td_remove(ior);
ReplyMsg(&ior->io_Message);
break;
case CMD_INVALID: // Invalid command (0)
case CMD_RESET: // Not supported by SCSI
case CMD_UPDATE: // Not supported by SCSI
@ -464,9 +547,6 @@ CMD_SEEK_continue:
case TD_RAWWRITE: // Not supported by SCSI (raw bits to disk)
case TD_GETDRIVETYPE: // Not supported by SCSI (floppy-only DRIVExxxx)
case TD_GETNUMTRACKS: // Not supported by SCSI (floppy-only)
case TD_REMOVE: // Notify when disk changes
case TD_ADDCHANGEINT: // TD_REMOVE done right
case TD_REMCHANGEINT: // Remove softint set by ADDCHANGEINT
default:
/* Unknown command */
printf("Unknown cmd %x\n", ior->io_Command);
@ -482,6 +562,40 @@ CMD_SEEK_continue:
void scsipi_completion_poll(struct scsipi_channel *chan);
/*
* irq_and_timer_handler()
* -----------------------
* This function may be called by code which only needs to run background
* processing of interrupts and timer events. The function will return
* after each service action, so should be called repeatedly until an
* external condition is met.
*/
int
irq_and_timer_handler(void)
{
struct siop_softc *sc = asave->as_device_private;
struct scsipi_channel *chan = &sc->sc_channel;
uint32_t int_mask = asave->as_int_mask;
uint32_t timer_mask = asave->as_timer_mask;
uint32_t mask;
mask = Wait(int_mask | timer_mask);
/* Handle incoming interrupts */
irq_poll(mask & int_mask, sc);
if (mask & timer_mask) {
WaitIO(&asave->as_timerio[0]->tr_node);
callout_run_timeouts();
sd_testunitready_walk(chan);
restart_timer();
}
/* Process the failure completion queue, if anything is present */
scsipi_completion_poll(chan);
return ((mask & int_mask) ? 1 : 0);
}
static void
cmd_handler(void)
{
@ -550,6 +664,9 @@ fail_msgport:
wait_mask = int_mask | timer_mask | cmd_mask;
chan = &sc->sc_channel;
asave->as_int_mask = int_mask;
asave->as_timer_mask = timer_mask;
while (1) {
mask = Wait(wait_mask);
@ -565,6 +682,7 @@ fail_msgport:
if (mask & timer_mask) {
WaitIO(&asave->as_timerio[0]->tr_node);
callout_run_timeouts();
sd_testunitready_walk(chan);
restart_timer();
}
@ -645,7 +763,7 @@ struct unit_list {
unit_list_t *unit_list = NULL;
int
open_unit(uint scsi_target, void **io_Unit)
open_unit(uint scsi_target, void **io_Unit, uint flags)
{
unit_list_t *cur;
for (cur = unit_list; cur != NULL; cur = cur->next) {
@ -655,12 +773,19 @@ open_unit(uint scsi_target, void **io_Unit)
return (0);
}
}
if (flags & TDF_DEBUG_OPEN)
return (ERROR_BAD_UNIT); // This flag only grabs already open device
cur = AllocMem(sizeof (*cur), MEMF_PUBLIC);
if (cur == NULL)
return (ERROR_NO_MEMORY);
struct IOStdReq ior;
ior.io_Message.mn_ReplyPort = CreateMsgPort();
ior.io_Command = CMD_ATTACH;
ior.io_Unit = NULL;
ior.io_Offset = scsi_target;
ior.io_Length = flags;
PutMsg(myPort, &ior.io_Message);
WaitPort(ior.io_Message.mn_ReplyPort);
@ -674,13 +799,6 @@ open_unit(uint scsi_target, void **io_Unit)
return (ERROR_BAD_UNIT); // Attach failed
/* Add new device to periph list */
cur = AllocMem(sizeof (*cur), MEMF_PUBLIC);
if (cur == NULL) {
// XXX: Need to CMD_DETACH peripheral here?
FreeMem(cur, sizeof (*cur));
return (ERROR_NO_MEMORY);
}
cur->count = 1;
cur->periph = (struct scsipi_periph *) ior.io_Unit;
cur->scsi_target = scsi_target;

View File

@ -1,13 +1,17 @@
#ifndef _CMD_HANDLER_H
#define _CMD_HANDLER_H
int open_unit(uint scsi_target, void **io_Unit);
int open_unit(uint scsi_target, void **io_Unit, uint flags);
void close_unit(void *io_Unit);
int start_cmd_handler(uint *boardnum);
void stop_cmd_handler(void);
void cmd_complete(void *ior, int8_t rc);
void td_addchangeint(struct IORequest *ior);
void td_remchangeint(struct IORequest *ior);
void td_remove(struct IORequest *ior);
/* Trackdisk-64 enhanced commands */
/* Check before defining. AmigaOS 3.2 NDK provides these in
* trackdisk.h

View File

@ -196,9 +196,10 @@ static BPTR __attribute__((used))
drv_expunge(struct Library *dev asm("a6"))
{
ObtainSemaphore(&entry_sem);
if (dev->lib_OpenCnt != 0) {
if ((dev->lib_OpenCnt != 0) || periph_still_attached()) {
printf("expunge() device still open\n");
dev->lib_Flags |= LIBF_DELEXP;
dev->lib_Flags |= LIBF_DELEXP; // Indicate I'll expunge myself later
ReleaseSemaphore(&entry_sem);
return (0);
}
@ -244,7 +245,7 @@ drv_open(struct Library *dev asm("a6"), struct IORequest *ioreq asm("a1"),
ObtainSemaphore(&entry_sem);
dev->lib_OpenCnt++;
if ((rc = open_unit(scsi_unit, (void **) &ioreq->io_Unit)) != 0) {
if ((rc = open_unit(scsi_unit, (void **) &ioreq->io_Unit, flags)) != 0) {
printf("Open fail %d.%d\n", scsi_unit % 10, scsi_unit / 10);
dev->lib_OpenCnt--;
ioreq->io_Error = rc;
@ -293,6 +294,36 @@ drv_close(struct Library *dev asm("a6"), struct IORequest *ioreq asm("a1"))
static void __attribute__((used))
drv_begin_io(struct Library *dev asm("a6"), struct IORequest *ior asm("a1"))
{
/* These commands are forced to always execute in immediate mode */
switch (ior->io_Command) {
case TD_REMCHANGEINT:
printf("TD_REMCHANGEINT\n");
td_remchangeint(ior);
return;
case CMD_START:
/*
* This driver doesn't currently disable queue processing
* on a CMD_STOP, so it does not need to immediately
* execute a CMD_START.
*/
break;
}
/* These commands may optionally execute in immediate mode */
if (ior->io_Flags & IOF_QUICK) {
switch (ior->io_Command) {
case TD_ADDCHANGEINT:
printf("TD_ADDCHANGEINT\n");
td_addchangeint(ior);
return;
case TD_REMOVE:
printf("TD_REMOVE\n");
td_remove(ior);
return;
}
}
/* All other commands must be pushed to the driver task */
ior->io_Flags &= ~IOF_QUICK;
PutMsg(myPort, &ior->io_Message);
}

View File

@ -12,8 +12,14 @@
#define ERROR_BAD_DRIVE_TYPE 33 // TDERR_BadDriveType
#define ERROR_SELF_UNIT 40 // HFERR_SelfUnit
#define ERROR_INQUIRY_FAILED 46 // (HFERR_BadStatus + 1)
#define ERROR_TIMEOUT 47 // (HFERR_BadStatus + 2)
#define ERROR_BUS_RESET 48 // (HFERR_BadStatus + 3)
#define ERROR_TRY_AGAIN 49 // (HFERR_BadStatus + 4)
#define ERROR_NO_BOARD 50 // HFERR_NoBoard
#define ERROR_BAD_BOARD 51 // (HFERR_NoBoard + 1)
#define ERROR_SENSE_CODE 52 // (HFERR_NoBoard + 2)
#define TDF_DEBUG_OPEN (1<<7) // Open unit in debug mode (no I/O)
/*
*

49
port.c
View File

@ -10,6 +10,9 @@
#include <proto/exec.h>
#include <clib/debug_protos.h>
#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>
#include <intuition/intuition.h>
#include <inline/intuition.h>
#include <exec/execbase.h>
#include "device.h"
#include "printf.h"
@ -22,11 +25,27 @@
#define PRINTF_CALLOUT(args...)
#endif
#undef panic
void
panic(const char *s)
panic(const char *fmt, ...)
{
printf("PANIC: %s", s);
va_list ap;
struct Library *IntuitionBase;
struct EasyStruct es = {
sizeof (es),
0,
"A4091 Panic",
(char *) fmt,
"OK",
};
printf("PANIC: %s\n\n", fmt);
IntuitionBase = OpenLibrary("intuition.library", 37);
if (IntuitionBase != NULL) {
va_start(ap, fmt);
(void) EasyRequestArgs(NULL, &es, NULL, ap);
va_end(ap);
CloseLibrary(IntuitionBase);
}
}
#if 0
@ -84,7 +103,6 @@ bsd_splx(int ilevel)
Enable();
}
#ifdef USE_SERIAL_OUTPUT
const char *
device_xname(void *ptr)
{
@ -95,6 +113,7 @@ device_xname(void *ptr)
return (dev->dv_xname);
}
#if 0
unsigned int
read_system_ticks(void)
{
@ -175,11 +194,10 @@ callout_t *callout_head = NULL;
static void
callout_add(callout_t *c)
{
c->co_next = callout_head;
c->co_prev = NULL;
if (callout_head != NULL) {
callout_head->co_next->co_prev = c;
}
c->co_next = callout_head;
if (callout_head != NULL)
callout_head->co_prev = c;
callout_head = c;
}
@ -187,18 +205,13 @@ static void
callout_remove(callout_t *c)
{
if (c == callout_head) {
if (c->co_prev != NULL) {
printf("CALLOUT head %p has non-NULL prev %p\n",
callout_head, c->co_prev);
c->co_prev = NULL;
}
callout_head = c->co_next;
} else if (c->co_prev != NULL) {
c->co_prev->co_next = c->co_next;
} else if (c->co_next != NULL) {
printf("CALLOUT list corrupt head=%p c=%p\n", callout_head, c);
if (callout_head != NULL)
callout_head->co_prev = NULL;
return;
}
if (c->co_prev != NULL)
c->co_prev->co_next = c->co_next;
if (c->co_next != NULL)
c->co_next->co_prev = c->co_prev;
}

9
port.h
View File

@ -22,9 +22,10 @@
struct device;
typedef struct device *device_t;
void panic(const char *s);
void panic(const char *s, ...);
unsigned int read_system_ticks(void);
unsigned int ticks_since_last(void);
int irq_and_timer_handler(void);
#define __USE(x) (/*LINTED*/(void)(x))
@ -36,6 +37,7 @@ void bsd_splx();
typedef uint32_t paddr_t;
typedef uint32_t vaddr_t;
#define hz TICKS_PER_SECOND
#define mstohz(m) ((m) * TICKS_PER_SECOND / 1000)
#define kvtop(x) ((uint32_t)(x))
@ -70,8 +72,8 @@ int dbgprintf(const char *fmt, ...);
#define KASSERT(x)
#define mutex_init(x, y, z)
#define mutex_enter(x)
#define mutex_exit(x)
#define mutex_enter(x) do { } while (0)
#define mutex_exit(x) do { } while (0)
#define cv_init(x, y)
#define cv_wait(x, y)
#define cv_broadcast(x)
@ -101,7 +103,6 @@ void *device_private(device_t dev);
#define printf(x...) do { } while (0)
#define vfprintf(x...) do { } while (0)
#define putchar(x...) do { } while (0)
#define panic(x) panic((const char *)0)
#endif
#endif /* _PORT_H */

View File

@ -275,9 +275,11 @@ scsibusattach(device_t parent, device_t self, void *aux)
if (chan->chan_flags & SCSIPI_CHAN_OPENINGS) {
if (chan->chan_max_periph > 256)
chan->chan_max_periph = 256;
#ifndef PORT_AMIGA
} else {
if (chan->chan_adapter->adapt_max_periph > 256)
chan->chan_adapter->adapt_max_periph = 256;
#endif
}
#if 0

View File

@ -163,7 +163,7 @@ int safe_open(struct IOStdReq *ioreq, uint scsi_unit)
{
ioreq->io_Message.mn_Node.ln_Type = NT_REPLYMSG;
if (open_unit(scsi_unit, (void **) &ioreq->io_Unit)) {
if (open_unit(scsi_unit, (void **) &ioreq->io_Unit, 0)) {
printf("No unit at %d.%d\n", scsi_unit % 10, scsi_unit / 10);
ioreq->io_Error = HFERR_SelTimeout;
// HFERR_SelfUnit - attempted to open our own SCSI ID

View File

@ -44,15 +44,18 @@
#include <proto/exec.h>
#include <inline/exec.h>
#if 0
__KERNEL_RCSID(0, "$NetBSD: scsipi_base.c,v 1.187 2020/09/17 01:19:41 jakllsch Exp $");
#endif
#include "scsipiconf.h"
#include "scsi_disk.h"
#include "scsipi_disk.h"
#include "scsipi_base.h"
#include "scsipi_all.h"
#include "scsi_all.h"
#include "siopreg.h"
#include "siopvar.h"
#include "scsi_message.h"
#include "sd.h"
#undef SCSIPI_DEBUG
#undef QUEUE_DEBUG
@ -68,10 +71,6 @@ static void scsipi_put_tag(struct scsipi_xfer *xs);
extern struct ExecBase *SysBase;
#ifdef PORT_AMIGA
void irq_poll(int gotint, struct siop_softc *sc);
#endif
#if 0
/*
* scsipi_update_timeouts:
@ -264,7 +263,7 @@ scsipi_get_xs(struct scsipi_periph *periph, int flags)
chan->chan_active++;
#if 0
printf("get_xs(%p) active=%u\n", xs, periph->periph_active);
printf("get_xs(%p) active=%u\n", xs, chan->chan_active);
#endif
return (xs);
}
@ -296,7 +295,7 @@ scsipi_put_xs(struct scsipi_xfer *xs)
chan->chan_xs_free = xs;
#if 0
printf("put_xs(%p) active=%u\n", xs, periph->periph_active);
printf("put_xs(%p) active=%u\n", xs, chan->chan_active);
#endif
}
@ -330,7 +329,6 @@ scsipi_execute_xs(struct scsipi_xfer *xs)
KASSERT(!cold);
#ifdef PORT_AMIGA
uint timeout;
/*
* Set the LUN in the CDB if we have an older device. We also
* set it for more modern SCSI-2 devices "just in case".
@ -408,7 +406,11 @@ scsipi_execute_xs(struct scsipi_xfer *xs)
scsipi_printaddr(periph);
printf("invalid tag mask 0x%08x\n",
XS_CTL_TAGTYPE(xs));
#ifdef PORT_AMIGA
panic("invalid tag mask %x", XS_CTL_TAGTYPE(xs));
#else
panic("scsipi_execute_xs");
#endif
}
}
@ -441,7 +443,11 @@ scsipi_execute_xs(struct scsipi_xfer *xs)
scsipi_printaddr(periph);
printf("not polling, but enqueue failed with %d\n",
error);
#ifdef PORT_AMIGA
panic("not polling but enqueue failed %d", error);
#else
panic("scsipi_execute_xs");
#endif
}
scsipi_printaddr(periph);
@ -464,57 +470,19 @@ scsipi_execute_xs(struct scsipi_xfer *xs)
/*
* Not an asynchronous command; wait for it to complete.
*/
#ifdef PORT_AMIGA
/*
* XXX: More can be done to improve the completion poll timeout.
* It could instead call into an enhanced cmdhandler function
* which would choose to only wait on interrupts and timer
* messages. That would increase efficiency by not having
* the driver poll for 53C710 interrupt status every tick.
*/
timeout = xs->timeout * TICKS_PER_SECOND / 1000;
if (timeout == 0) {
timeout = 1; // Run at least one poll iteration
}
struct siop_softc *sc = device_private(chan->chan_adapter->adapt_dev);
irq_poll(1, sc);
while ((xs->xs_status & XS_STS_DONE) == 0) {
/*
* Need to run interrupt message handling here because
* this code is running in the same thread as the normal
* interrupt message handling.
*/
if (timeout-- == 0) {
printf("SCSI completion poll timeout: %d\n", xs->timeout);
break;
}
delay(1000000 / TICKS_PER_SECOND); // 1 tick
irq_poll(1, sc);
}
/*
* If the XS did not complete due to timeout, then execute
* the timeout callout, if one has been set up.
*/
if ((xs->xs_status & XS_STS_DONE) == 0) {
if (callout_pending(&xs->xs_callout)) {
printf("Did not reach STS_DONE, running callout\n");
callout_call(&xs->xs_callout);
callout_stop(&xs->xs_callout); // Combine with call?
}
}
#else /* !PORT_AMIGA */
while ((xs->xs_status & XS_STS_DONE) == 0) {
if (poll) {
scsipi_printaddr(periph);
#ifndef PORT_AMIGA
printf("polling command not done\n");
panic("scsipi_execute_xs");
#endif
}
#ifdef PORT_AMIGA
irq_and_timer_handler(); // Run timer and interrupts
#endif
cv_wait(xs_cv(xs), chan_mtx(chan));
}
#endif
/*
* Command is complete. scsipi_done() has awakened us to perform
@ -539,6 +507,9 @@ scsipi_execute_xs(struct scsipi_xfer *xs)
*/
mutex_enter(chan_mtx(chan));
free_xs:
if (xs->xs_done_callback != NULL) {
printf("BUG: xs_done_callback not called\n");
}
scsipi_put_xs(xs);
mutex_exit(chan_mtx(chan));
@ -568,10 +539,12 @@ scsipi_execute_xs(struct scsipi_xfer *xs)
int
scsipi_channel_init(struct scsipi_channel *chan)
{
// struct scsipi_adapter *adapt = chan->chan_adapter;
#ifndef PORT_AMIGA
struct scsipi_adapter *adapt = chan->chan_adapter;
#endif
int i;
#if 0
#ifndef PORT_AMIGA
/* Initialize shared data. */
scsipi_init();
#endif
@ -584,7 +557,7 @@ scsipi_channel_init(struct scsipi_channel *chan)
for (i = 0; i < SCSIPI_CHAN_PERIPH_BUCKETS; i++)
LIST_INIT(&chan->chan_periphtab[i]);
#if 0
#ifndef PORT_AMIGA
/*
* Create the asynchronous completion thread.
*/
@ -599,7 +572,7 @@ scsipi_channel_init(struct scsipi_channel *chan)
return 0;
}
static uint32_t
uint32_t
scsipi_chan_periph_hash(uint64_t t, uint64_t l)
{
return (0);
@ -703,6 +676,8 @@ scsipi_make_xs_internal(struct scsipi_periph *periph,
xs->timeout = timeout;
xs->bp = bp;
if (timeout == 0)
printf("WARNING: xs new timeout is ZERO for cmd %x\n", cmd->opcode);
return (xs);
}
@ -770,22 +745,28 @@ scsipi_grow_resources(struct scsipi_channel *chan)
{
if (chan->chan_flags & SCSIPI_CHAN_CANGROW) {
#ifndef PORT_AMIGA
if ((chan->chan_flags & SCSIPI_CHAN_TACTIVE) == 0) {
#endif
/*
* Amiga driver doesn't wait for completion thread
* to grow resources.
*/
mutex_exit(chan_mtx(chan));
scsipi_adapter_request(chan,
ADAPTER_REQ_GROW_RESOURCES, NULL);
mutex_enter(chan_mtx(chan));
return scsipi_get_resource(chan);
#ifndef PORT_AMIGA
}
/*
* ask the channel thread to do it. It'll have to thaw the
* queue
*/
#if 0
scsipi_channel_freeze_locked(chan, 1);
#endif
chan->chan_tflags |= SCSIPI_CHANT_GROWRES;
// cv_broadcast(chan_cv_complete(chan));
#endif
return 0;
}
@ -853,6 +834,8 @@ scsipi_get_tag(struct scsipi_xfer *xs)
}
xs->xs_tag_id = tag;
SDT_PROBE3(scsi, base, tag, get,
xs, xs->xs_tag_id, xs->xs_tag_type);
}
/*
@ -870,6 +853,9 @@ scsipi_put_tag(struct scsipi_xfer *xs)
KASSERT(mutex_owned(chan_mtx(periph->periph_channel)));
SDT_PROBE3(scsi, base, tag, put,
xs, xs->xs_tag_id, xs->xs_tag_type);
word = xs->xs_tag_id >> 5;
bit = xs->xs_tag_id & 0x1f;
@ -888,7 +874,13 @@ scsipi_run_queue(struct scsipi_channel *chan)
struct scsipi_periph *periph;
for (;;) {
#ifndef PORT_AMIGA
#ifdef PORT_AMIGA
/*
* A reset is pending on channel - don't issue anything new.
*/
if (chan->chan_flags & SCSIPI_CHAN_RESET_PEND)
break;
#else
/*
* If the channel is frozen, we can't do any work right
* now.
@ -908,6 +900,11 @@ scsipi_run_queue(struct scsipi_channel *chan)
#ifdef PORT_AMIGA
if ((periph->periph_sent >= periph->periph_openings) ||
(periph->periph_flags & PERIPH_UNTAG) != 0) {
/*
* PERIPH_UNTAG means the device is running a
* single untagged command. No other commands
* are allowed at this time.
*/
if (xs == TAILQ_LAST(&chan->chan_queue, scsipi_xfer_queue))
break; // Last entry in queue
continue;
@ -1128,27 +1125,32 @@ scsipi_done(struct scsipi_xfer *xs)
scsipi_run_queue(chan);
}
/*
* scsipi_completion_poll
* ----------------------
* Finish completions or perform other channel thread service operations.
*/
void
scsipi_completion_poll(struct scsipi_channel *chan)
{
struct scsipi_xfer *xs;
chan->chan_flags |= SCSIPI_CHAN_TACTIVE;
while ((xs = TAILQ_FIRST(&chan->chan_complete)) != NULL) {
do {
#ifndef PORT_AMIGA
if (chan->chan_tflags & SCSIPI_CHANT_GROWRES) {
/* attempt to get more openings for this channel */
chan->chan_tflags &= ~SCSIPI_CHANT_GROWRES;
mutex_exit(chan_mtx(chan));
scsipi_adapter_request(chan,
ADAPTER_REQ_GROW_RESOURCES, NULL);
#if 0
scsipi_channel_thaw(chan, 1);
#endif
if (chan->chan_tflags & SCSIPI_CHANT_GROWRES)
delay(100000);
mutex_enter(chan_mtx(chan));
continue;
}
#endif
if (chan->chan_tflags & SCSIPI_CHANT_KICK) {
/* explicitly run the queues for this channel */
chan->chan_tflags &= ~SCSIPI_CHANT_KICK;
@ -1159,6 +1161,8 @@ scsipi_completion_poll(struct scsipi_channel *chan)
}
if (chan->chan_tflags & SCSIPI_CHANT_SHUTDOWN)
break;
xs = TAILQ_FIRST(&chan->chan_complete);
if (xs) {
#ifdef QUEUE_DEBUG
printf("(removing %p)", xs);
@ -1178,8 +1182,10 @@ scsipi_completion_poll(struct scsipi_channel *chan)
scsipi_run_queue(chan);
mutex_enter(chan_mtx(chan));
}
}
} while (xs != NULL);
#ifndef PORT_AMIGA // Amiga driver runs this as part of command handler thread
chan->chan_flags &= ~SCSIPI_CHAN_TACTIVE;
#endif
}
@ -1348,20 +1354,15 @@ scsipi_complete(struct scsipi_xfer *xs)
if ((xs->xs_control & XS_CTL_POLL) ||
(chan->chan_flags & SCSIPI_CHAN_TACTIVE) == 0) {
#ifdef PORT_AMIGA
/* Wait 1 second */
int count = TICKS_PER_SECOND;
struct siop_softc *sc =
device_private(chan->chan_adapter->adapt_dev);
while (count-- > 0) {
delay(20000);
/*
* Continue running interrupt processing
* while waiting to try again.
*/
irq_poll(1, sc);
}
printf(",");
/*
* Wait at least 1 second, running timer and
* interrupts until we've seen two timer
* messages.
*/
int count = 0;
do {
count += irq_and_timer_handler();
} while (count < 2);
#else /* !PORT_AMIGA */
/* XXX: quite extreme */
kpause("xsbusy", false, hz, chan_mtx(chan));
@ -1428,7 +1429,7 @@ scsipi_complete(struct scsipi_xfer *xs)
mutex_enter(chan_mtx(chan));
if (error == ERESTART) {
printf("restart retries left=%d\n", xs->xs_retries);
printf("restart %p retries left=%d\n", xs, xs->xs_retries);
SDT_PROBE1(scsi, base, xfer, restart, xs);
/*
* If we get here, the periph has been thawed and frozen
@ -1517,26 +1518,6 @@ scsipi_print_sense(struct scsipi_xfer * xs, int verbosity)
}
#endif
#ifdef PORT_AMIGA
void
periph_media_unloaded(struct scsipi_periph *periph)
{
if (periph->periph_flags & PERIPH_MEDIA_LOADED) {
periph->periph_flags &= ~PERIPH_MEDIA_LOADED;
periph->periph_changenum++;
}
}
void
periph_media_loaded(struct scsipi_periph *periph)
{
if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) {
periph->periph_flags |= PERIPH_MEDIA_LOADED;
periph->periph_changenum++;
}
}
#endif
/*
* scsipi_interpret_sense:
*
@ -1625,7 +1606,7 @@ scsipi_interpret_sense(struct scsipi_xfer *xs)
case 0x04: /* drive not ready after it was selected */
#ifdef PORT_AMIGA
if ((periph->periph_flags & PERIPH_REMOVABLE) != 0)
periph_media_unloaded(periph);
sd_media_unloaded(periph);
#else
if ((periph->periph_flags & PERIPH_REMOVABLE) != 0)
periph->periph_flags &= ~PERIPH_MEDIA_LOADED;
@ -1681,10 +1662,7 @@ scsipi_interpret_sense(struct scsipi_xfer *xs)
error = 0;
break;
case SKEY_NOT_READY:
#ifdef PORT_AMIGA
printf("SKEY_NOT_READY: asc=%02x ascq=%02x\n",
sense->asc, sense->ascq);
#else
#ifndef PORT_AMIGA
if ((periph->periph_flags & PERIPH_REMOVABLE) != 0)
periph->periph_flags &= ~PERIPH_MEDIA_LOADED;
#endif
@ -1693,7 +1671,7 @@ scsipi_interpret_sense(struct scsipi_xfer *xs)
if (sense->asc == 0x3A) {
#ifdef PORT_AMIGA
if (periph->periph_flags & PERIPH_REMOVABLE)
periph_media_unloaded(periph);
sd_media_unloaded(periph);
#endif
error = ENODEV; /* Medium not present */
if (xs->xs_control & XS_CTL_SILENT_NODEV)
@ -1727,7 +1705,7 @@ scsipi_interpret_sense(struct scsipi_xfer *xs)
}
#ifdef PORT_AMIGA
if ((periph->periph_flags & PERIPH_REMOVABLE) != 0)
periph_media_unloaded(periph);
sd_media_unloaded(periph);
#else
if ((periph->periph_flags & PERIPH_REMOVABLE) != 0)
periph->periph_flags &= ~PERIPH_MEDIA_LOADED;

View File

@ -16,7 +16,6 @@ int scsipi_command(struct scsipi_periph *periph, struct scsipi_generic *cmd,
int cmdlen, u_char *data_addr, int datalen, int retries, int timeout,
struct buf *bp, int flags);
void periph_media_unloaded(struct scsipi_periph *periph);
void periph_media_loaded(struct scsipi_periph *periph);
uint32_t scsipi_chan_periph_hash(uint64_t t, uint64_t l);
#endif /* _SCSIPI_BASE */

View File

@ -199,7 +199,9 @@ struct scsipi_adapter {
int adapt_nchannels; /* number of adapter channels */
volatile int adapt_refcnt; /* adapter's reference count */
int adapt_openings; /* total # of command openings */
#ifndef PORT_AMIGA
int adapt_max_periph; /* max openings per periph */
#endif
int adapt_flags;
void (*adapt_request)(struct scsipi_channel *,
@ -360,6 +362,9 @@ struct scsipi_channel {
#define SCSIPI_CHAN_CANGROW 0x02 /* channel can grow resources */
#define SCSIPI_CHAN_NOSETTLE 0x04 /* don't wait for devices to settle */
#define SCSIPI_CHAN_TACTIVE 0x08 /* completion thread is active */
#ifdef PORT_AMIGA
#define SCSIPI_CHAN_RESET_PEND 0x10 /* reset pending on channel */
#endif
/* chan thread flags (chan_tflags) */
#define SCSIPI_CHANT_SHUTDOWN 0x01 /* channel is shutting down */
@ -427,6 +432,8 @@ struct scsipi_opcodes
struct scsipi_periph {
#ifdef PORT_AMIGA
void *drv_state; /* pointer to Amiga driver's device state */
struct MinList periph_changeintlist; /* Notify list for media change */
struct Interrupt *periph_changeint; /* Old notify for media change */
#else
device_t periph_dev; /* pointer to peripheral's device */
#endif
@ -464,6 +471,7 @@ struct scsipi_periph {
#ifdef PORT_AMIGA
uint periph_blkshift; /* Block size of this LUN in bits */
uint periph_changenum; /* Count of removes/inserts */
uint periph_tur_active; /* Test unit ready already active */
#endif
int periph_version; /* ANSI SCSI version */

263
sd.c
View File

@ -28,7 +28,7 @@
#endif
#ifndef SD_IO_TIMEOUT
#define SD_IO_TIMEOUT (5 * 1000) // 5 seconds
#define SD_IO_TIMEOUT (3 * 1000) // 5 seconds
#endif
typedef struct
@ -45,26 +45,83 @@ static void geom_done_inquiry(struct scsipi_xfer *xs);
static const int8_t error_code_mapping[] = {
0, // 0 XS_NOERROR No error, (invalid sense)
HFERR_BadStatus, // 1 XS_SENSE Check returned sense for error
ERROR_SENSE_CODE, // 1 XS_SENSE Check returned sense for error
HFERR_BadStatus, // 2 XS_SHORTSENSE Check ATAPI sense for the error
HFERR_DMA, // 3 XS_DRIVER_STUFFUP Driver failed operation
HFERR_BadStatus, // 4 XS_RESOURCE_SHORTAGE Adapter resource shortage
ERROR_NO_MEMORY, // 4 XS_RESOURCE_SHORTAGE Adapter resource shortage
HFERR_SelTimeout, // 5 XS_SELTIMEOUT Device timed out.. turned off?
HFERR_SelTimeout, // 6 XS_TIMEOUT Timeout was caught by SW
ERROR_TIMEOUT, // 6 XS_TIMEOUT Timeout was caught by SW
IOERR_UNITBUSY, // 7 XS_BUSY Device busy, try again later?
HFERR_Phase, // 8 XS_RESET Bus reset; possible retry cmd
HFERR_Phase, // 9 XS_REQUEUE Requeue this command
ERROR_BUS_RESET, // 8 XS_RESET Bus reset; possible retry cmd
ERROR_TRY_AGAIN, // 9 XS_REQUEUE Requeue this command
};
/* Translate error code to AmigaOS code */
static int
translate_xs_error(scsipi_xfer_result_t res)
translate_xs_error(struct scsipi_xfer *xs)
{
scsipi_xfer_result_t res = xs->error;
if (res == XS_SENSE) {
if ((xs->sense.scsi_sense.asc == 0x3a) ||
((xs->sense.scsi_sense.asc == 0x04) &&
(xs->sense.scsi_sense.ascq == 0x02))) {
return (TDERR_DiskChanged); // No disk present
}
if (xs->sense.scsi_sense.asc == 0x27)
return (TDERR_WriteProt); // Write-protected
}
if (res < ARRAY_SIZE(error_code_mapping))
res = error_code_mapping[res];
return (res);
}
void
call_changeintlist(struct scsipi_periph *periph)
{
struct IOStdReq *io;
Forbid();
if (periph->periph_changeint != NULL) {
printf("Notify TD_REMOVE\n");
Cause(periph->periph_changeint); // TD_REMOVE interrupt
}
for (io = (struct IOStdReq *)periph->periph_changeintlist.mlh_Head;
io->io_Message.mn_Node.ln_Succ != NULL;
io = (struct IOStdReq *)io->io_Message.mn_Node.ln_Succ) {
if (io->io_Data != NULL) {
printf("Notify TD_ADDCHANGEINT %p\n", io->io_Data);
Cause(io->io_Data); // TD_ADDCHANGEINT interrupt
}
}
Permit();
}
void
sd_media_unloaded(struct scsipi_periph *periph)
{
if (periph->periph_flags & PERIPH_MEDIA_LOADED) {
periph->periph_flags &= ~PERIPH_MEDIA_LOADED;
periph->periph_changenum++;
call_changeintlist(periph);
printf("Media unloaded\n");
}
}
void
sd_media_loaded(struct scsipi_periph *periph)
{
if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) {
periph->periph_flags |= PERIPH_MEDIA_LOADED;
periph->periph_changenum++;
call_changeintlist(periph);
printf("Media loaded\n");
}
}
/*
* sd_read_capacity
* ----------------
@ -232,6 +289,8 @@ sd_testunitready(void *periph_p, void *ior)
if (periph->periph_quirks & PQUIRK_NOTUR) {
/* Device does not support TEST_UNIT_READY */
struct IOExtTD *iotd = (struct IOExtTD *) ior;
if (ior == NULL)
return (0);
iotd->iotd_Req.io_Actual = 0; // Assume drive is present
cmd_complete(ior, 0);
return (0);
@ -239,8 +298,9 @@ sd_testunitready(void *periph_p, void *ior)
memset(&cmd, 0, sizeof (cmd));
cmd.opcode = SCSI_TEST_UNIT_READY;
cmd.byte2 = periph->periph_lun << 5;
flags = XS_CTL_ASYNC | XS_CTL_SIMPLE_TAG | XS_CTL_IGNORE_ILLEGAL_REQUEST |
flags = XS_CTL_ASYNC | XS_CTL_SIMPLE_TAG |
XS_CTL_IGNORE_NOT_READY | XS_CTL_IGNORE_MEDIA_CHANGE;
/* No buffer, no retries, timeout 2 seconds */
@ -249,12 +309,60 @@ sd_testunitready(void *periph_p, void *ior)
if (__predict_false(xs == NULL))
return (TDERR_NoMem); // out of memory
periph->periph_tur_active++;
printf(" sd_testunitready %d tur_active=%d\n",
periph->periph_target, periph->periph_tur_active);
/*
* Note that ior will be NULL when this function is called by
* sd_testunitready_walk(). When called by TD_CHANGESTATE, ior
* is non-NULL. In either case, sd_tur_complete() will know how
* to handle this.
*/
xs->amiga_ior = ior;
xs->xs_done_callback = sd_tur_complete;
return (scsipi_execute_xs(xs));
}
static BOOL
IsMinListEmpty(const struct MinList *list)
{
BOOL is_empty;
is_empty = (BOOL)(list->mlh_TailPred == (struct MinNode *)list);
return(is_empty);
}
/*
* sd_testunitready_walk
* ---------------------
* Walks all peripherals of the channel which have client applications
* waiting for change interrupts (TD_REMOVE or TD_ADDCHANGEINT).
*/
void
sd_testunitready_walk(struct scsipi_channel *chan)
{
struct scsipi_periph *periph;
int i;
static uint8_t iter = 0;
if ((iter++ & 3) != 0) // Poll every 4 seconds
return;
for (i = 0; i < SCSIPI_CHAN_PERIPH_BUCKETS; i++) {
LIST_FOREACH(periph, &chan->chan_periphtab[i], periph_hash) {
if ((periph->periph_tur_active == 0) &&
((periph->periph_changeint != NULL) ||
!IsMinListEmpty(&periph->periph_changeintlist))) {
/* Need to poll this device to detect load/eject */
sd_testunitready(periph, NULL);
}
}
}
}
/*
* sd_readwrite
* ------------
@ -485,13 +593,21 @@ sd_startstop(void *periph_p, void *ior, int start, int load_eject, int immed)
/* Allow more time for start */
timeout = load_eject ?
(start ? 20000 : 5000) :
#ifdef EJECT_DEBUG
(start ? 20000 : 3000) :
#else
(start ? 45000 : 8000) :
#endif
(start ? 6000 : 3000);
flags |= XS_CTL_IGNORE_MEDIA_CHANGE | XS_CTL_IGNORE_NOT_READY;
xs = scsipi_make_xs_locked(periph, (struct scsipi_generic *) &cmd,
#ifdef EJECT_DEBUG
cmdlen, NULL, 0, 0, timeout, NULL, flags);
#else
cmdlen, NULL, 0, 1, timeout, NULL, flags);
#endif
if (__predict_false(xs == NULL))
return (TDERR_NoMem); // out of memory
@ -501,13 +617,6 @@ sd_startstop(void *periph_p, void *ior, int start, int load_eject, int immed)
/* Return previous media state in io_Actual 0=Present, 1=Removed */
iotd->iotd_Req.io_Actual = !(periph->periph_flags & PERIPH_MEDIA_LOADED);
#if 0
printf("sd%d.%d %p %s\n",
periph->periph_target, periph->periph_lun, xs,
load_eject ? (start ? "load" : "eject") :
(start ? "start" : "stop"));
#endif
return (scsipi_execute_xs(xs));
}
@ -561,7 +670,7 @@ queue_get_mode_page(struct scsipi_xfer *oxs, uint8_t page, uint8_t dbd,
static void
geom_done_mode_page_5(struct scsipi_xfer *xs)
{
int rc = translate_xs_error(xs->error);
int rc = translate_xs_error(xs);
scsi_mode_sense_t *modepage = (scsi_mode_sense_t *) xs->data;
printf("mode_page_5 complete: %d\n", rc);
@ -613,7 +722,7 @@ geom_done_mode_page_5(struct scsipi_xfer *xs)
static void
geom_done_mode_page_4(struct scsipi_xfer *xs)
{
int rc = translate_xs_error(xs->error);
int rc = translate_xs_error(xs);
scsi_mode_sense_t *modepage = (scsi_mode_sense_t *) xs->data;
printf("mode_page_4 complete: %d\n", rc);
@ -778,7 +887,7 @@ geom_done_inquiry(struct scsipi_xfer *oxs)
rc = scsipi_execute_xs(xs);
if (rc != 0)
cmd_complete(oxs->amiga_ior, translate_xs_error(rc));
cmd_complete(oxs->amiga_ior, rc);
}
int
@ -823,11 +932,18 @@ sd_scsidirect(void *periph_p, void *scmd_p, void *ior)
else
flags |= XS_CTL_DATA_OUT;
#if 0
// flags |= XS_CTL_DATA_UIO;
// xs->xs_control |= XS_CTL_USERCMD; // to indicate user command (no autosense)
if ((scmd->scsi_Flags & SCSIF_OLDAUTOSENSE) == SCSIF_OLDAUTOSENSE)
printf("scsidirect: Old autosense\n");
else if (scmd->scsi_Flags & SCSIF_AUTOSENSE)
printf("scsidirect: Autosense\n");
/*
* XXX: If SCSIF_AUTOSENSE is not set, then we need to disable
* automatic sense with the following (untested):
* xs->xs_control |= XS_CTL_USERCMD; // to indicate user command
*/
#endif
xs = scsipi_make_xs_locked(periph, cmdp, cmdlen, buf, buflen,
@ -842,12 +958,6 @@ sd_scsidirect(void *periph_p, void *scmd_p, void *ior)
xs->xs_periph->periph_target, xs->xs_periph->periph_lun, xs);
#endif
return (scsipi_execute_xs(xs));
// xs->xs_control |= XS_CTL_USERCMD; // to indicate user command
//
// flags |= XS_CTL_DATA_UIO;
// XS_CTL_RESET XS_CTL_TARGET XS_CTL_ESCAPE XS_CTL_URGENT
// XS_CTL_SIMPLE_TAG XS_CTL_ORDERED_TAG XS_CTL_HEAD_TAG
// XS_CTL_REQSENSE
}
@ -855,26 +965,31 @@ sd_scsidirect(void *periph_p, void *scmd_p, void *ior)
static void
sd_complete(struct scsipi_xfer *xs)
{
int rc = translate_xs_error(xs->error);
int rc = translate_xs_error(xs);
#ifdef DEBUG
if (xs->amiga_ior == NULL) {
printf("NULL IOR received\n\n");
return; /* This should not happen */
}
#endif
#if 0
#ifdef DEBUG_SD_READWRITE
printf("sd%d.%d %p done %c rc=%d\n",
xs->xs_periph->periph_target, xs->xs_periph->periph_lun, xs,
(xs->xs_control & XS_CTL_DATA_OUT) ? 'W' : 'R', rc);
#endif
#ifdef DEBUG_SD
if (xs->error == XS_SENSE) {
uint8_t key = SSD_SENSE_KEY(xs->sense.scsi_sense.flags);
printf("got sense:");
printf("sd_complete sense key=%x asc=%02x ascq=%02x\n",
SSD_SENSE_KEY(xs->sense.scsi_sense.flags),
xs->sense.scsi_sense.asc, xs->sense.scsi_sense.ascq);
#if 0
for (int t = 0; t < sizeof (xs->sense.scsi_sense); t++)
printf(" %02x", ((uint8_t *) &xs->sense.scsi_sense)[t]);
printf("\nkey=%x asc=%02x ascq=%02x\n",
key, xs->sense.scsi_sense.asc, xs->sense.scsi_sense.ascq);
printf("\n");
#endif
}
#endif
cmd_complete(xs->amiga_ior, rc);
@ -883,20 +998,21 @@ sd_complete(struct scsipi_xfer *xs)
static void
sd_startstop_complete(struct scsipi_xfer *xs)
{
int rc = translate_xs_error(xs->error);
int rc = translate_xs_error(xs);
if (xs->error != 0)
printf("startstop complete xs->error=%d\n", xs->error);
if (xs->error == XS_SENSE) {
uint8_t key = SSD_SENSE_KEY(xs->sense.scsi_sense.flags);
printf("sense key=%02x asc=%02x ascq=%02x\n", key,
printf("startstop sense key=%02x asc=%02x ascq=%02x\n", key,
xs->sense.scsi_sense.asc, xs->sense.scsi_sense.ascq);
if ((key == SKEY_NOT_READY) && (xs->sense.scsi_sense.asc == 4)) {
/* "Not ready" status is fine for eject / load / stop / start */
cmd_complete(xs->amiga_ior, 0);
return;
rc = 0;
}
}
/* Kick off an immediate TEST_UNIT_READY to detect load/eject state */
sd_testunitready(xs->xs_periph, NULL);
cmd_complete(xs->amiga_ior, rc);
}
@ -906,44 +1022,58 @@ sd_tur_complete(struct scsipi_xfer *xs)
{
struct IOExtTD *iotd = (struct IOExtTD *) xs->amiga_ior;
struct scsipi_periph *periph = xs->xs_periph;
ULONG actual; // 0 = Present, !0 = Not present
int rc = translate_xs_error(xs->error);
int rc = translate_xs_error(xs);
if (xs->error == XS_SENSE) {
uint8_t key = SSD_SENSE_KEY(xs->sense.scsi_sense.flags);
if (key == SKEY_NOT_READY) {
if (xs->sense.scsi_sense.asc == 0x3a) {
periph_media_unloaded(periph);
iotd->iotd_Req.io_Actual = -1; // Drive is not present
} else {
iotd->iotd_Req.io_Actual = 0; // Drive present, but not ready
periph_media_loaded(periph);
}
cmd_complete(xs->amiga_ior, 0);
} else {
iotd->iotd_Req.io_Actual = 0; // Assume drive is present
cmd_complete(xs->amiga_ior, key); // Return error code
}
periph->periph_tur_active--;
#if 0
printf("got sense:");
for (int t = 0; t < sizeof (xs->sense.scsi_sense); t++)
printf(" %02x", ((uint8_t *) &xs->sense.scsi_sense)[t]);
printf("\nkey=%x asc=%02x ascq=%02x\n",
key, xs->sense.scsi_sense.asc, xs->sense.scsi_sense.ascq);
printf("tur complete %d rc=%d xserror=%d tur_active=%d\n",
periph->periph_target, rc, xs->error, periph->periph_tur_active);
#endif
return;
if (xs->error == XS_SENSE) {
rc = SSD_SENSE_KEY(xs->sense.scsi_sense.flags);
if (rc == SKEY_NOT_READY) {
if ((xs->sense.scsi_sense.asc == 0x3a) ||
((xs->sense.scsi_sense.asc == 0x04) &&
(xs->sense.scsi_sense.ascq == 0x02))) {
sd_media_unloaded(periph);
actual = -1; // Drive is not present
} else {
actual = 0; // Drive present, though not ready
sd_media_loaded(periph);
}
rc = 0;
} else {
actual = 0; // Assume drive is present
}
#undef DEBUG_SD_TEST_UNIT_READY
#ifdef DEBUG_SD_TEST_UNIT_READY
if (xs->sense.scsi_sense.asc != 0x3a) {
printf("TUR sense:");
for (int t = 0; t < sizeof (xs->sense.scsi_sense); t++)
printf(" %02x", ((uint8_t *) &xs->sense.scsi_sense)[t]);
printf("\nkey=%x asc=%02x ascq=%02x\n",
SSD_SENSE_KEY(xs->sense.scsi_sense.flags),
xs->sense.scsi_sense.asc, xs->sense.scsi_sense.ascq);
}
#endif
} else {
actual = 0; // Drive is present (and ready)
sd_media_loaded(periph);
}
if (iotd != NULL) {
iotd->iotd_Req.io_Actual = actual;
cmd_complete(xs->amiga_ior, rc); // Return error code
}
iotd->iotd_Req.io_Actual = 0; // Drive is present (and ready)
periph_media_loaded(periph);
cmd_complete(xs->amiga_ior, rc);
}
static void
scsidirect_complete(struct scsipi_xfer *xs)
{
int rc = translate_xs_error(xs->error);
int rc = translate_xs_error(xs);
struct SCSICmd *scmd = xs->xs_callback_arg;
scmd->scsi_Status = rc;
@ -951,11 +1081,12 @@ scsidirect_complete(struct scsipi_xfer *xs)
scmd->scsi_CmdActual = scmd->scsi_CmdLength;
if (rc != 0) {
printf("sdirect%d.%d fail %d\n",
xs->xs_periph->periph_target, xs->xs_periph->periph_lun, rc);
printf("sdirect%d.%d fail %d (%d)\n",
xs->xs_periph->periph_target, xs->xs_periph->periph_lun, rc,
xs->error);
if (scmd->scsi_Flags & SCSIF_AUTOSENSE) {
UWORD len = scmd->scsi_SenseLength;
if (len < sizeof (xs->sense.scsi_sense))
if (len > sizeof (xs->sense.scsi_sense))
len = sizeof (xs->sense.scsi_sense);
CopyMem(&xs->sense.scsi_sense, scmd->scsi_SenseData, len);
scmd->scsi_SenseActual = len;

10
sd.h
View File

@ -1,5 +1,5 @@
#ifndef _MY_SD_H
#define _MY_SD_H
#ifndef _SD_H
#define _SD_H
int sd_readwrite(void *periph, uint64_t blkno, uint b_flags,
void *buf, uint buflen, void *ior);
@ -10,7 +10,11 @@ int sd_get_protstatus(void *periph_p, ULONG *status);
int sd_startstop(void *periph_p, void *ior, int start, int load_eject,
int immed);
int sd_testunitready(void *periph_p, void *ior);
void sd_testunitready_walk(struct scsipi_channel *chan);
uint32_t sd_blocksize(void *periph_p);
#endif /* _MY_SD_H */
void sd_media_unloaded(struct scsipi_periph *periph);
void sd_media_loaded(struct scsipi_periph *periph);
#endif /* _SD_H */

108
siop.c
View File

@ -142,13 +142,14 @@ const
/* default to not inhibit sync negotiation on any drive */
u_char siop_inhibit_sync[8] = { 0, 0, 0, 0, 0, 0, 0 }; /* initialize, so patchable */
const u_char siop_allow_disc[8] = {3, 3, 3, 3, 3, 3, 3, 3};
#if 0
int siop_no_dma = 1; // CDH debug
#else
int siop_no_dma = 0;
#endif
u_char siop_allow_disc[8] = {3, 3, 3, 3, 3, 3, 3, 3};
int siop_no_disc = 0; // Disable Synchronous SCSI when this flag is set
int siop_no_dma = 0; // Disable 53C710 DMA when this flag is set
/*
* siop_reset_delay must provide sufficient time for all targets
* on the bus to recover following a bus reset.
*/
const int siop_reset_delay = 250; /* delay after reset, in milliseconds */
#if 0
@ -230,6 +231,7 @@ void siop_dump_trace(void);
#define SIOP_TRACE(a,b,c,d)
#endif
#ifndef PORT_AMIGA
/*
* default minphys routine for siop based controllers
*/
@ -240,8 +242,9 @@ siop_minphys(struct buf *bp)
/*
* No max transfer at this level.
*/
// minphys(bp);
minphys(bp);
}
#endif
/*
* used by specific siop controller
@ -267,9 +270,11 @@ siop_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req,
#endif
flags = xs->xs_control;
#ifndef PORT_AMIGA
/* XXXX ?? */
if (flags & XS_CTL_DATA_UIO)
panic("siop: scsi data uio requested");
#endif
/* XXXX ?? */
if (sc->sc_nexus && flags & XS_CTL_POLL)
@ -437,6 +442,19 @@ siop_sched(struct siop_softc *sc)
if (acb->xs->xs_control & XS_CTL_RESET)
siopreset(sc);
#ifdef PORT_AMIGA
/*
* Setup timeout callout for every issued transaction on the channel.
*
* This differs from the original NetBSD driver where a callout is
* only set for the first transaction active on the bus. In that case,
* if the first one finishes, but following transactions do not finish,
* a driver hang will occur, since there is nothing to terminate another
* active command.
*/
callout_reset(&acb->xs->xs_callout,
mstohz(acb->xs->timeout) + 1, siop_timeout, acb);
#endif
#if 0
acb->cmd.bytes[0] |= slp->scsipi_scsi.lun << 5; /* XXXX */
#endif
@ -492,12 +510,10 @@ siop_scsidone(struct siop_acb *acb, int stat)
--sc->sc_active;
SIOP_TRACE('d','a',stat,0)
} else if (sc->ready_list.tqh_last == &acb->chain.tqe_next) {
printf("CDH: acb %p is at top of ready list\n", acb);
TAILQ_REMOVE(&sc->ready_list, acb, chain);
SIOP_TRACE('d','r',stat,0)
} else {
register struct siop_acb *acb2;
printf("CDH: searching for acb %p\n", acb);
for (acb2 = sc->nexus_list.tqh_first; acb2;
acb2 = acb2->chain.tqe_next)
if (acb2 == acb) {
@ -529,6 +545,21 @@ siop_scsidone(struct siop_acb *acb, int stat)
scsipi_done(xs);
#ifdef PORT_AMIGA
if (sc->sc_channel.chan_flags & SCSIPI_CHAN_RESET_PEND) {
/*
* If reset is pending and there is no current I/O active on
* the channel, then go ahead and reset the channel now.
*/
if ((sc->sc_nexus == NULL) && (sc->nexus_list.tqh_first == NULL)) {
siopreset(sc);
/* Tell scsipi completion thread to restart the queue */
sc->sc_channel.chan_tflags |= SCSIPI_CHANT_KICK;
}
}
#endif
if (dosched && sc->sc_nexus == NULL)
siop_sched(sc);
}
@ -635,10 +666,17 @@ siopinitialize(struct siop_softc *sc)
}
#ifdef PORT_AMIGA
if (sc->sc_nodisconnect) {
/* sc->sc_nodisconnect can be used to prevent SCSI target disconnect */
for (i = 0; i < 8; ++i)
if (sc->sc_nodisconnect & (1 << i))
siop_allow_disc[i] = 0;
}
#endif
if (sc->sc_nosync) {
#ifdef PORT_AMIGA
inhibit_sync = sc->sc_nosync & 0xff;
#else
if (scsi_nosync) {
inhibit_sync = (scsi_nosync >> shift_nosync) & 0xff;
shift_nosync += 8;
#endif
@ -683,8 +721,24 @@ siop_timeout(void *arg)
s = bsd_splbio();
#ifdef PORT_AMIGA
/*
* To prevent clobbering transactions on this channel to other targets
* which have not timed out, we will:
* 1) Mark the channel as pending reset.
* 2) Complete this transaction as XS_TIMEOUT.
* 3) siop_scsidone() will take care of resetting the channel when
* there are no more transactions pending for the channel,
*/
sc->sc_channel.chan_flags |= SCSIPI_CHAN_RESET_PEND;
printf("XS_TIMEOUT %p %p\n", acb, acb->xs);
acb->xs->error = XS_TIMEOUT;
siop_scsidone(acb, acb->stat[0]);
#else
acb->xs->error = XS_TIMEOUT;
siopreset(sc);
#endif
bsd_splx(s);
}
@ -783,6 +837,10 @@ siopreset(struct siop_softc *sc)
}
}
#ifdef PORT_AMIGA
sc->sc_channel.chan_flags &= ~SCSIPI_CHAN_RESET_PEND;
#endif
sc->sc_flags |= SIOP_ALIVE;
sc->sc_flags &= ~(SIOP_INTDEFER|SIOP_INTSOFF);
/* enable SCSI and DMA interrupts */
@ -819,6 +877,9 @@ siop_start(struct siop_softc *sc, int target, int lun, u_char *cbuf, int clen,
printf("siop_start: NULL acb!\n");
return;
}
#if 0
printf("siop_start %d.%d acb=%p xs=%p retries=%d\n", target, lun, acb, acb->xs, acb->xs ? acb->xs->xs_retries : -1);
#endif
#ifdef DEBUG
if (siop_debug & 0x100 && rp->siop_sbcl & SIOP_BSY) {
@ -976,6 +1037,7 @@ siop_start(struct siop_softc *sc, int target, int lun, u_char *cbuf, int clen,
dma_cachectl (buf, len);
#endif
#ifndef PORT_AMIGA
#ifdef DEBUG
if (siop_debug & 0x100 && rp->siop_sbcl & SIOP_BSY) {
printf ("ACK! siop was busy at start: rp %p script %p dsa %p active %ld\n",
@ -985,10 +1047,14 @@ siop_start(struct siop_softc *sc, int target, int lun, u_char *cbuf, int clen,
#endif
siopreset(sc);
}
#endif
#endif
if (sc->nexus_list.tqh_first == NULL) {
#ifndef PORT_AMIGA
/* Callout is now configured for every transaction in siop_sched() */
callout_reset(&acb->xs->xs_callout,
mstohz(acb->xs->timeout) + 1, siop_timeout, acb);
#endif
if (rp->siop_istat & SIOP_ISTAT_CON)
printf("%s: siop_select while connected?\n",
device_xname(sc->sc_dev));
@ -1153,7 +1219,6 @@ siop_checkintr(struct siop_softc *sc, u_char istat, u_char dstat,
int target = 0;
int dfifo, dbc, sstat1;
// printf("CDH: siop_checkintr acb=%p\n", acb);
dfifo = rp->siop_dfifo;
dbc = rp->siop_dbc0;
sstat1 = rp->siop_sstat1;
@ -1176,17 +1241,6 @@ siop_checkintr(struct siop_softc *sc, u_char istat, u_char dstat,
#ifdef DEBUG
++siopints;
#endif
#if 0
/*
* It appears the following code is invalid, as this function might
* be called with acb being NULL, such as the case where an I/O
* has timed out and needs to be restarted.
*/
if (acb == NULL) {
printf("ERROR: siop_checkintr() acb is NULL\n");
goto fail_return;
}
#endif
#ifdef DEBUG
#if 0
if ((siop_debug & 0x100) && (acb != NULL)) {
@ -1465,8 +1519,8 @@ siop_checkintr(struct siop_softc *sc, u_char istat, u_char dstat,
rp->siop_dsps == 0xff02)) {
#ifdef DEBUG
if (siop_debug & 0x100)
printf ("%s: ID %02x disconnected TEMP %lx (+%lx) curbuf %lx curlen %lx buf %p len %lx dfifo %x dbc %x sstat1 %x starts %d acb %p\n",
device_xname(sc->sc_dev), 1 << target, rp->siop_temp,
printf ("%s: TGT %x disconnected TEMP %lx (+%lx) curbuf %lx curlen %lx buf %p len %lx dfifo %x dbc %x sstat1 %x starts %d acb %p\n",
device_xname(sc->sc_dev), target, rp->siop_temp,
rp->siop_temp ? rp->siop_temp - sc->sc_scriptspa : 0,
acb->iob_curbuf, acb->iob_curlen,
acb->ds.chain[0].databuf, acb->ds.chain[0].datalen, dfifo, dbc, sstat1, siopstarts, acb);
@ -1524,8 +1578,8 @@ siop_checkintr(struct siop_softc *sc, u_char istat, u_char dstat,
printf ("%s: adjusting DMA chain\n",
device_xname(sc->sc_dev));
if (rp->siop_dsps == 0xff02)
printf ("%s: ID %02x disconnected without Save Data Pointers\n",
device_xname(sc->sc_dev), 1 << target);
printf ("%s: TGT %x disconnected without Save Data Pointers\n",
device_xname(sc->sc_dev), target);
#endif
/* XXX is: if (rp->siop_dsps != 0xff02) { */
/* not disconnected without save data ptr */
@ -1895,7 +1949,7 @@ siopintr(register struct siop_softc *sc)
printf ("siopintr: status == 0xff\n");
#endif
if ((sc->sc_flags & (SIOP_INTSOFF | SIOP_INTDEFER)) != SIOP_INTSOFF) {
#if 1
#if 0
if (rp->siop_sbcl & SIOP_BSY) {
printf ("%s: SCSI bus busy at completion",
device_xname(sc->sc_dev));

View File

@ -123,8 +123,10 @@ struct siop_tinfo {
struct siop_softc {
device_t sc_dev;
// struct isr sc_isr;
#ifndef PORT_AMIGA
struct isr sc_isr;
void *sc_siop_si;
#endif
u_char sc_istat;
u_char sc_dstat;
@ -141,7 +143,6 @@ struct siop_softc {
u_long sc_scriptspa; /* physical address of scripts */
siop_regmap_p sc_siopp; /* the SIOP */
u_long sc_active; /* number of active I/O's */
u_long sc_nosync; /* no synchronous SCSI (bit / target) */
/* Lists of command blocks */
TAILQ_HEAD(acb_list, siop_acb) free_list,
@ -168,6 +169,10 @@ struct siop_softc {
u_char sc_sien;
#else
u_short sc_sien;
#endif
#ifdef PORT_AMIGA
u_char sc_nosync; /* no synchronous SCSI (bit / target) */
u_char sc_nodisconnect; /* no disconnect SCSI (bit / target) */
#endif
/* one for each target */
struct syncpar {