📄 seagate.c
字号:
return retcode (st0x_aborted);#endif DPRINTK (PHASE_SELECTION, "scsi%d : phase = SELECTION\n", hostno); clock = jiffies + ST0X_SELECTION_DELAY;/* * Arbitration/selection procedure : * 1. Disable drivers * 2. Write HOST adapter address bit * 3. Set start arbitration. * 4. We get either ARBITRATION COMPLETE or SELECT at this * point. * 5. OR our ID and targets on bus. * 6. Enable SCSI drivers and asserted SEL and ATTN */#ifdef ARBITRATE save_flags (flags); cli (); WRITE_CONTROL (0); WRITE_DATA ((controller_type == SEAGATE) ? 0x80 : 0x40); WRITE_CONTROL (CMD_START_ARB); restore_flags (flags); ULOOP( ST0X_SELECTION_DELAY * 10000 ) { status_read = STATUS; if (status_read & STAT_ARB_CMPL) break; if (st0x_aborted) /* FIXME: What? We are going to do something even after abort? */ break; if (TIMEOUT || (status_read & STAT_SEL)) { printk( "scsi%d : arbitration lost or timeout.\n", hostno ); WRITE_CONTROL (BASE_CMD); return retcode (DID_NO_CONNECT); } } DPRINTK (PHASE_SELECTION, "scsi%d : arbitration complete\n", hostno);#endif/* * When the SCSI device decides that we're gawking at it, it will * respond by asserting BUSY on the bus. * * Note : the Seagate ST-01/02 product manual says that we should * twiddle the DATA register before the control register. However, * this does not work reliably so we do it the other way around. * * Probably could be a problem with arbitration too, we really should * try this with a SCSI protocol or logic analyzer to see what is * going on. */ tmp_data = (unsigned char) ((1 << target) | (controller_type == SEAGATE ? 0x80 : 0x40)); tmp_control = BASE_CMD | CMD_DRVR_ENABLE | CMD_SEL | (reselect ? CMD_ATTN : 0); save_flags(flags); cli();#ifdef OLDCNTDATASCEME#ifdef SWAPCNTDATA WRITE_CONTROL (tmp_control); WRITE_DATA (tmp_data);#else WRITE_DATA (tmp_data); WRITE_CONTROL (tmp_control);#endif#else tmp_control ^= CMD_BSY; /* This is guesswork. What used to be in driver */ WRITE_CONTROL (tmp_control); /* could never work: it sent data into control */ WRITE_DATA (tmp_data); /* register and control info into data. Hopefully */ tmp_control ^= CMD_BSY; /* fixed, but order of first two may be wrong. */ WRITE_CONTROL (tmp_control); /* -- pavel@ucw.cz */#endif restore_flags (flags); ULOOP( 250*1000 ) { if (st0x_aborted) {/* * 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. */ WRITE_CONTROL (BASE_CMD); if (STATUS & STAT_BSY) { printk ("scsi%d : BST asserted after we've been aborted.\n", hostno); seagate_st0x_reset (NULL, 0); return retcode (DID_RESET); } return retcode (st0x_aborted); } if (STATUS & STAT_BSY) break; if (TIMEOUT) { DPRINTK (PHASE_SELECTION, "scsi%d : NO CONNECT with target %d, stat = %x \n", hostno, target, STATUS); return retcode (DID_NO_CONNECT); } }/* Establish current pointers. Take into account scatter / gather */ if ((nobuffs = SCint->use_sg)) {#if (DEBUG & DEBUG_SG) { int i; printk ("scsi%d : scatter gather requested, using %d buffers.\n", hostno, nobuffs); for (i = 0; i < nobuffs; ++i) printk ("scsi%d : buffer %d address = %08x length = %d\n", hostno, i, buffer[i].address, buffer[i].length); }#endif buffer = (struct scatterlist *) SCint->buffer; len = buffer->length; data = (unsigned char *) buffer->address; } else { DPRINTK (DEBUG_SG, "scsi%d : scatter gather not requested.\n", hostno); buffer = NULL; len = SCint->request_bufflen; data = (unsigned char *) SCint->request_buffer; } DPRINTK (PHASE_DATAIN | PHASE_DATAOUT, "scsi%d : len = %d\n", hostno, len); break;#ifdef LINKED case LINKED_RIGHT: break; case LINKED_WRONG: break;#endif } /* end of switch(reselect) *//* * There are several conditions under which we wish to send a message : * 1. When we are allowing disconnect / reconnect, and need to establish * the I_T_L nexus via an IDENTIFY with the DiscPriv bit set. * * 2. When we are doing linked commands, are have the wrong I_T_L nexus * established and want to send an ABORT message. *//* GCC does not like an ifdef inside a macro, so do it the hard way. */#ifdef LINKED WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | (((reselect == CAN_RECONNECT) || (reselect == LINKED_WRONG) )? CMD_ATTN : 0));#else WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | (((reselect == CAN_RECONNECT) )? CMD_ATTN : 0));#endif/* * 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. * * SJT: The nasty-looking assembler is gone, so it's slower. * */ DPRINTK (PHASE_ETC, "scsi%d : phase = INFORMATION TRANSFER\n", hostno); incommand = 1; transfersize = SCint->transfersize; underflow = SCint->underflow;/* * 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) { printk ("scsi%d : got parity error\n", hostno); st0x_aborted = DID_PARITY; }#endif if (status_read & STAT_REQ) {#if ((DEBUG & PHASE_ETC) == 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 = DID_ERROR; } }#endif switch (status_read & REQ_MASK) { case REQ_DATAOUT:/* * If we are in fast mode, then we simply splat the data out * in word-sized chunks as fast as we can. */ if (!len) {#if 0 printk ("scsi%d: underflow to target %d lun %d \n", hostno, target, lun); st0x_aborted = DID_ERROR; fast = 0;#endif break; } if (fast && transfersize && !(len % transfersize) && (len >= transfersize)#ifdef FAST32 && !(transfersize % 4)#endif ) { DPRINTK (DEBUG_FAST, "scsi%d : FAST transfer, underflow = %d, transfersize = %d\n" " len = %d, data = %08x\n", hostno, SCint->underflow, SCint->transfersize, len, data);/* SJT: Start. Fast Write */#ifdef SEAGATE_USE_ASM __asm__( "cld\n\t"#ifdef FAST32 "shr $2, %%ecx\n\t" "1:\t" "lodsl\n\t" "movl %%eax, (%%edi)\n\t"#else "1:\t" "lodsb\n\t" "movb %%al, (%%edi)\n\t"#endif "loop 1b;"/* output */ :/* input */ : "D" (phys_to_virt(st0x_dr)), "S" (data), "c" (SCint->transfersize) /* clobbered */ : "eax", "ecx", "esi" );#else /* SEAGATE_USE_ASM */ {#ifdef FAST32 unsigned int *iop = phys_to_virt (st0x_dr); const unsigned int *dp = (unsigned int *) data; int xferlen = transfersize >> 2;#else unsigned char *iop = phys_to_virt (st0x_dr); const unsigned char *dp = data; int xferlen = transfersize;#endif for (; xferlen; --xferlen) *iop = *dp++; }#endif /* SEAGATE_USE_ASM *//* SJT: End */ len -= transfersize; data += transfersize; DPRINTK (DEBUG_FAST, "scsi%d : FAST transfer complete len = %d data = %08x\n", hostno, len, data); } else {/* * We loop as long as we are in a data out phase, there is data to send, * and BSY is still active. *//* SJT: Start. Slow Write. */#ifdef SEAGATE_USE_ASM/* * We loop as long as we are in a data out phase, there is data to send, * and BSY is still active. *//* Local variables : len = ecx , data = esi, st0x_cr_sr = ebx, st0x_dr = edi*/ __asm__ ( /* Test for any data here at all. */ "orl %%ecx, %%ecx\n\t" "jz 2f\n\t" "cld\n\t"/* "movl " SYMBOL_NAME_STR(st0x_cr_sr) ", %%ebx\n\t" *//* "movl " SYMBOL_NAME_STR(st0x_dr) ", %%edi\n\t" */ "1:\t" "movb (%%ebx), %%al\n\t" /* Test for BSY */ "test $1, %%al\n\t" "jz 2f\n\t" /* Test for data out phase - STATUS & REQ_MASK should be REQ_DATAOUT, which is 0. */ "test $0xe, %%al\n\t" "jnz 2f\n\t" /* Test for REQ */ "test $0x10, %%al\n\t" "jz 1b\n\t" "lodsb\n\t" "movb %%al, (%%edi)\n\t" "loop 1b\n\t" "2:\n"/* output */ : "=S" (data), "=c" (len) /* input */ : "0" (data), "1" (len), "b" (phys_to_virt(st0x_cr_sr)), "D" (phys_to_virt(st0x_dr)) /* clobbered */ : "eax", "ebx", "edi"); #else /* SEAGATE_USE_ASM */ while (len) { unsigned char stat; stat = STATUS; if (!(stat & STAT_BSY) || ((stat & REQ_MASK) != REQ_DATAOUT)) break; if (stat & STAT_REQ) { WRITE_DATA (*data++); --len; } }#endif /* SEAGATE_USE_ASM *//* SJT: End. */ } if (!len && nobuffs) { --nobuffs; ++buffer; len = buffer->length; data = (unsigned char *) buffer->address; DPRINTK (DEBUG_SG, "scsi%d : next scatter-gather buffer len = %d address = %08x\n", hostno, len, data); } break; case REQ_DATAIN:#ifdef SLOW_RATE if (borken) {#if (DEBUG & (PHASE_DATAIN)) transfered += len;#endif for (; len && (STATUS & (REQ_MASK | STAT_REQ)) == (REQ_DATAIN | STAT_REQ) ; --len) { *data++ = DATA; borken_wait (); }#if (DEBUG & (PHASE_DATAIN)) transfered -= len;#endif } else#endif if (fast && transfersize && !(len % transfersize) && (len >= transfersize)#ifdef FAST32 && !(transfersize % 4)#endif ) { DPRINTK (DEBUG_FAST, "scsi%d : FAST transfer, underflow = %d, transfersize = %d\n" " len = %d, data = %08x\n", hostno, SCint->underflow, SCint->transfersize, len, data);/* SJT: Start. Fast Read */#ifdef SEAGATE_USE_ASM __asm__( "cld\n\t"#ifdef FAST32 "shr $2, %%ecx\n\t" "1:\t" "movl (%%esi), %%eax\n\t" "stosl\n\t"#else "1:\t" "movb (%%esi), %%al\n\t" "stosb\n\t"#endif "loop 1b\n\t"/* output */ : /* input */ : "S" (phys_to_virt(st0x_dr)), "D" (data), "c" (SCint->transfersize) /* clobbered */ : "eax", "ecx", "edi");#else /* SEAGATE_USE_ASM */ {#ifdef FAST32 const unsigned int *iop = phys_to_virt (st0x_dr); unsigned int *dp = (unsigned int *) data; int xferlen = len >> 2;#else const unsigned char *iop = phys_to_virt (st0x_dr); unsigned char *dp = data; int xferlen = len;#endif for (; xferlen; --xferlen) *dp++ = *iop; }#endif /* SEAGATE_USE_ASM *//* SJT: End */ len -= transfersize; data += transfersize;#if (DEBUG & PHASE_DATAIN) printk ("scsi%d: transfered += %d\n", hostno, transfersize); transfered += transfersize;#endif DPRINTK (DEBUG_FAST, "scsi%d : FAST transfer complete len = %d data = %08x\n", hostno, len, data); } else {#if (DEBUG & PHASE_DATAIN) printk ("scsi%d: transfered += %d\n", hostno, len); transfered += len; /* Assume we'll transfer it all, then subtract what we *didn't* transfer */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -