--- linux/kernel/blk_drv/scsi/seagate.c 2018/04/24 18:08:13 1.1.1.1 +++ linux/kernel/blk_drv/scsi/seagate.c 2018/04/24 18:13:41 1.1.1.2 @@ -8,13 +8,19 @@ #include -#ifdef CONFIG_SCSI_SEAGATE +#if defined(CONFIG_SCSI_SEAGATE) || defined(CONFIG_SCSI_FD_88x) +#include +#include #include - #include "seagate.h" #include "scsi.h" #include "hosts.h" +extern void seagate_intr(void); +static int internal_command(unsigned char target, const void *cmnd, + void *buff, int bufflen, int reselect); +void (*do_seagate)(void) = NULL; + static int incommand; /* set if arbitration has finished and we are in some command phase. @@ -27,7 +33,7 @@ static void *base_address = NULL; /* */ static volatile int abort_confirm = 0; -volatile void *st0x_cr_sr; /* +static volatile void *st0x_cr_sr; /* control register write, status register read. 256 bytes in length. @@ -71,9 +77,33 @@ typedef struct } Signature; static const Signature signatures[] = { +#ifdef CONFIG_SCSI_SEAGATE {"SCSI BIOS 2.00 (C) Copyright 1987 Seagate", 15, 40}, + +/* + The following two lines are NOT mistakes. One detects + ROM revision 3.0.0, the other 3.2. Since seagate + has only one type of SCSI adapter, and this is not + going to change, the "SEAGATE" and "SCSI" together + are probably "good enough" +*/ + {"SEAGATE SCSI BIOS ",16, 17}, -{"SEAGATE SCSI BIOS ",17, 17}}; +{"SEAGATE SCSI BIOS ",17, 17}, +#endif + +/* + This is for the Future Domain 88x series. I've been told that + the Seagate controllers are just repackages of these, and seeing + early seagate BIOS bearing the Future Domain copyright, + I believe it. +*/ + +#ifdef CONFIG_SCSI_FD_88x +{"FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/90", 5, 46}, +#endif +} +; /* Note that the last signature handles BIOS revisions 3.0.0 and 3.2 - the real ID's are @@ -86,31 +116,44 @@ SEAGATE SCSI BIOS REVISION 3.2 #define NUM_SIGNATURES (sizeof(signatures) / sizeof(Signature)) #endif +/* + * hostno stores the hostnumber, as told to us by the init routine. + */ + +static int hostno = -1; + int seagate_st0x_detect (int hostnum) { - #ifndef OVERRIDE - int i,j; - #endif +#ifndef OVERRIDE + int i,j; +#endif - /* - First, we try for the manual override. - */ - #ifdef DEBUG - printk("Autodetecting seagate ST0x\n"); - #endif +/* + * First, we try for the manual override. + */ +#ifdef DEBUG + printk("Autodetecting seagate ST0x\n"); +#endif + + if (hostno != -1) + { + printk ("ERROR : seagate_st0x_detect() called twice.\n"); + return 0; + } base_address = NULL; - #ifdef OVERRIDE - base_address = (void *) OVERRIDE; - #ifdef DEBUG - printk("Base address overridden to %x\n", base_address); - #endif - #else - /* - To detect this card, we simply look for the SEAGATE SCSI - from the BIOS version notice in all the possible locations - of the ROM's. - */ +#ifdef OVERRIDE + base_address = (void *) OVERRIDE; +#ifdef DEBUG + printk("Base address overridden to %x\n", base_address); +#endif +#else +/* + * To detect this card, we simply look for the signature + * from the BIOS version notice in all the possible locations + * of the ROM's. This has a nice sideeffect of not trashing + * any register locations that might be used by something else. + */ for (i = 0; i < (sizeof (seagate_bases) / sizeof (char * )); ++i) for (j = 0; !base_address && j < NUM_SIGNATURES; ++j) @@ -118,75 +161,182 @@ int seagate_st0x_detect (int hostnum) signatures[j].offset), (void *) signatures[j].signature, signatures[j].length)) base_address = (void *) seagate_bases[i]; - #endif + #endif if (base_address) { st0x_cr_sr =(void *) (((unsigned char *) base_address) + 0x1a00); st0x_dr = (void *) (((unsigned char *) base_address )+ 0x1c00); - #ifdef DEBUG - printk("ST0x detected. Base address = %x, cr = %x, dr = %x\n", base_address, st0x_cr_sr, st0x_dr); - #endif +#ifdef DEBUG + printk("ST0x detected. Base address = %x, cr = %x, dr = %x\n", base_address, st0x_cr_sr, st0x_dr); +#endif + hostno = hostnum; + +/* + * At all times, we will use IRQ 5. + */ + +#if 1 + set_intr_gate (0x25, seagate_intr); + __asm__(" + inb $0x21, %%al + andb $0xdf, %%al + outb %%al, $0x21"::); +#endif return -1; } else { - #ifdef DEBUG - printk("ST0x not detected.\n"); - #endif +#ifdef DEBUG + printk("ST0x not detected.\n"); +#endif return 0; } } - - char *seagate_st0x_info(void) { static char buffer[] = "Seagate ST-0X SCSI driver by Drew Eckhardt \n" -"$Header: /var/lib/cvsd/linux/linux/kernel/blk_drv/scsi/seagate.c,v 1.1.1.1 2018/04/24 18:08:13 root Exp $\n"; +"$Header: /var/lib/cvsd/linux/linux/kernel/blk_drv/scsi/seagate.c,v 1.1.1.2 2018/04/24 18:13:41 root Exp $\n"; return buffer; } +/* + * These are our saved pointers for the outstanding command that is + * waiting for a reconnect + */ + +static unsigned char current_target; +static unsigned char *current_cmnd, *current_data; +static int current_bufflen; +static void (*done_fn)(int, int) = NULL; + +/* + * These control weather or not disconnect / reconnect will be attempted, + * or are being attempted. + */ + +#define NO_RECONNECT 0 +#define RECONNECT_NOW 1 +#define CAN_RECONNECT 2 + +/* + * This determines if we are expecting to reconnect or not. + */ + +static int should_reconnect = 0; +void seagate_unexpected_intr (void) + { + printk("scsi%d: unexpected interrupt.\n", hostno); + } + +/* + * The seagate_reconnect_intr routine is called when a target reselects the + * host adapter. This occurs on the interrupt triggered by the target + * asserting SEL. + */ -int seagate_st0x_command(unsigned char target, const void *cmnd, - void *buff, int bufflen) +void seagate_reconnect_intr (void) + { + int temp; + +#if (DEBUG & PHASE_RESELECT) + printk("scsi%d : seagate_reconnect_intr() called\n", hostno); +#endif + + if (!should_reconnect) + seagate_unexpected_intr(); + else + { + should_reconnect = 0; + +#if (DEBUG & PHASE_RESELECT) + printk("scsi%d : internal_command(" + "%d, %08x, %08x, %d, RECONNECT_NOW\n", hostno, + current_target, current_data, current_bufflen); +#endif + + temp = internal_command (current_target, + current_cmnd, current_data, current_bufflen, + RECONNECT_NOW); + + if (msg_byte(temp) != DISCONNECT) + { + if (done_fn) + { +#if (DEBUG & PHASE_RESELECT) + printk("scsi%d : done_fn(%d,%08x)", hostno, + hostno, temp); +#endif + done_fn (hostno, temp); + } + else + printk("done_fn() not defined.\n"); + } + } + } + +/* + * The seagate_st0x_queue_command() function provides a queued interface + * to the seagate SCSI driver. Basically, it just passes control onto the + * seagate_command() function, after fixing it so that the done_fn() + * is set to the one passed to the function. + */ + +int seagate_st0x_queue_command (unsigned char target, const void *cmnd, + void *buff, int bufflen, void (*fn)(int, + int)) + { + int result; + + done_fn = fn; + current_target = target; + (const void *) current_cmnd = cmnd; + current_data = buff; + current_bufflen = bufflen; + + result = internal_command (target, cmnd, buff, bufflen, + CAN_RECONNECT); + if (msg_byte(result) == DISCONNECT) + return 0; + else + { + done_fn (hostno, result); + return 1; + } + } + +int seagate_st0x_command (unsigned char target, const void *cmnd, + void *buff, int bufflen) + { + return internal_command (target, cmnd, buff, bufflen, + (int) NO_RECONNECT); + } + +static int internal_command(unsigned char target, const void *cmnd, + void *buff, int bufflen, int reselect) { int len; unsigned char *data; + int clock; + int temp; - int clock; /* - We use clock for timeouts, etc. This replaces the - seagate_st0x_timeout that we had been using. - */ - #if (DEBUG & PHASE_SELECTION) - int temp; - #endif - - #if (DEBUG & PHASE_EXIT) - void *retaddr, *realretaddr; - #endif - - #if ((DEBUG & PHASE_ETC) || (DEBUG & PRINT_COMMAND) || (DEBUG & PHASE_EXIT)) - int i; - #endif - - #if (DEBUG & PHASE_ETC) - int phase=0, newphase; - #endif + +#if ((DEBUG & PHASE_ETC) || (DEBUG & PRINT_COMMAND) || (DEBUG & PHASE_EXIT)) + int i; +#endif + +#if (DEBUG & PHASE_ETC) + int phase=0, newphase; +#endif int done = 0; unsigned char status = 0; unsigned char message = 0; register unsigned char status_read; - #if (DEBUG & PHASE_EXIT) - __asm__(" -movl 4(%%ebp), %%eax -":"=a" (realretaddr):); - printk("return address = %08x\n", realretaddr); - #endif - + do_seagate = seagate_unexpected_intr; len=bufflen; data=(unsigned char *) buff; @@ -194,73 +344,201 @@ movl 4(%%ebp), %%eax incommand = 0; st0x_aborted = 0; - #if (DEBUG & PRINT_COMMAND) - printk ("seagate_st0x_command, target = %d, command = ", target); - for (i = 0; i < COMMAND_SIZE(((unsigned char *)cmnd)[0]); ++i) - printk("%02x ", ((unsigned char *) cmnd)[i]); - printk("\n"); - #endif +#if (DEBUG & PRINT_COMMAND) + printk ("scsi%d : target = %d, command = ", hostno, target); + for (i = 0; i < COMMAND_SIZE(((unsigned char *)cmnd)[0]); ++i) + printk("%02x ", ((unsigned char *) cmnd)[i]); + printk("\n"); +#endif + +#if (DEBUG & PHASE_RESELECT) + switch (reselect) + { + case RECONNECT_NOW : + printk("scsi%d : reconnecting\n", hostno); + break; + case CAN_RECONNECT : + printk("scsi%d : allowed to reconnect\n", hostno); + break; + default : + printk("scsi%d : not allowed to reconnect\n", hostno); + } +#endif + if (target > 6) + { + if (reselect == RECONNECT_NOW) + eoi(); return DID_BAD_TARGET; + } - - #if (DEBUG & PHASE_BUS_FREE) - printk ("SCSI PHASE = BUS FREE \n"); - #endif +/* + * We work it differently depending on if this is is "the first time," + * or a reconnect. If this is a reselct phase, then SEL will + * be asserted, and we must skip selection / arbitration phases. + */ - /* + if (reselect == RECONNECT_NOW) + { +#if (DEBUG & PHASE_RESELECT) + printk("scsi%d : phase RESELECT \n", hostno); +#endif - BUS FREE PHASE +/* + * At this point, we should find the logical or of our ID and the original + * target's ID on the BUS, with BSY, SEL, and I/O signals asserted. + * + * After ARBITRATION phase is completed, only SEL, BSY, and the + * target ID are asserted. A valid initator ID is not on the bus + * until IO is asserted, so we must wait for that. + */ + + for (clock = jiffies + 10, temp = 0; (jiffies < clock) && + !(STATUS & STAT_IO);); + + if (jiffies >= clock) + { +#if (DEBUG & PHASE_RESELECT) + printk("scsi%d : RESELECT timed out while waiting for IO .\n", + hostno); +#endif + eoi(); + return (DID_BAD_INTR << 16); + } - On entry, we make sure that the BUS is in a BUS FREE - phase, by insuring that both BSY and SEL are low for - at least one bus settle delay. The standard requires a - minimum of 400 ns, which is 16 clock cycles on a - 386-40 . +/* + * After I/O is asserted by the target, we can read our ID and its + * ID off of the BUS. + */ + + if (!((temp = DATA) & 0x80)) + { +#if (DEBUG & PHASE_RESELECT) + printk("scsi%d : detected reconnect request to different target.\n" + "\tData bus = %d\n", hostno, temp); +#endif + eoi(); + return (DID_BAD_INTR << 16); + } - This doesn't give us much time - so we'll do two several - reads to be sure be sure. - */ + if (!(temp & (1 << current_target))) + { + printk("scsi%d : Unexpected reselect interrupt. Data bus = %d\n", + hostno, temp); + eoi(); + return (DID_BAD_INTR << 16); + } + data=current_data; /* WDE add */ + cmnd=current_cmnd; /* WDE add */ + len=current_bufflen; /* WDE add */ - clock = jiffies + ST0X_BUS_FREE_DELAY; +/* + * We have determined that we have been selected. At this point, + * we must respond to the reselection by asserting BSY ourselves + */ - while (((STATUS | STATUS | STATUS) & - (STAT_BSY | STAT_SEL)) && - (!st0x_aborted) && (jiffies < clock)); - - if (jiffies > clock) - return retcode(DID_BUS_BUSY); - else if (st0x_aborted) - return retcode(st0x_aborted); + CONTROL = (BASE_CMD | CMD_DRVR_ENABLE | CMD_BSY); - /* - Bus free has been detected, within BUS settle. I used to support an arbitration - phase - however, on the seagate, this degraded performance by a factor > 10 - so - it is no more. - */ +/* + * The target will drop SEL, and raise BSY, at which time we must drop + * BSY. + */ + + for (clock = jiffies + 10; (jiffies < clock) && (STATUS & STAT_SEL);); + + if (jiffies >= clock) + { + CONTROL = (BASE_CMD | CMD_INTR); +#if (DEBUG & PHASE_RESELECT) + printk("scsi%d : RESELECT timed out while waiting for SEL.\n", + hostno); +#endif + eoi(); + return (DID_BAD_INTR << 16); + } - /* - SELECTION PHASE + CONTROL = BASE_CMD; - Now, we select the disk, giving it the SCSI ID at data - and a command of PARITY if necessary, plus driver enable, - plus raise select signal. - */ +/* + * At this point, we have connected with the target and can get + * on with our lives. + */ + eoi(); + } + else + { +#if (DEBUG & PHASE_BUS_FREE) + printk ("scsi%d : phase = BUS FREE \n", hostno); +#endif - #if (DEBUG & PHASE_SELECTION) - printk("SCSI PHASE = SELECTION\n"); - #endif +/* + * BUS FREE PHASE + * + * On entry, we make sure that the BUS is in a BUS FREE + * phase, by insuring that both BSY and SEL are low for + * at least one bus settle delay. Several reads help + * eliminate wire glitch. + */ + + clock = jiffies + ST0X_BUS_FREE_DELAY; + + while (((STATUS | STATUS | STATUS) & + (STAT_BSY | STAT_SEL)) && + (!st0x_aborted) && (jiffies < clock)); + + if (jiffies > clock) + return retcode(DID_BUS_BUSY); + else if (st0x_aborted) + return retcode(st0x_aborted); - clock = jiffies + ST0X_SELECTION_DELAY; - DATA = (unsigned char) (1 << target); +/* + * Bus free has been detected, within BUS settle. I used to + * support an arbitration phase - however, on the Seagate, this + * degraded performance by a factor > 10 - so it is no more. + */ - CONTROL = BASE_CMD | CMD_DRVR_ENABLE | CMD_SEL; +/* + * SELECTION PHASE + * + * Now, we select the disk, giving it the SCSI ID at data + * and a command of PARITY if necessary, and we raise SEL. + */ - /* - When the SCSI device decides that we're gawking at it, it will respond by asserting BUSY on the bus. - */ - while (!((status_read = STATUS) & STAT_BSY) && (jiffies < clock) && !st0x_aborted) +#if (DEBUG & PHASE_SELECTION) + printk("scsi%d : phase = SELECTION\n", hostno); +#endif + + clock = jiffies + ST0X_SELECTION_DELAY; + +/* + * If we wish to disconnect, we should request a MESSAGE OUT + * at this point. Technically, ATTN should be raised before + * SEL = true and BSY = false (from arbitration), but I think this + * should do. + */ + if (reselect) + CONTROL = BASE_CMD | CMD_DRVR_ENABLE | + CMD_ATTN; + +/* + * We must assert both our ID and our target's ID on the bus. + */ + DATA = (unsigned char) ((1 << target) | 0x80); + +/* + * If we are allowing ourselves to reconnect, then I will keep + * ATTN raised so we get MSG OUT. + */ + CONTROL = BASE_CMD | CMD_DRVR_ENABLE | CMD_SEL | + (reselect ? CMD_ATTN : 0); + +/* + * When the SCSI device decides that we're gawking at it, it will + * respond by asserting BUSY on the bus. + */ + while (!((status_read = STATUS) & STAT_BSY) && + (jiffies < clock) && !st0x_aborted) #if (DEBUG & PHASE_SELECTION) { @@ -271,110 +549,128 @@ movl 4(%%ebp), %%eax } printk("Done. \n\r"); - printk("Status = %02x, seagate_st0x_timeout = %d, aborted = %02x \n", status_read, temp, - st0x_aborted); + printk("scsi%d : status = %02x, seagate_st0x_timeout = %d, aborted = %02x \n", + hostno, status_read, temp, st0x_aborted); #else ; #endif - if ((jiffies > clock) || (!st0x_aborted & !(status_read & STAT_BSY))) - { - #if (DEBUG & PHASE_SELECT) - printk ("NO CONNECT with target %d, status = %x \n", target, STATUS); - #endif - return retcode(DID_NO_CONNECT); - } - - /* - If we have been aborted, and we have a command in progress, IE the target still has - BSY asserted, then we will reset the bus, and notify the midlevel driver to - expect sense. - */ - - if (st0x_aborted) - { - CONTROL = BASE_CMD; - if (STATUS & STAT_BSY) + if ((jiffies > clock) || (!st0x_aborted && + !(status_read & STAT_BSY))) { - seagate_st0x_reset(); - return retcode(DID_RESET); +#if (DEBUG & PHASE_SELECT) + printk ("scsi%d : NO CONNECT with target %d, status = %x \n", + hostno, target, STATUS); +#endif + return retcode(DID_NO_CONNECT); } - - return retcode(st0x_aborted); - } - - /* - COMMAND PHASE - The device has responded with a BSY, so we may now enter - the information transfer phase, where we will send / recieve - data and command as directed by the target. +/* + * If we have been aborted, and we have a command in progress, IE the + * target still has BSY asserted, then we will reset the bus, and + * notify the midlevel driver to expect sense. + */ - The nasty looking read / write inline assembler loops we use for - DATAIN and DATAOUT phases are approximately 4-5 times as fast as - the 'C' versions - since we're moving 1024 bytes of data, this - really adds up. - */ + if (st0x_aborted) + { + CONTROL = BASE_CMD; + if (STATUS & STAT_BSY) + { + seagate_st0x_reset(); + return retcode(DID_RESET); + } + return retcode(st0x_aborted); + } + } - #if (DEBUG & PHASE_ETC) - printk("PHASE = information transfer\n"); - #endif + CONTROL = BASE_CMD | CMD_DRVR_ENABLE | + ((reselect == CAN_RECONNECT) ? CMD_ATTN : 0) ; + +/* + * INFORMATION TRANSFER PHASE + * + * The nasty looking read / write inline assembler loops we use for + * DATAIN and DATAOUT phases are approximately 4-5 times as fast as + * the 'C' versions - since we're moving 1024 bytes of data, this + * really adds up. + */ + +#if (DEBUG & PHASE_ETC) + printk("scsi%d : phase = INFORMATION TRANSFER\n", hostno); +#endif incommand = 1; - /* - Enable command - */ - - CONTROL = BASE_CMD | CMD_DRVR_ENABLE; - /* - Now, we poll the device for status information, - and handle any requests it makes. Note that since we are unsure of - how much data will be flowing across the system, etc and cannot - make reasonable timeouts, that we will instead have the midlevel - driver handle any timeouts that occur in this phase. - */ +/* + * Now, we poll the device for status information, + * and handle any requests it makes. Note that since we are unsure of + * how much data will be flowing across the system, etc and cannot + * make reasonable timeouts, that we will instead have the midlevel + * driver handle any timeouts that occur in this phase. + */ while (((status_read = STATUS) & STAT_BSY) && !st0x_aborted && !done) + { +#ifdef PARITY + if (status_read & STAT_PARITY) { - #ifdef PARITY - if (status_read & STAT_PARITY) - { - done = 1; - st0x_aborted = DID_PARITY; - } - #endif + done = 1; + st0x_aborted = DID_PARITY; + } +#endif - if (status_read & STAT_REQ) + if (status_read & STAT_REQ) + { +#if (DEBUG & PHASE_ETC) + if ((newphase = (status_read & REQ_MASK)) != phase) { - #if (DEBUG & PHASE_ETC) - if ((newphase = (status_read & REQ_MASK)) != phase) - { - phase = newphase; - switch (phase) - { - case REQ_DATAOUT : printk("SCSI PHASE = DATA OUT\n"); break; - case REQ_DATAIN : printk("SCSI PHASE = DATA IN\n"); break; - case REQ_CMDOUT : printk("SCSI PHASE = COMMAND OUT\n"); break; - case REQ_STATIN : printk("SCSI PHASE = STATUS IN\n"); break; - case REQ_MSGOUT : printk("SCSI PHASE = MESSAGE OUT\n"); break; - case REQ_MSGIN : printk("SCSI PHASE = MESSAGE IN\n"); break; - default : printk("UNKNOWN PHASE"); st0x_aborted = 1; done = 1; - } - } - #endif - - switch (status_read & REQ_MASK) - { - case REQ_DATAOUT : + phase = newphase; + switch (phase) + { + case REQ_DATAOUT: + printk("scsi%d : phase = DATA OUT\n", + hostno); + break; + case REQ_DATAIN : + printk("scsi%d : phase = DATA IN\n", + hostno); + break; + case REQ_CMDOUT : + printk("scsi%d : phase = COMMAND OUT\n", + hostno); + break; + case REQ_STATIN : + printk("scsi%d : phase = STATUS IN\n", + hostno); + break; + case REQ_MSGOUT : + printk("scsi%d : phase = MESSAGE OUT\n", + hostno); + break; + case REQ_MSGIN : + printk("scsi%d : phase = MESSAGE IN\n", + hostno); + break; + default : + printk("scsi%d : phase = UNKNOWN\n", + hostno); + st0x_aborted = 1; + done = 1; + } + } +#endif - /* - We loop as long as we are in a data out phase, there is data to send, and BSY is still - active - */ - __asm__ (" + switch (status_read & REQ_MASK) + { + case REQ_DATAOUT : + +/* + * We loop as long as we are in a data out phase, there is data to send, + * and BSY is still active. + */ + __asm__ (" /* Local variables : @@ -428,15 +724,15 @@ movl 4(%%ebp), %%eax /* clobbered */ "ebx", "ecx", "edi", "esi"); - break; + break; - case REQ_DATAIN : - /* - We loop as long as we are in a data out phase, there is room to read, and BSY is still - active - */ + case REQ_DATAIN : +/* + * We loop as long as we are in a data in phase, there is room to read, + * and BSY is still active + */ - __asm__ (" + __asm__ (" /* Local variables : ecx = len @@ -491,71 +787,153 @@ movl 4(%%ebp), %%eax "0" (data), "1" (len) : /* clobbered */ "ebx", "ecx", "edi", "esi"); - break; + break; - case REQ_CMDOUT : - while (((status_read = STATUS) & STAT_BSY) && ((status_read & REQ_MASK) == - REQ_CMDOUT)) - DATA = *(unsigned char *) cmnd ++; - break; - - case REQ_STATIN : - status = DATA; - break; + case REQ_CMDOUT : + while (((status_read = STATUS) & STAT_BSY) && + ((status_read & REQ_MASK) == REQ_CMDOUT)) + if (status_read & STAT_REQ) + DATA = *(unsigned char *) cmnd ++; + break; + + case REQ_STATIN : + status = DATA; + break; + + case REQ_MSGOUT : +/* + * We can only have sent a MSG OUT if we requested to do this + * by raising ATTN. So, we must drop ATTN. + */ + + CONTROL = BASE_CMD | CMD_DRVR_ENABLE; +/* + * If we are reconecting, then we must send an IDENTIFY message in + * response to MSGOUT. + */ + if (reselect) + { + DATA = IDENTIFY(1,0); +#if (DEBUG & (PHASE_RESELECT | PHASE_MSGOUT)) + printk("scsi%d : sent IDENTIFY message.\n", hostno); +#endif + } + else + { + DATA = MESSAGE_REJECT; - case REQ_MSGOUT : - DATA = MESSAGE_REJECT; - break; +#if (DEBUG & PHASE_MSGOUT) + printk("scsi%d : sent MESSAGE REJECT message.\n", hostno); +#endif + } + break; - case REQ_MSGIN : - if ((message = DATA) == COMMAND_COMPLETE) - done=1; - - break; + case REQ_MSGIN : + switch (message = DATA) + { + case DISCONNECT : + should_reconnect = 1; + current_data = data; /* WDE add */ + current_bufflen = len; /* WDE add */ +#if (DEBUG & (PHASE_RESELECT | PHASE_MSGIN)) + printk("scsi%d : disconnected.\n", hostno); + done=1; + break; +#endif + case COMMAND_COMPLETE : +#if (DEBUG & PHASE_MSGIN) + printk("scsi%d : command complete.\n", hostno); + done=1; + break; +#endif + case ABORT : +#if (DEBUG & PHASE_MSGIN) + printk("scsi%d : abort message.\n", hostno); +#endif + done=1; + break; + case SAVE_POINTERS : + current_data = data; /* WDE mod */ + current_bufflen = len; /* WDE add */ +#if (DEBUG & PHASE_MSGIN) + printk("scsi%d : pointers saved.\n", hostno); +#endif + break; + case RESTORE_POINTERS: + data=current_data; /* WDE mod */ + cmnd=current_cmnd; +#if (DEBUG & PHASE_MSGIN) + printk("scsi%d : pointers restored.\n", hostno); +#endif + break; + default: - default : printk("UNKNOWN PHASE"); st0x_aborted = DID_ERROR; +/* + * IDENTIFY distinguishes itself from the other messages by setting the + * high byte. + */ + + if (message & 0x80) + { +#if (DEBUG & PHASE_MSGIN) + printk("scsi%d : IDENTIFY message received from id %d, lun %d.\n", + hostno, target, message & 7); +#endif } - } + else + { + +#if (DEBUG & PHASE_MSGIN) + printk("scsi%d : unknown message %d from target %d.\n", + hostno, message, target); +#endif + } + } + break; - } + default : + printk("scsi%d : unknown phase.\n", hostno); + st0x_aborted = DID_ERROR; + } + } /* while ends */ + } /* if ends */ #if (DEBUG & (PHASE_DATAIN | PHASE_DATAOUT | PHASE_EXIT)) printk("Transfered %d bytes, allowed %d additional bytes\n", (bufflen - len), len); #endif #if (DEBUG & PHASE_EXIT) - printk("Buffer : \n"); - for (i = 0; i < 20; ++i) - printk ("%02x ", ((unsigned char *) buff)[i]); - printk("\n"); - printk("Status = %02x, message = %02x\n", status, message); + printk("Buffer : \n"); + for (i = 0; i < 20; ++i) + printk ("%02x ", ((unsigned char *) data)[i]); /* WDE mod */ + printk("\n"); + printk("Status = %02x, message = %02x\n", status, message); #endif - if (st0x_aborted) + if (st0x_aborted) + { + if (STATUS & STAT_BSY) { - if (STATUS & STAT_BSY) - { - seagate_st0x_reset(); - st0x_aborted = DID_RESET; - } - abort_confirm = 1; - } - - CONTROL = BASE_CMD; - -#if (DEBUG & PHASE_EXIT) - __asm__(" -mov 4(%%ebp), %%eax -":"=a" (retaddr):); + seagate_st0x_reset(); + st0x_aborted = DID_RESET; + } + abort_confirm = 1; + } - printk("Exiting seagate_st0x_command() - return address is %08x \n", retaddr); - if (retaddr != realretaddr) - panic ("Corrupted stack : return address on entry != return address on exit.\n"); - + if (should_reconnect) + { +#if (DEBUG & PHASE_RESELECT) + printk("scsi%d : exiting seagate_st0x_queue_command() with reconnect enabled.\n", + hostno); #endif + do_seagate = seagate_reconnect_intr; + CONTROL = BASE_CMD | CMD_INTR ; + } + else + CONTROL = BASE_CMD; - return retcode (st0x_aborted); + return retcode (st0x_aborted); } int seagate_st0x_abort (int code) @@ -604,4 +982,6 @@ int seagate_st0x_reset (void) #endif return 0; } + #endif +