📄 seagate.c
字号:
* degraded performance by a factor > 10 - so it is no more. *//* * 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. */#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) { temp = clock - jiffies; if (!(jiffies % 5)) printk("seagate_st0x_timeout : %d \r",temp); } printk("Done. \n\r"); 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 ("scsi%d : NO CONNECT with target %d, status = %x \n", hostno, 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) { seagate_st0x_reset(); return retcode(DID_RESET); } return retcode(st0x_aborted); } } 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;/* * 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) { done = 1; st0x_aborted = DID_PARITY; } #endif if (status_read & STAT_REQ) {#if (DEBUG & PHASE_ETC) if ((newphase = (status_read & REQ_MASK)) != phase) { 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 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 : len = ecx data = esi st0x_cr_sr = ebx st0x_dr = edi Test for any data here at all.*/ "movl %0, %%esi\n" /* local value of data */ "\tmovl %1, %%ecx\n" /* local value of len */ "\torl %%ecx, %%ecx jz 2f cld movl _st0x_cr_sr, %%ebx movl _st0x_dr, %%edi 1: movb (%%ebx), %%al\n"/* Test for BSY*/ "\ttest $1, %%al jz 2f\n"/* Test for data out phase - STATUS & REQ_MASK should be REQ_DATAOUT, which is 0.*/ "\ttest $0xe, %%al jnz 2f \n"/* Test for REQ*/ "\ttest $0x10, %%al jz 1b lodsb movb %%al, (%%edi) loop 1b2: movl %%esi, %2 movl %%ecx, %3 ":/* output */"=r" (data), "=r" (len) :/* input */"0" (data), "1" (len) :/* clobbered */"ebx", "ecx", "edi", "esi"); break; 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__ (/* Local variables : ecx = len edi = data esi = st0x_cr_sr ebx = st0x_dr Test for room to read*/ "movl %0, %%edi\n" /* data */ "\tmovl %1, %%ecx\n" /* len */ "\torl %%ecx, %%ecx jz 2f cld movl _st0x_cr_sr, %%esi movl _st0x_dr, %%ebx1: movb (%%esi), %%al\n"/* Test for BSY*/ "\ttest $1, %%al jz 2f\n"/* Test for data in phase - STATUS & REQ_MASK should be REQ_DATAIN, = STAT_IO, which is 4.*/ "\tmovb $0xe, %%ah andb %%al, %%ah cmpb $0x04, %%ah jne 2f\n" /* Test for REQ*/ "\ttest $0x10, %%al jz 1b movb (%%ebx), %%al stosb loop 1b2: movl %%edi, %2\n" /* data */ "\tmovl %%ecx, %3\n" /* len */ :/* output */"=r" (data), "=r" (len) :/* input */"0" (data), "1" (len) :/* clobbered */"ebx", "ecx", "edi", "esi"); 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, lun);#if (DEBUG & (PHASE_RESELECT | PHASE_MSGOUT)) printk("scsi%d : sent IDENTIFY message.\n", hostno);#endif } else { DATA = MESSAGE_REJECT; #if (DEBUG & PHASE_MSGOUT) printk("scsi%d : sent MESSAGE REJECT message.\n", hostno);#endif } 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:/* * 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 *) data)[i]); /* WDE mod */ printk("\n"); printk("Status = %02x, message = %02x\n", status, message);#endif if (st0x_aborted) { if (STATUS & STAT_BSY) { seagate_st0x_reset(); st0x_aborted = DID_RESET; } abort_confirm = 1; } if (should_reconnect) {#if (DEBUG & PHASE_RESELECT) printk("scsi%d : exiting seagate_st0x_queue_command() with reconnect enabled.\n", hostno);#endif CONTROL = BASE_CMD | CMD_INTR ; } else CONTROL = BASE_CMD; return retcode (st0x_aborted); }int seagate_st0x_abort (Scsi_Cmnd * SCpnt, int code) { if (code) st0x_aborted = code; else st0x_aborted = DID_ABORT; return 0; }/* the seagate_st0x_reset function resets the SCSI bus*/ int seagate_st0x_reset (void) { unsigned clock; /* No timeouts - this command is going to fail because it was reset. */#ifdef DEBUG printk("In seagate_st0x_reset()\n");#endif /* assert RESET signal on SCSI bus. */ CONTROL = BASE_CMD | CMD_RST; clock=jiffies+2; /* Wait. */ while (jiffies < clock); CONTROL = BASE_CMD; st0x_aborted = DID_RESET;#ifdef DEBUG printk("SCSI bus reset.\n");#endif return 0; }#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -