mirror of
https://github.com/LIV2/a4091-software.git
synced 2025-12-06 06:22:44 +00:00
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:
parent
aff7e8d0c9
commit
110fc9b97a
2
Makefile
2
Makefile
@ -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
40
a4091.c
@ -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
526
a4091d.c
@ -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);
|
||||
}
|
||||
|
||||
43
attach.c
43
attach.c
@ -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);
|
||||
}
|
||||
|
||||
10
attach.h
10
attach.h
@ -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];
|
||||
|
||||
144
cmdhandler.c
144
cmdhandler.c
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
37
device.c
37
device.c
@ -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);
|
||||
}
|
||||
|
||||
6
device.h
6
device.h
@ -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
49
port.c
@ -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
9
port.h
@ -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 */
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
190
scsipi_base.c
190
scsipi_base.c
@ -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;
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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
263
sd.c
@ -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
10
sd.h
@ -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
108
siop.c
@ -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));
|
||||
|
||||
@ -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 {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user