📄 seagate.c
字号:
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 */#endif/* * We loop as long as we are in a data in phase, there is room to read, * and BSY is still active *//* SJT: Start. */#ifdef SEAGATE_USE_ASMint __dummy_3,__dummy_4;/* Dummy clobbering variables for the new gcc-2.95 *//* * We loop as long as we are in a data in phase, there is room to read, * and BSY is still active */ /* Local variables : ecx = len, edi = data esi = st0x_cr_sr, ebx = st0x_dr */ __asm__ ( /* Test for room to read */ "orl %%ecx, %%ecx\n\t" "jz 2f\n\t" "cld\n\t"/* "movl " SYMBOL_NAME_STR(st0x_cr_sr) ", %%esi\n\t" *//* "movl " SYMBOL_NAME_STR(st0x_dr) ", %%ebx\n\t" */ "1:\t" "movb (%%esi), %%al\n\t" /* Test for BSY */ "test $1, %%al\n\t" "jz 2f\n\t" /* Test for data in phase - STATUS & REQ_MASK should be REQ_DATAIN, = STAT_IO, which is 4. */ "movb $0xe, %%ah\n\t" "andb %%al, %%ah\n\t" "cmpb $0x04, %%ah\n\t" "jne 2f\n\t" /* Test for REQ */ "test $0x10, %%al\n\t" "jz 1b\n\t" "movb (%%ebx), %%al\n\t" "stosb\n\t" "loop 1b\n\t" "2:\n"/* output */ : "=D" (data), "=c" (len) ,"=S" (__dummy_3) ,"=b" (__dummy_4)/* input */ : "0" (data), "1" (len), "2" (phys_to_virt(st0x_cr_sr)), "3" (phys_to_virt(st0x_dr)) /* clobbered */ : "eax" ); #else /* SEAGATE_USE_ASM */ while (len) { unsigned char stat; stat = STATUS; if (!(stat & STAT_BSY) || ((stat & REQ_MASK) != REQ_DATAIN)) break; if (stat & STAT_REQ) { *data++ = DATA; --len; } }#endif /* SEAGATE_USE_ASM *//* SJT: End. */#if (DEBUG & PHASE_DATAIN) printk ("scsi%d: transfered -= %d\n", hostno, len); transfered -= len; /* Since we assumed all of Len got * transfered, correct our mistake */#endif } 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_CMDOUT: while (((status_read = STATUS) & STAT_BSY) && ((status_read & REQ_MASK) == REQ_CMDOUT)) if (status_read & STAT_REQ) { WRITE_DATA (*(const unsigned char *) cmnd); cmnd = 1 + (const unsigned char *) cmnd;#ifdef SLOW_RATE if (borken) borken_wait ();#endif } 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. */ WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE);/* * If we are reconnecting, then we must send an IDENTIFY message in * response to MSGOUT. */ switch (reselect) { case CAN_RECONNECT: WRITE_DATA (IDENTIFY (1, lun)); DPRINTK (PHASE_RESELECT | PHASE_MSGOUT, "scsi%d : sent IDENTIFY message.\n", hostno); break;#ifdef LINKED case LINKED_WRONG: WRITE_DATA (ABORT); linked_connected = 0; reselect = CAN_RECONNECT; goto connect_loop; DPRINTK (PHASE_MSGOUT | DEBUG_LINKED, "scsi%d : sent ABORT message to cancel incorrect I_T_L nexus.\n", hostno);#endif /* LINKED */ DPRINTK (DEBUG_LINKED, "correct\n"); default: WRITE_DATA (NOP); printk ("scsi%d : target %d requested MSGOUT, sent NOP message.\n", hostno, target); } break; case REQ_MSGIN: switch (message = DATA) { case DISCONNECT: DANY ("seagate: deciding to disconnect\n"); should_reconnect = 1; current_data = data; /* WDE add */ current_buffer = buffer; current_bufflen = len; /* WDE add */ current_nobuffs = nobuffs;#ifdef LINKED linked_connected = 0;#endif done = 1; DPRINTK ((PHASE_RESELECT | PHASE_MSGIN), "scsi%d : disconnected.\n", hostno); break;#ifdef LINKED case LINKED_CMD_COMPLETE: case LINKED_FLG_CMD_COMPLETE:#endif case COMMAND_COMPLETE:/* * Note : we should check for underflow here. */ DPRINTK (PHASE_MSGIN, "scsi%d : command complete.\n", hostno); done = 1; break; case ABORT: DPRINTK (PHASE_MSGIN, "scsi%d : abort message.\n", hostno); done = 1; break; case SAVE_POINTERS: current_buffer = buffer; current_bufflen = len; /* WDE add */ current_data = data; /* WDE mod */ current_nobuffs = nobuffs; DPRINTK (PHASE_MSGIN, "scsi%d : pointers saved.\n", hostno); break; case RESTORE_POINTERS: buffer = current_buffer; cmnd = current_cmnd; data = current_data; /* WDE mod */ len = current_bufflen; nobuffs = current_nobuffs; DPRINTK (PHASE_MSGIN, "scsi%d : pointers restored.\n", hostno); break; default:/* * IDENTIFY distinguishes itself from the other messages by setting the * high byte. [FIXME: should not this read "the high bit"? - pavel@ucw.cz] * * Note : we need to handle at least one outstanding command per LUN, * and need to hash the SCSI command for that I_T_L nexus based on the * known ID (at this point) and LUN. */ if (message & 0x80) { DPRINTK (PHASE_MSGIN, "scsi%d : IDENTIFY message received from id %d, lun %d.\n", hostno, target, message & 7); } else {/* * We should go into a MESSAGE OUT phase, and send a MESSAGE_REJECT * if we run into a message that we don't like. The seagate driver * needs some serious restructuring first though. */ DPRINTK (PHASE_MSGIN, "scsi%d : unknown message %d from target %d.\n", hostno, message, target); } } break; default: printk ("scsi%d : unknown phase.\n", hostno); st0x_aborted = DID_ERROR; } /* end of switch (status_read & REQ_MASK) */#ifdef SLOW_RATE/* * I really don't care to deal with borken devices in each single * byte transfer case (ie, message in, message out, status), so * I'll do the wait here if necessary. */ if (borken) borken_wait ();#endif } /* if(status_read & STAT_REQ) ends */ } /* while(((status_read = STATUS)...) ends */ DPRINTK (PHASE_DATAIN | PHASE_DATAOUT | PHASE_EXIT, "scsi%d : Transfered %d bytes\n", hostno, transfered);#if (DEBUG & PHASE_EXIT)#if 0 /* Doesn't work for scatter/gather */ printk ("Buffer : \n"); for (i = 0; i < 20; ++i) printk ("%02x ", ((unsigned char *) data)[i]); /* WDE mod */ printk ("\n");#endif printk ("scsi%d : status = ", hostno); print_status (status); printk ("message = %02x\n", message);#endif/* We shouldn't reach this until *after* BSY has been deasserted */#ifdef LINKED else {/* * Fix the message byte so that unsuspecting high level drivers don't * puke when they see a LINKED COMMAND message in place of the COMMAND * COMPLETE they may be expecting. Shouldn't be necessary, but it's * better to be on the safe side. * * A non LINKED* message byte will indicate that the command completed, * and we are now disconnected. */ switch (message) { case LINKED_CMD_COMPLETE: case LINKED_FLG_CMD_COMPLETE: message = COMMAND_COMPLETE; linked_target = current_target; linked_lun = current_lun; linked_connected = 1; DPRINTK (DEBUG_LINKED, "scsi%d : keeping I_T_L nexus established" "for linked command.\n", hostno); /* We also will need to adjust status to accommodate intermediate conditions. */ if ((status == INTERMEDIATE_GOOD) || (status == INTERMEDIATE_C_GOOD)) status = GOOD; break;/* * We should also handle what are "normal" termination messages * here (ABORT, BUS_DEVICE_RESET?, and COMMAND_COMPLETE individually, * and flake if things aren't right. */ default: DPRINTK (DEBUG_LINKED, "scsi%d : closing I_T_L nexus.\n", hostno); linked_connected = 0; } }#endif /* LINKED */ if (should_reconnect) { DPRINTK (PHASE_RESELECT, "scsi%d : exiting seagate_st0x_queue_command()" "with reconnect enabled.\n", hostno); WRITE_CONTROL (BASE_CMD | CMD_INTR); } else WRITE_CONTROL (BASE_CMD); return retcode (st0x_aborted);} /* end of internal_command */int seagate_st0x_abort (Scsi_Cmnd * SCpnt){ st0x_aborted = DID_ABORT; return SCSI_ABORT_PENDING;}#undef ULOOP#undef TIMEOUT/* * the seagate_st0x_reset function resets the SCSI bus */int seagate_st0x_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags){/* No timeouts - this command is going to fail because it was reset. */ DANY ("scsi%d: Reseting bus... ", hostno );/* assert RESET signal on SCSI bus. */ WRITE_CONTROL (BASE_CMD | CMD_RST); udelay( 20*1000 ); WRITE_CONTROL (BASE_CMD); st0x_aborted = DID_RESET; DANY ("done.\n"); return SCSI_RESET_WAKEUP;}/* Eventually this will go into an include file, but this will be later */static Scsi_Host_Template driver_template = SEAGATE_ST0X;#include "scsi_module.c"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -