📄 cpqfctsinit.c
字号:
copy_info( &info, " TACH RxEOFa %9u TACH Elastic Store %u\n", fcChip->fcStats.Rx_EOFa, fcChip->fcStats.e_stores); copy_info( &info, " BufferCreditWait %9uus TACH FM Inits %u\n", fcChip->fcStats.BB0_Timer*10, fcChip->fcStats.FMinits ); copy_info( &info, " FC-2 Timeouts %9u FC-2 Logouts %u\n", fcChip->fcStats.timeouts, fcChip->fcStats.logouts); copy_info( &info, " FC-2 Aborts %9u FC-4 Aborts %u\n", fcChip->fcStats.FC2aborted, fcChip->fcStats.FC4aborted); // clear the counters cpqfcTSClearLinkStatusCounters( fcChip);#endif return info.buffillen;}#if DEBUG_CMNDUCHAR *ScsiToAscii( UCHAR ScsiCommand){/*++Routine Description: Converts a SCSI command to a text string for debugging purposes.Arguments: ScsiCommand -- hex value SCSI CommandReturn Value: An ASCII, null-terminated string if found, else returns NULL.Original code from M. McGowen, Compaq--*/ switch (ScsiCommand) { case 0x00: return( "Test Unit Ready" ); case 0x01: return( "Rezero Unit or Rewind" ); case 0x02: return( "Request Block Address" ); case 0x03: return( "Requese Sense" ); case 0x04: return( "Format Unit" ); case 0x05: return( "Read Block Limits" ); case 0x07: return( "Reassign Blocks" ); case 0x08: return( "Read (6)" ); case 0x0a: return( "Write (6)" ); case 0x0b: return( "Seek (6)" ); case 0x12: return( "Inquiry" ); case 0x15: return( "Mode Select (6)" ); case 0x16: return( "Reserve" ); case 0x17: return( "Release" ); case 0x1a: return( "ModeSen(6)" ); case 0x1b: return( "Start/Stop Unit" ); case 0x1c: return( "Receive Diagnostic Results" ); case 0x1d: return( "Send Diagnostic" ); case 0x25: return( "Read Capacity" ); case 0x28: return( "Read (10)" ); case 0x2a: return( "Write (10)" ); case 0x2b: return( "Seek (10)" ); case 0x2e: return( "Write and Verify" ); case 0x2f: return( "Verify" ); case 0x34: return( "Pre-Fetch" ); case 0x35: return( "Synchronize Cache" ); case 0x37: return( "Read Defect Data (10)" ); case 0x3b: return( "Write Buffer" ); case 0x3c: return( "Read Buffer" ); case 0x3e: return( "Read Long" ); case 0x3f: return( "Write Long" ); case 0x41: return( "Write Same" ); case 0x4c: return( "Log Select" ); case 0x4d: return( "Log Sense" ); case 0x56: return( "Reserve (10)" ); case 0x57: return( "Release (10)" ); case 0xa0: return( "ReportLuns" ); case 0xb7: return( "Read Defect Data (12)" ); case 0xca: return( "Peripheral Device Addressing SCSI Passthrough" ); case 0xcb: return( "Compaq Array Firmware Passthrough" ); default: return( NULL ); }} // end ScsiToAscii()void cpqfcTS_print_scsi_cmd(Scsi_Cmnd * cmd){printk("cpqfcTS: (%s) chnl 0x%02x, trgt = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n", ScsiToAscii( cmd->cmnd[0]), cmd->channel, cmd->target, cmd->lun, cmd->cmd_len);if( cmd->cmnd[0] == 0) // Test Unit Ready?{ int i; printk("Cmnd->request_bufflen = 0x%X, ->use_sg = %d, ->bufflen = %d\n", cmd->request_bufflen, cmd->use_sg, cmd->bufflen); printk("Cmnd->request_buffer = %p, ->sglist_len = %d, ->buffer = %p\n", cmd->request_buffer, cmd->sglist_len, cmd->buffer); for (i = 0; i < cmd->cmd_len; i++) printk("0x%02x ", cmd->cmnd[i]); printk("\n");}}#endif /* DEBUG_CMND */static void QueCmndOnBoardLock( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd){ int i; for( i=0; i< CPQFCTS_REQ_QUEUE_LEN; i++) { // find spare slot if( cpqfcHBAdata->BoardLockCmnd[i] == NULL ) { cpqfcHBAdata->BoardLockCmnd[i] = Cmnd;// printk(" BoardLockCmnd[%d] %p Queued, chnl/target/lun %d/%d/%d\n",// i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun); break; } } if( i >= CPQFCTS_REQ_QUEUE_LEN) { printk(" cpqfcTS WARNING: Lost Cmnd %p on BoardLock Q full!", Cmnd); }}static void QueLinkDownCmnd( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd){ int indx; // Remember the command ptr so we can return; we'll complete when // the device comes back, causing immediate retry for( indx=0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++)//, SCptr++) { if( cpqfcHBAdata->LinkDnCmnd[indx] == NULL ) // available? {#ifdef DUMMYCMND_DBG printk(" @add Cmnd %p to LnkDnCmnd[%d]@ ", Cmnd,indx);#endif cpqfcHBAdata->LinkDnCmnd[indx] = Cmnd; break; } } if( indx >= CPQFCTS_REQ_QUEUE_LEN ) // no space for Cmnd?? { // this will result in an _abort call later (with possible trouble) printk("no buffer for LinkDnCmnd!! %p\n", Cmnd); }}// The file "hosts.h" says not to call scsi_done from// inside _queuecommand, so we'll do it from the heartbeat timerstatic void QueBadTargetCmnd( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd){ int i; // printk(" can't find target %d\n", Cmnd->target); for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++) { // find spare slot if( cpqfcHBAdata->BadTargetCmnd[i] == NULL ) { cpqfcHBAdata->BadTargetCmnd[i] = Cmnd;// printk(" BadTargetCmnd[%d] %p Queued, chnl/target/lun %d/%d/%d\n",// i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun); break; } }}// This is the "main" entry point for Linux Scsi commands --// it all starts here.int cpqfcTS_queuecommand(Scsi_Cmnd *Cmnd, void (* done)(Scsi_Cmnd *)){ struct Scsi_Host *HostAdapter = Cmnd->host; CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; PTACHYON fcChip = &cpqfcHBAdata->fcChip; TachFCHDR_GCMND fchs; // only use for FC destination id field PFC_LOGGEDIN_PORT pLoggedInPort; ULONG ulStatus, SESTtype; LONG ExchangeID; ENTER("cpqfcTS_queuecommand"); PCI_TRACEO( (ULONG)Cmnd, 0x98) Cmnd->scsi_done = done;#ifdef DEBUG_CMND cpqfcTS_print_scsi_cmd( Cmnd);#endif // prevent board contention with kernel thread... if( cpqfcHBAdata->BoardLock ) {// printk(" @BrdLck Hld@ "); QueCmndOnBoardLock( cpqfcHBAdata, Cmnd); } else { // in the current system (2.2.12), this routine is called // after spin_lock_irqsave(), so INTs are disabled. However, // we might have something pending in the LinkQ, which // might cause the WorkerTask to run. In case that // happens, make sure we lock it out. PCI_TRACE( 0x98) CPQ_SPINLOCK_HBA( cpqfcHBAdata) PCI_TRACE( 0x98) // can we find an FC device mapping to this SCSI target? pLoggedInPort = fcFindLoggedInPort( fcChip, Cmnd, // search Scsi Nexus 0, // DON'T search linked list for FC port id NULL, // DON'T search linked list for FC WWN NULL); // DON'T care about end of list if( pLoggedInPort == NULL ) // not found! {// printk(" @Q bad targ cmnd %p@ ", Cmnd); QueBadTargetCmnd( cpqfcHBAdata, Cmnd); } else // we know what FC device to send to... { // does this device support FCP target functions? // (determined by PRLI field) if( !(pLoggedInPort->fcp_info & TARGET_FUNCTION) ) { printk(" Doesn't support TARGET functions port_id %Xh\n", pLoggedInPort->port_id ); QueBadTargetCmnd( cpqfcHBAdata, Cmnd); } // In this case (previous login OK), the device is temporarily // unavailable waiting for re-login, in which case we expect it // to be back in between 25 - 500ms. // If the FC port doesn't log back in within several seconds // (i.e. implicit "logout"), or we get an explicit logout, // we set "device_blocked" in Scsi_Device struct; in this // case 30 seconds will elapse before Linux/Scsi sends another // command to the device. else if( pLoggedInPort->prli != TRUE ) {// printk("Device (Chnl/Target %d/%d) invalid PRLI, port_id %06lXh\n",// Cmnd->channel, Cmnd->target, pLoggedInPort->port_id); QueLinkDownCmnd( cpqfcHBAdata, Cmnd);// Need to use "blocked" flag?? // Cmnd->device->device_blocked = TRUE; // just let it timeout } else // device supports TARGET functions, and is logged in... { // (context of fchs is to "reply" to...) fchs.s_id = pLoggedInPort->port_id; // destination FC address // what is the data direction? For data TO the device, // we need IWE (Intiator Write Entry). Otherwise, IRE. if( Cmnd->cmnd[0] == WRITE_10 || Cmnd->cmnd[0] == WRITE_6 || Cmnd->cmnd[0] == WRITE_BUFFER || Cmnd->cmnd[0] == VENDOR_WRITE_OPCODE || // CPQ specific Cmnd->cmnd[0] == MODE_SELECT ) { SESTtype = SCSI_IWE; // data from HBA to Device } else SESTtype = SCSI_IRE; // data from Device to HBA ulStatus = cpqfcTSBuildExchange( cpqfcHBAdata, SESTtype, // e.g. Initiator Read Entry (IRE) &fchs, // we are originator; only use d_id Cmnd, // Linux SCSI command (with scatter/gather list) &ExchangeID );// fcController->fcExchanges index, -1 if failed if( !ulStatus ) // Exchange setup? { if( cpqfcHBAdata->BoardLock ) { TriggerHBA( fcChip->Registers.ReMapMemBase, 0); printk(" @bl! %d, xID %Xh@ ", current->pid, ExchangeID); } ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID ); if( !ulStatus ) { PCI_TRACEO( ExchangeID, 0xB8) // submitted to Tach's Outbound Que (ERQ PI incremented) // waited for completion for ELS type (Login frames issued // synchronously) } else // check reason for Exchange not being started - we might // want to Queue and start later, or fail with error { printk("quecommand: cpqfcTSStartExchange failed: %Xh\n", ulStatus ); } } // end good BuildExchange status else // SEST table probably full -- why? hardware hang? { printk("quecommand: cpqfcTSBuildExchange faild: %Xh\n", ulStatus); } } // end can't do FCP-SCSI target functions } // end can't find target (FC device) CPQ_SPINUNLOCK_HBA( cpqfcHBAdata) } PCI_TRACEO( (ULONG)Cmnd, 0x9C) LEAVE("cpqfcTS_queuecommand"); return 0;} // Entry point for upper Scsi layer intiated abort. Typically// this is called if the command (for hard disk) fails to complete// in 30 seconds. This driver intends to complete all disk commands// within Exchange ".timeOut" seconds (now 7) with target status, or// in case of ".timeOut" expiration, a DID_SOFT_ERROR which causes// immediate retry.// If any disk commands get the _abort call, except for the case that// the physical device was removed or unavailable due to hardware// errors, it should be considered a driver error and reported to// the author.int cpqfcTS_abort(Scsi_Cmnd *Cmnd){ struct Scsi_Host *HostAdapter = Cmnd->host; // get the pointer to our Scsi layer HBA buffer CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; PTACHYON fcChip = &cpqfcHBAdata->fcChip; FC_EXCHANGES *Exchanges = fcChip->Exchanges; int i; ENTER("cpqfcTS_abort"); Cmnd->result = DID_ABORT <<16; // assume we'll find it printk(" @Linux _abort Scsi_Cmnd %p ", Cmnd); // See if we can find a Cmnd pointer that matches... // The most likely case is we accepted the command
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -