PageRenderTime 1802ms CodeModel.GetById 121ms RepoModel.GetById 1ms app.codeStats 2ms

/drivers/scsi/cpqfcTSworker.c

https://bitbucket.org/abioy/linux
C | 6520 lines | 3618 code | 1329 blank | 1573 comment | 654 complexity | fb40d0ad9b6df81c59f2f69f6b870311 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, GPL-2.0, LGPL-2.0, AGPL-1.0

Large files files are truncated, but you can click here to view the full file

  1. /* Copyright(c) 2000, Compaq Computer Corporation
  2. * Fibre Channel Host Bus Adapter
  3. * 64-bit, 66MHz PCI
  4. * Originally developed and tested on:
  5. * (front): [chip] Tachyon TS HPFC-5166A/1.2 L2C1090 ...
  6. * SP# P225CXCBFIEL6T, Rev XC
  7. * SP# 161290-001, Rev XD
  8. * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5
  9. *
  10. * This program is free software; you can redistribute it and/or modify it
  11. * under the terms of the GNU General Public License as published by the
  12. * Free Software Foundation; either version 2, or (at your option) any
  13. * later version.
  14. *
  15. * This program is distributed in the hope that it will be useful, but
  16. * WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18. * General Public License for more details.
  19. * Written by Don Zimmerman
  20. */
  21. #include <linux/sched.h>
  22. #include <linux/timer.h>
  23. #include <linux/string.h>
  24. #include <linux/slab.h>
  25. #include <linux/ioport.h>
  26. #include <linux/kernel.h>
  27. #include <linux/stat.h>
  28. #include <linux/blkdev.h>
  29. #include <linux/interrupt.h>
  30. #include <linux/delay.h>
  31. #include <linux/smp_lock.h>
  32. #include <linux/pci.h>
  33. #define __KERNEL_SYSCALLS__
  34. #define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM))
  35. #include <linux/unistd.h>
  36. #include <asm/system.h>
  37. #include <asm/irq.h>
  38. #include <asm/dma.h>
  39. #include "scsi.h"
  40. #include "hosts.h" // struct Scsi_Host definition for T handler
  41. #include "cpqfcTSchip.h"
  42. #include "cpqfcTSstructs.h"
  43. #include "cpqfcTStrigger.h"
  44. //#define LOGIN_DBG 1
  45. // REMARKS:
  46. // Since Tachyon chips may be permitted to wait from 500ms up to 2 sec
  47. // to empty an outgoing frame from its FIFO to the Fibre Channel stream,
  48. // we cannot do everything we need to in the interrupt handler. Specifically,
  49. // every time a link re-init (e.g. LIP) takes place, all SCSI I/O has to be
  50. // suspended until the login sequences have been completed. Login commands
  51. // are frames just like SCSI commands are frames; they are subject to the same
  52. // timeout issues and delays. Also, various specs provide up to 2 seconds for
  53. // devices to log back in (i.e. respond with ACC to a login frame), so I/O to
  54. // that device has to be suspended.
  55. // A serious problem here occurs on highly loaded FC-AL systems. If our FC port
  56. // has a low priority (e.g. high arbitrated loop physical address, alpa), and
  57. // some other device is hogging bandwidth (permissible under FC-AL), we might
  58. // time out thinking the link is hung, when it's simply busy. Many such
  59. // considerations complicate the design. Although Tachyon assumes control
  60. // (in silicon) for many link-specific issues, the Linux driver is left with the
  61. // rest, which turns out to be a difficult, time critical chore.
  62. // These "worker" functions will handle things like FC Logins; all
  63. // processes with I/O to our device must wait for the Login to complete
  64. // and (if successful) I/O to resume. In the event of a malfunctioning or
  65. // very busy loop, it may take hundreds of millisecs or even seconds to complete
  66. // a frame send. We don't want to hang up the entire server (and all
  67. // processes which don't depend on Fibre) during this wait.
  68. // The Tachyon chip can have around 30,000 I/O operations ("exchanges")
  69. // open at one time. However, each exchange must be initiated
  70. // synchronously (i.e. each of the 30k I/O had to be started one at a
  71. // time by sending a starting frame via Tachyon's outbound que).
  72. // To accommodate kernel "module" build, this driver limits the exchanges
  73. // to 256, because of the contiguous physical memory limitation of 128M.
  74. // Typical FC Exchanges are opened presuming the FC frames start without errors,
  75. // while Exchange completion is handled in the interrupt handler. This
  76. // optimizes performance for the "everything's working" case.
  77. // However, when we have FC related errors or hot plugging of FC ports, we pause
  78. // I/O and handle FC-specific tasks in the worker thread. These FC-specific
  79. // functions will handle things like FC Logins and Aborts. As the Login sequence
  80. // completes to each and every target, I/O can resume to that target.
  81. // Our kernel "worker thread" must share the HBA with threads calling
  82. // "queuecommand". We define a "BoardLock" semaphore which indicates
  83. // to "queuecommand" that the HBA is unavailable, and Cmnds are added to a
  84. // board lock Q. When the worker thread finishes with the board, the board
  85. // lock Q commands are completed with status causing immediate retry.
  86. // Typically, the board is locked while Logins are in progress after an
  87. // FC Link Down condition. When Cmnds are re-queued after board lock, the
  88. // particular Scsi channel/target may or may not have logged back in. When
  89. // the device is waiting for login, the "prli" flag is clear, in which case
  90. // commands are passed to a Link Down Q. Whenever the login finally completes,
  91. // the LinkDown Q is completed, again with status causing immediate retry.
  92. // When FC devices are logged in, we build and start FC commands to the
  93. // devices.
  94. // NOTE!! As of May 2000, kernel 2.2.14, the error recovery logic for devices
  95. // that never log back in (e.g. physically removed) is NOT completely
  96. // understood. I've still seen instances of system hangs on failed Write
  97. // commands (possibly from the ext2 layer?) on device removal. Such special
  98. // cases need to be evaluated from a system/application view - e.g., how
  99. // exactly does the system want me to complete commands when the device is
  100. // physically removed??
  101. // local functions
  102. static void SetLoginFields(
  103. PFC_LOGGEDIN_PORT pLoggedInPort,
  104. TachFCHDR_GCMND* fchs,
  105. BOOLEAN PDisc,
  106. BOOLEAN Originator);
  107. static void AnalyzeIncomingFrame(
  108. CPQFCHBA *cpqfcHBAdata,
  109. ULONG QNdx );
  110. static void SendLogins( CPQFCHBA *cpqfcHBAdata, __u32 *FabricPortIds );
  111. static int verify_PLOGI( PTACHYON fcChip,
  112. TachFCHDR_GCMND* fchs, ULONG* reject_explain);
  113. static int verify_PRLI( TachFCHDR_GCMND* fchs, ULONG* reject_explain);
  114. static void LoadWWN( PTACHYON fcChip, UCHAR* dest, UCHAR type);
  115. static void BuildLinkServicePayload(
  116. PTACHYON fcChip, ULONG type, void* payload);
  117. static void UnblockScsiDevice( struct Scsi_Host *HostAdapter,
  118. PFC_LOGGEDIN_PORT pLoggedInPort);
  119. static void cpqfcTSCheckandSnoopFCP( PTACHYON fcChip, ULONG x_ID);
  120. static void CompleteBoardLockCmnd( CPQFCHBA *cpqfcHBAdata);
  121. static void RevalidateSEST( struct Scsi_Host *HostAdapter,
  122. PFC_LOGGEDIN_PORT pLoggedInPort);
  123. static void IssueReportLunsCommand(
  124. CPQFCHBA* cpqfcHBAdata,
  125. TachFCHDR_GCMND* fchs);
  126. // (see scsi_error.c comments on kernel task creation)
  127. void cpqfcTSWorkerThread( void *host)
  128. {
  129. struct Scsi_Host *HostAdapter = (struct Scsi_Host*)host;
  130. CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
  131. #ifdef PCI_KERNEL_TRACE
  132. PTACHYON fcChip = &cpqfcHBAdata->fcChip;
  133. #endif
  134. DECLARE_MUTEX_LOCKED(fcQueReady);
  135. DECLARE_MUTEX_LOCKED(fcTYOBcomplete);
  136. DECLARE_MUTEX_LOCKED(TachFrozen);
  137. DECLARE_MUTEX_LOCKED(BoardLock);
  138. ENTER("WorkerThread");
  139. lock_kernel();
  140. daemonize("cpqfcTS_wt_%d", HostAdapter->host_no);
  141. siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
  142. cpqfcHBAdata->fcQueReady = &fcQueReady; // primary wait point
  143. cpqfcHBAdata->TYOBcomplete = &fcTYOBcomplete;
  144. cpqfcHBAdata->TachFrozen = &TachFrozen;
  145. cpqfcHBAdata->worker_thread = current;
  146. unlock_kernel();
  147. if( cpqfcHBAdata->notify_wt != NULL )
  148. up( cpqfcHBAdata->notify_wt); // OK to continue
  149. while(1)
  150. {
  151. unsigned long flags;
  152. down_interruptible( &fcQueReady); // wait for something to do
  153. if (signal_pending(current) )
  154. break;
  155. PCI_TRACE( 0x90)
  156. // first, take the IO lock so the SCSI upper layers can't call
  157. // into our _quecommand function (this also disables INTs)
  158. spin_lock_irqsave( HostAdapter->host_lock, flags); // STOP _que function
  159. PCI_TRACE( 0x90)
  160. CPQ_SPINLOCK_HBA( cpqfcHBAdata)
  161. // next, set this pointer to indicate to the _quecommand function
  162. // that the board is in use, so it should que the command and
  163. // immediately return (we don't actually require the semaphore function
  164. // in this driver rev)
  165. cpqfcHBAdata->BoardLock = &BoardLock;
  166. PCI_TRACE( 0x90)
  167. // release the IO lock (and re-enable interrupts)
  168. spin_unlock_irqrestore( HostAdapter->host_lock, flags);
  169. // disable OUR HBA interrupt (keep them off as much as possible
  170. // during error recovery)
  171. disable_irq( cpqfcHBAdata->HostAdapter->irq);
  172. // OK, let's process the Fibre Channel Link Q and do the work
  173. cpqfcTS_WorkTask( HostAdapter);
  174. // hopefully, no more "work" to do;
  175. // re-enable our INTs for "normal" completion processing
  176. enable_irq( cpqfcHBAdata->HostAdapter->irq);
  177. cpqfcHBAdata->BoardLock = NULL; // allow commands to be queued
  178. CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
  179. // Now, complete any Cmnd we Q'd up while BoardLock was held
  180. CompleteBoardLockCmnd( cpqfcHBAdata);
  181. }
  182. // hopefully, the signal was for our module exit...
  183. if( cpqfcHBAdata->notify_wt != NULL )
  184. up( cpqfcHBAdata->notify_wt); // yep, we're outta here
  185. }
  186. // Freeze Tachyon routine.
  187. // If Tachyon is already frozen, return FALSE
  188. // If Tachyon is not frozen, call freeze function, return TRUE
  189. //
  190. static BOOLEAN FreezeTach( CPQFCHBA *cpqfcHBAdata)
  191. {
  192. PTACHYON fcChip = &cpqfcHBAdata->fcChip;
  193. BOOLEAN FrozeTach = FALSE;
  194. // It's possible that the chip is already frozen; if so,
  195. // "Freezing" again will NOT! generate another Freeze
  196. // Completion Message.
  197. if( (fcChip->Registers.TYstatus.value & 0x70000) != 0x70000)
  198. { // (need to freeze...)
  199. fcChip->FreezeTachyon( fcChip, 2); // both ERQ and FCP assists
  200. // 2. Get Tach freeze confirmation
  201. // (synchronize SEST manipulation with Freeze Completion Message)
  202. // we need INTs on so semaphore can be set.
  203. enable_irq( cpqfcHBAdata->HostAdapter->irq); // only way to get Semaphore
  204. down_interruptible( cpqfcHBAdata->TachFrozen); // wait for INT handler sem.
  205. // can we TIMEOUT semaphore wait?? TBD
  206. disable_irq( cpqfcHBAdata->HostAdapter->irq);
  207. FrozeTach = TRUE;
  208. } // (else, already frozen)
  209. return FrozeTach;
  210. }
  211. // This is the kernel worker thread task, which processes FC
  212. // tasks which were queued by the Interrupt handler or by
  213. // other WorkTask functions.
  214. #define DBG 1
  215. //#undef DBG
  216. void cpqfcTS_WorkTask( struct Scsi_Host *HostAdapter)
  217. {
  218. CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
  219. PTACHYON fcChip = &cpqfcHBAdata->fcChip;
  220. FC_EXCHANGES *Exchanges = fcChip->Exchanges;
  221. ULONG QconsumerNdx;
  222. LONG ExchangeID;
  223. ULONG ulStatus=0;
  224. TachFCHDR_GCMND fchs;
  225. PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
  226. ENTER("WorkTask");
  227. // copy current index to work on
  228. QconsumerNdx = fcLQ->consumer;
  229. PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x90)
  230. // NOTE: when this switch completes, we will "consume" the Que item
  231. // printk("Que type %Xh\n", fcLQ->Qitem[QconsumerNdx].Type);
  232. switch( fcLQ->Qitem[QconsumerNdx].Type )
  233. {
  234. // incoming frame - link service (ACC, UNSOL REQ, etc.)
  235. // or FCP-SCSI command
  236. case SFQ_UNKNOWN:
  237. AnalyzeIncomingFrame( cpqfcHBAdata, QconsumerNdx );
  238. break;
  239. case EXCHANGE_QUEUED: // an Exchange (i.e. FCP-SCSI) was previously
  240. // Queued because the link was down. The
  241. // heartbeat timer detected it and Queued it here.
  242. // We attempt to start it again, and if
  243. // successful we clear the EXCHANGE_Q flag.
  244. // If the link doesn't come up, the Exchange
  245. // will eventually time-out.
  246. ExchangeID = (LONG) // x_ID copied from DPC timeout function
  247. fcLQ->Qitem[QconsumerNdx].ulBuff[0];
  248. // It's possible that a Q'd exchange could have already
  249. // been started by other logic (e.g. ABTS process)
  250. // Don't start if already started (Q'd flag clear)
  251. if( Exchanges->fcExchange[ExchangeID].status & EXCHANGE_QUEUED )
  252. {
  253. // printk(" *Start Q'd x_ID %Xh: type %Xh ",
  254. // ExchangeID, Exchanges->fcExchange[ExchangeID].type);
  255. ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID);
  256. if( !ulStatus )
  257. {
  258. // printk("success* ");
  259. }
  260. else
  261. {
  262. #ifdef DBG
  263. if( ulStatus == EXCHANGE_QUEUED)
  264. printk("Queued* ");
  265. else
  266. printk("failed* ");
  267. #endif
  268. }
  269. }
  270. break;
  271. case LINKDOWN:
  272. // (lots of things already done in INT handler) future here?
  273. break;
  274. case LINKACTIVE: // Tachyon set the Lup bit in FM status
  275. // NOTE: some misbehaving FC ports (like Tach2.1)
  276. // can re-LIP immediately after a LIP completes.
  277. // if "initiator", need to verify LOGs with ports
  278. // printk("\n*LNKUP* ");
  279. if( fcChip->Options.initiator )
  280. SendLogins( cpqfcHBAdata, NULL ); // PLOGI or PDISC, based on fcPort data
  281. // if SendLogins successfully completes, PortDiscDone
  282. // will be set.
  283. // If SendLogins was successful, then we expect to get incoming
  284. // ACCepts or REJECTs, which are handled below.
  285. break;
  286. // LinkService and Fabric request/reply processing
  287. case ELS_FDISC: // need to send Fabric Discovery (Login)
  288. case ELS_FLOGI: // need to send Fabric Login
  289. case ELS_SCR: // need to send State Change Registration
  290. case FCS_NSR: // need to send Name Service Request
  291. case ELS_PLOGI: // need to send PLOGI
  292. case ELS_ACC: // send generic ACCept
  293. case ELS_PLOGI_ACC: // need to send ELS ACCept frame to recv'd PLOGI
  294. case ELS_PRLI_ACC: // need to send ELS ACCept frame to recv'd PRLI
  295. case ELS_LOGO: // need to send ELS LOGO (logout)
  296. case ELS_LOGO_ACC: // need to send ELS ACCept frame to recv'd PLOGI
  297. case ELS_RJT: // ReJecT reply
  298. case ELS_PRLI: // need to send ELS PRLI
  299. // printk(" *ELS %Xh* ", fcLQ->Qitem[QconsumerNdx].Type);
  300. // if PortDiscDone is not set, it means the SendLogins routine
  301. // failed to complete -- assume that LDn occurred, so login frames
  302. // are invalid
  303. if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn
  304. {
  305. printk("Discard Q'd ELS login frame\n");
  306. break;
  307. }
  308. ulStatus = cpqfcTSBuildExchange(
  309. cpqfcHBAdata,
  310. fcLQ->Qitem[QconsumerNdx].Type, // e.g. PLOGI
  311. (TachFCHDR_GCMND*)
  312. fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
  313. NULL, // no data (no scatter/gather list)
  314. &ExchangeID );// fcController->fcExchanges index, -1 if failed
  315. if( !ulStatus ) // Exchange setup?
  316. {
  317. ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
  318. if( !ulStatus )
  319. {
  320. // submitted to Tach's Outbound Que (ERQ PI incremented)
  321. // waited for completion for ELS type (Login frames issued
  322. // synchronously)
  323. }
  324. else
  325. // check reason for Exchange not being started - we might
  326. // want to Queue and start later, or fail with error
  327. {
  328. }
  329. }
  330. else // Xchange setup failed...
  331. printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
  332. break;
  333. case SCSI_REPORT_LUNS:
  334. // pass the incoming frame (actually, it's a PRLI frame)
  335. // so we can send REPORT_LUNS, in order to determine VSA/PDU
  336. // FCP-SCSI Lun address mode
  337. IssueReportLunsCommand( cpqfcHBAdata, (TachFCHDR_GCMND*)
  338. fcLQ->Qitem[QconsumerNdx].ulBuff);
  339. break;
  340. case BLS_ABTS: // need to ABORT one or more exchanges
  341. {
  342. LONG x_ID = fcLQ->Qitem[QconsumerNdx].ulBuff[0];
  343. BOOLEAN FrozeTach = FALSE;
  344. if ( x_ID >= TACH_SEST_LEN ) // (in)sanity check
  345. {
  346. // printk( " cpqfcTS ERROR! BOGUS x_ID %Xh", x_ID);
  347. break;
  348. }
  349. if( Exchanges->fcExchange[ x_ID].Cmnd == NULL ) // should be RARE
  350. {
  351. // printk(" ABTS %Xh Scsi Cmnd null! ", x_ID);
  352. break; // nothing to abort!
  353. }
  354. //#define ABTS_DBG
  355. #ifdef ABTS_DBG
  356. printk("INV SEST[%X] ", x_ID);
  357. if( Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT)
  358. {
  359. printk("FC2TO");
  360. }
  361. if( Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT)
  362. {
  363. printk("IA");
  364. }
  365. if( Exchanges->fcExchange[x_ID].status & PORTID_CHANGED)
  366. {
  367. printk("PORTID");
  368. }
  369. if( Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED)
  370. {
  371. printk("DEVRM");
  372. }
  373. if( Exchanges->fcExchange[x_ID].status & LINKFAIL_TX)
  374. {
  375. printk("LKF");
  376. }
  377. if( Exchanges->fcExchange[x_ID].status & FRAME_TO)
  378. {
  379. printk("FRMTO");
  380. }
  381. if( Exchanges->fcExchange[x_ID].status & ABORTSEQ_NOTIFY)
  382. {
  383. printk("ABSQ");
  384. }
  385. if( Exchanges->fcExchange[x_ID].status & SFQ_FRAME)
  386. {
  387. printk("SFQFR");
  388. }
  389. if( Exchanges->fcExchange[ x_ID].type == 0x2000)
  390. printk(" WR");
  391. else if( Exchanges->fcExchange[ x_ID].type == 0x3000)
  392. printk(" RD");
  393. else if( Exchanges->fcExchange[ x_ID].type == 0x10)
  394. printk(" ABTS");
  395. else
  396. printk(" %Xh", Exchanges->fcExchange[ x_ID].type);
  397. if( !(Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT))
  398. {
  399. printk(" Cmd %p, ",
  400. Exchanges->fcExchange[ x_ID].Cmnd);
  401. printk(" brd/chn/trg/lun %d/%d/%d/%d port_id %06X\n",
  402. cpqfcHBAdata->HBAnum,
  403. Exchanges->fcExchange[ x_ID].Cmnd->channel,
  404. Exchanges->fcExchange[ x_ID].Cmnd->target,
  405. Exchanges->fcExchange[ x_ID].Cmnd->lun,
  406. Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF);
  407. }
  408. else // assume that Cmnd ptr is invalid on _abort()
  409. {
  410. printk(" Cmd ptr invalid\n");
  411. }
  412. #endif
  413. // Steps to ABORT a SEST exchange:
  414. // 1. Freeze TL SCSI assists & ERQ (everything)
  415. // 2. Receive FROZEN inbound CM (must succeed!)
  416. // 3. Invalidate x_ID SEST entry
  417. // 4. Resume TL SCSI assists & ERQ (everything)
  418. // 5. Build/start on exchange - change "type" to BLS_ABTS,
  419. // timeout to X sec (RA_TOV from PLDA is actually 0)
  420. // 6. Set Exchange Q'd status if ABTS cannot be started,
  421. // or simply complete Exchange in "Terminate" condition
  422. PCI_TRACEO( x_ID, 0xB4)
  423. // 1 & 2 . Freeze Tach & get confirmation of freeze
  424. FrozeTach = FreezeTach( cpqfcHBAdata);
  425. // 3. OK, Tachyon is frozen, so we can invalidate SEST exchange.
  426. // FC2_TIMEOUT means we are originating the abort, while
  427. // TARGET_ABORT means we are ACCepting an abort.
  428. // LINKFAIL_TX, ABORTSEQ_NOFITY, INV_ENTRY or FRAME_TO are
  429. // all from Tachyon:
  430. // Exchange was corrupted by LDn or other FC physical failure
  431. // INITIATOR_ABORT means the upper layer driver/application
  432. // requested the abort.
  433. // clear bit 31 (VALid), to invalidate & take control from TL
  434. fcChip->SEST->u[ x_ID].IWE.Hdr_Len &= 0x7FFFFFFF;
  435. // examine and Tach's "Linked List" for IWEs that
  436. // received (nearly) simultaneous transfer ready (XRDY)
  437. // repair linked list if necessary (TBD!)
  438. // (If we ignore the "Linked List", we will time out
  439. // WRITE commands where we received the FCP-SCSI XFRDY
  440. // frame (because Tachyon didn't processes it). Linked List
  441. // management should be done as an optimization.
  442. // readl( fcChip->Registers.ReMapMemBase+TL_MEM_SEST_LINKED_LIST ));
  443. // 4. Resume all Tachlite functions (for other open Exchanges)
  444. // as quickly as possible to allow other exchanges to other ports
  445. // to resume. Freezing Tachyon may cause cascading errors, because
  446. // any received SEST frame cannot be processed by the SEST.
  447. // Don't "unfreeze" unless Link is operational
  448. if( FrozeTach ) // did we just freeze it (above)?
  449. fcChip->UnFreezeTachyon( fcChip, 2); // both ERQ and FCP assists
  450. PCI_TRACEO( x_ID, 0xB4)
  451. // Note there is no confirmation that the chip is "unfrozen". Also,
  452. // if the Link is down when unfreeze is called, it has no effect.
  453. // Chip will unfreeze when the Link is back up.
  454. // 5. Now send out Abort commands if possible
  455. // Some Aborts can't be "sent" (Port_id changed or gone);
  456. // if the device is gone, there is no port_id to send the ABTS to.
  457. if( !(Exchanges->fcExchange[ x_ID].status & PORTID_CHANGED)
  458. &&
  459. !(Exchanges->fcExchange[ x_ID].status & DEVICE_REMOVED) )
  460. {
  461. Exchanges->fcExchange[ x_ID].type = BLS_ABTS;
  462. fchs.s_id = Exchanges->fcExchange[ x_ID].fchs.d_id;
  463. ulStatus = cpqfcTSBuildExchange(
  464. cpqfcHBAdata,
  465. BLS_ABTS,
  466. &fchs, // (uses only s_id)
  467. NULL, // (no scatter/gather list for ABTS)
  468. &x_ID );// ABTS on this Exchange ID
  469. if( !ulStatus ) // Exchange setup build OK?
  470. {
  471. // ABTS may be needed because an Exchange was corrupted
  472. // by a Link disruption. If the Link is UP, we can
  473. // presume that this ABTS can start immediately; otherwise,
  474. // set Que'd status so the Login functions
  475. // can restart it when the FC physical Link is restored
  476. if( ((fcChip->Registers.FMstatus.value &0xF0) &0x80)) // loop init?
  477. {
  478. // printk(" *set Q status x_ID %Xh on LDn* ", x_ID);
  479. Exchanges->fcExchange[ x_ID].status |= EXCHANGE_QUEUED;
  480. }
  481. else // what FC device (port_id) does the Cmd belong to?
  482. {
  483. PFC_LOGGEDIN_PORT pLoggedInPort =
  484. Exchanges->fcExchange[ x_ID].pLoggedInPort;
  485. // if Port is logged in, we might start the abort.
  486. if( (pLoggedInPort != NULL)
  487. &&
  488. (pLoggedInPort->prli == TRUE) )
  489. {
  490. // it's possible that an Exchange has already been Queued
  491. // to start after Login completes. Check and don't
  492. // start it (again) here if Q'd status set
  493. // printk(" ABTS xchg %Xh ", x_ID);
  494. if( Exchanges->fcExchange[x_ID].status & EXCHANGE_QUEUED)
  495. {
  496. // printk("already Q'd ");
  497. }
  498. else
  499. {
  500. // printk("starting ");
  501. fcChip->fcStats.FC2aborted++;
  502. ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, x_ID );
  503. if( !ulStatus )
  504. {
  505. // OK
  506. // submitted to Tach's Outbound Que (ERQ PI incremented)
  507. }
  508. else
  509. {
  510. /* printk("ABTS exchange start failed -status %Xh, x_ID %Xh ",
  511. ulStatus, x_ID);
  512. */
  513. }
  514. }
  515. }
  516. else
  517. {
  518. /* printk(" ABTS NOT starting xchg %Xh, %p ",
  519. x_ID, pLoggedInPort);
  520. if( pLoggedInPort )
  521. printk("prli %d ", pLoggedInPort->prli);
  522. */
  523. }
  524. }
  525. }
  526. else // what the #@!
  527. { // how do we fail to build an Exchange for ABTS??
  528. printk("ABTS exchange build failed -status %Xh, x_ID %Xh\n",
  529. ulStatus, x_ID);
  530. }
  531. }
  532. else // abort without ABTS -- just complete exchange/Cmnd to Linux
  533. {
  534. // printk(" *Terminating x_ID %Xh on %Xh* ",
  535. // x_ID, Exchanges->fcExchange[x_ID].status);
  536. cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, x_ID);
  537. }
  538. } // end of ABTS case
  539. break;
  540. case BLS_ABTS_ACC: // need to ACCept one ABTS
  541. // (NOTE! this code not updated for Linux yet..)
  542. printk(" *ABTS_ACC* ");
  543. // 1. Freeze TL
  544. fcChip->FreezeTachyon( fcChip, 2); // both ERQ and FCP assists
  545. memcpy( // copy the incoming ABTS frame
  546. &fchs,
  547. fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
  548. sizeof( fchs));
  549. // 3. OK, Tachyon is frozen so we can invalidate SEST entry
  550. // (if necessary)
  551. // Status FC2_TIMEOUT means we are originating the abort, while
  552. // TARGET_ABORT means we are ACCepting an abort
  553. ExchangeID = fchs.ox_rx_id & 0x7FFF; // RX_ID for exchange
  554. // printk("ABTS ACC for Target ExchangeID %Xh\n", ExchangeID);
  555. // sanity check on received ExchangeID
  556. if( Exchanges->fcExchange[ ExchangeID].status == TARGET_ABORT )
  557. {
  558. // clear bit 31 (VALid), to invalidate & take control from TL
  559. // printk("Invalidating SEST exchange %Xh\n", ExchangeID);
  560. fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len &= 0x7FFFFFFF;
  561. }
  562. // 4. Resume all Tachlite functions (for other open Exchanges)
  563. // as quickly as possible to allow other exchanges to other ports
  564. // to resume. Freezing Tachyon for too long may royally screw
  565. // up everything!
  566. fcChip->UnFreezeTachyon( fcChip, 2); // both ERQ and FCP assists
  567. // Note there is no confirmation that the chip is "unfrozen". Also,
  568. // if the Link is down when unfreeze is called, it has no effect.
  569. // Chip will unfreeze when the Link is back up.
  570. // 5. Now send out Abort ACC reply for this exchange
  571. Exchanges->fcExchange[ ExchangeID].type = BLS_ABTS_ACC;
  572. fchs.s_id = Exchanges->fcExchange[ ExchangeID].fchs.d_id;
  573. ulStatus = cpqfcTSBuildExchange(
  574. cpqfcHBAdata,
  575. BLS_ABTS_ACC,
  576. &fchs,
  577. NULL, // no data (no scatter/gather list)
  578. &ExchangeID );// fcController->fcExchanges index, -1 if failed
  579. if( !ulStatus ) // Exchange setup?
  580. {
  581. ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
  582. if( !ulStatus )
  583. {
  584. // submitted to Tach's Outbound Que (ERQ PI incremented)
  585. // waited for completion for ELS type (Login frames issued
  586. // synchronously)
  587. }
  588. else
  589. // check reason for Exchange not being started - we might
  590. // want to Queue and start later, or fail with error
  591. {
  592. }
  593. }
  594. break;
  595. case BLS_ABTS_RJT: // need to ReJecT one ABTS; reject implies the
  596. // exchange doesn't exist in the TARGET context.
  597. // ExchangeID has to come from LinkService space.
  598. printk(" *ABTS_RJT* ");
  599. ulStatus = cpqfcTSBuildExchange(
  600. cpqfcHBAdata,
  601. BLS_ABTS_RJT,
  602. (TachFCHDR_GCMND*)
  603. fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
  604. NULL, // no data (no scatter/gather list)
  605. &ExchangeID );// fcController->fcExchanges index, -1 if failed
  606. if( !ulStatus ) // Exchange setup OK?
  607. {
  608. ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
  609. // If it fails, we aren't required to retry.
  610. }
  611. if( ulStatus )
  612. {
  613. printk("Failed to send BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
  614. }
  615. else
  616. {
  617. printk("Sent BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
  618. }
  619. break;
  620. default:
  621. break;
  622. } // end switch
  623. //doNothing:
  624. // done with this item - now set the NEXT index
  625. if( QconsumerNdx+1 >= FC_LINKQ_DEPTH ) // rollover test
  626. {
  627. fcLQ->consumer = 0;
  628. }
  629. else
  630. {
  631. fcLQ->consumer++;
  632. }
  633. PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x94)
  634. LEAVE("WorkTask");
  635. return;
  636. }
  637. // When Tachyon reports link down, bad al_pa, or Link Service (e.g. Login)
  638. // commands come in, post to the LinkQ so that action can be taken outside the
  639. // interrupt handler.
  640. // This circular Q works like Tachyon's que - the producer points to the next
  641. // (unused) entry. Called by Interrupt handler, WorkerThread, Timer
  642. // sputlinkq
  643. void cpqfcTSPutLinkQue( CPQFCHBA *cpqfcHBAdata,
  644. int Type,
  645. void *QueContent)
  646. {
  647. PTACHYON fcChip = &cpqfcHBAdata->fcChip;
  648. // FC_EXCHANGES *Exchanges = fcChip->Exchanges;
  649. PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
  650. ULONG ndx;
  651. ENTER("cpqfcTSPutLinkQ");
  652. ndx = fcLQ->producer;
  653. ndx += 1; // test for Que full
  654. if( ndx >= FC_LINKQ_DEPTH ) // rollover test
  655. ndx = 0;
  656. if( ndx == fcLQ->consumer ) // QUE full test
  657. {
  658. // QUE was full! lost LK command (fatal to logic)
  659. fcChip->fcStats.lnkQueFull++;
  660. printk("*LinkQ Full!*");
  661. TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
  662. /*
  663. {
  664. int i;
  665. printk("LinkQ PI %d, CI %d\n", fcLQ->producer,
  666. fcLQ->consumer);
  667. for( i=0; i< FC_LINKQ_DEPTH; )
  668. {
  669. printk(" [%d]%Xh ", i, fcLQ->Qitem[i].Type);
  670. if( (++i %8) == 0) printk("\n");
  671. }
  672. }
  673. */
  674. printk( "cpqfcTS: WARNING!! PutLinkQue - FULL!\n"); // we're hung
  675. }
  676. else // QUE next element
  677. {
  678. // Prevent certain multiple (back-to-back) requests.
  679. // This is important in that we don't want to issue multiple
  680. // ABTS for the same Exchange, or do multiple FM inits, etc.
  681. // We can never be sure of the timing of events reported to
  682. // us by Tach's IMQ, which can depend on system/bus speeds,
  683. // FC physical link circumstances, etc.
  684. if( (fcLQ->producer != fcLQ->consumer)
  685. &&
  686. (Type == FMINIT) )
  687. {
  688. LONG lastNdx; // compute previous producer index
  689. if( fcLQ->producer)
  690. lastNdx = fcLQ->producer- 1;
  691. else
  692. lastNdx = FC_LINKQ_DEPTH-1;
  693. if( fcLQ->Qitem[lastNdx].Type == FMINIT)
  694. {
  695. // printk(" *skip FMINIT Q post* ");
  696. // goto DoneWithPutQ;
  697. }
  698. }
  699. // OK, add the Q'd item...
  700. fcLQ->Qitem[fcLQ->producer].Type = Type;
  701. memcpy(
  702. fcLQ->Qitem[fcLQ->producer].ulBuff,
  703. QueContent,
  704. sizeof(fcLQ->Qitem[fcLQ->producer].ulBuff));
  705. fcLQ->producer = ndx; // increment Que producer
  706. // set semaphore to wake up Kernel (worker) thread
  707. //
  708. up( cpqfcHBAdata->fcQueReady );
  709. }
  710. //DoneWithPutQ:
  711. LEAVE("cpqfcTSPutLinkQ");
  712. }
  713. // reset device ext FC link Q
  714. void cpqfcTSLinkQReset( CPQFCHBA *cpqfcHBAdata)
  715. {
  716. PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
  717. fcLQ->producer = 0;
  718. fcLQ->consumer = 0;
  719. }
  720. // When Tachyon gets an unassisted FCP-SCSI frame, post here so
  721. // an arbitrary context thread (e.g. IOCTL loopback test function)
  722. // can process it.
  723. // (NOTE: Not revised for Linux)
  724. // This Q works like Tachyon's que - the producer points to the next
  725. // (unused) entry.
  726. void cpqfcTSPutScsiQue( CPQFCHBA *cpqfcHBAdata,
  727. int Type,
  728. void *QueContent)
  729. {
  730. // CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
  731. // PTACHYON fcChip = &cpqfcHBAdata->fcChip;
  732. // ULONG ndx;
  733. // ULONG *pExchangeID;
  734. // LONG ExchangeID;
  735. /*
  736. KeAcquireSpinLockAtDpcLevel( &pDevExt->fcScsiQueLock);
  737. ndx = pDevExt->fcScsiQue.producer + 1; // test for Que full
  738. if( ndx >= FC_SCSIQ_DEPTH ) // rollover test
  739. ndx = 0;
  740. if( ndx == pDevExt->fcScsiQue.consumer ) // QUE full test
  741. {
  742. // QUE was full! lost LK command (fatal to logic)
  743. fcChip->fcStats.ScsiQueFull++;
  744. #ifdef DBG
  745. printk( "fcPutScsiQue - FULL!\n");
  746. #endif
  747. }
  748. else // QUE next element
  749. {
  750. pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].Type = Type;
  751. if( Type == FCP_RSP )
  752. {
  753. // this TL inbound message type means that a TL SEST exchange has
  754. // copied an FCP response frame into a buffer pointed to by the SEST
  755. // entry. That buffer is allocated in the SEST structure at ->RspHDR.
  756. // Copy the RspHDR for use by the Que handler.
  757. pExchangeID = (ULONG *)QueContent;
  758. memcpy(
  759. pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff,
  760. &fcChip->SEST->RspHDR[ *pExchangeID ],
  761. sizeof(pDevExt->fcScsiQue.Qitem[0].ulBuff)); // (any element for size)
  762. }
  763. else
  764. {
  765. memcpy(
  766. pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff,
  767. QueContent,
  768. sizeof(pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff));
  769. }
  770. pDevExt->fcScsiQue.producer = ndx; // increment Que
  771. KeSetEvent( &pDevExt->TYIBscsi, // signal any waiting thread
  772. 0, // no priority boost
  773. FALSE ); // no waiting later for this event
  774. }
  775. KeReleaseSpinLockFromDpcLevel( &pDevExt->fcScsiQueLock);
  776. */
  777. }
  778. static void ProcessELS_Request( CPQFCHBA*,TachFCHDR_GCMND*);
  779. static void ProcessELS_Reply( CPQFCHBA*,TachFCHDR_GCMND*);
  780. static void ProcessFCS_Reply( CPQFCHBA*,TachFCHDR_GCMND*);
  781. void cpqfcTSImplicitLogout( CPQFCHBA* cpqfcHBAdata,
  782. PFC_LOGGEDIN_PORT pFcPort)
  783. {
  784. PTACHYON fcChip = &cpqfcHBAdata->fcChip;
  785. if( pFcPort->port_id != 0xFFFC01 ) // don't care about Fabric
  786. {
  787. fcChip->fcStats.logouts++;
  788. printk("cpqfcTS: Implicit logout of WWN %08X%08X, port_id %06X\n",
  789. (ULONG)pFcPort->u.liWWN,
  790. (ULONG)(pFcPort->u.liWWN >>32),
  791. pFcPort->port_id);
  792. // Terminate I/O with this (Linux) Scsi target
  793. cpqfcTSTerminateExchange( cpqfcHBAdata,
  794. &pFcPort->ScsiNexus,
  795. DEVICE_REMOVED);
  796. }
  797. // Do an "implicit logout" - we can't really Logout the device
  798. // (i.e. with LOGOut Request) because of port_id confusion
  799. // (i.e. the Other port has no port_id).
  800. // A new login for that WWN will have to re-write port_id (0 invalid)
  801. pFcPort->port_id = 0; // invalid!
  802. pFcPort->pdisc = FALSE;
  803. pFcPort->prli = FALSE;
  804. pFcPort->plogi = FALSE;
  805. pFcPort->flogi = FALSE;
  806. pFcPort->LOGO_timer = 0;
  807. pFcPort->device_blocked = TRUE; // block Scsi Requests
  808. pFcPort->ScsiNexus.VolumeSetAddressing=0;
  809. }
  810. // On FC-AL, there is a chance that a previously known device can
  811. // be quietly removed (e.g. with non-managed hub),
  812. // while a NEW device (with different WWN) took the same alpa or
  813. // even 24-bit port_id. This chance is unlikely but we must always
  814. // check for it.
  815. static void TestDuplicatePortId( CPQFCHBA* cpqfcHBAdata,
  816. PFC_LOGGEDIN_PORT pLoggedInPort)
  817. {
  818. PTACHYON fcChip = &cpqfcHBAdata->fcChip;
  819. // set "other port" at beginning of fcPorts list
  820. PFC_LOGGEDIN_PORT pOtherPortWithPortId = fcChip->fcPorts.pNextPort;
  821. while( pOtherPortWithPortId )
  822. {
  823. if( (pOtherPortWithPortId->port_id ==
  824. pLoggedInPort->port_id)
  825. &&
  826. (pOtherPortWithPortId != pLoggedInPort) )
  827. {
  828. // trouble! (Implicitly) Log the other guy out
  829. printk(" *port_id %Xh is duplicated!* ",
  830. pOtherPortWithPortId->port_id);
  831. cpqfcTSImplicitLogout( cpqfcHBAdata, pOtherPortWithPortId);
  832. }
  833. pOtherPortWithPortId = pOtherPortWithPortId->pNextPort;
  834. }
  835. }
  836. // Dynamic Memory Allocation for newly discovered FC Ports.
  837. // For simplicity, maintain fcPorts structs for ALL
  838. // for discovered devices, including those we never do I/O with
  839. // (e.g. Fabric addresses)
  840. static PFC_LOGGEDIN_PORT CreateFcPort(
  841. CPQFCHBA* cpqfcHBAdata,
  842. PFC_LOGGEDIN_PORT pLastLoggedInPort,
  843. TachFCHDR_GCMND* fchs,
  844. LOGIN_PAYLOAD* plogi)
  845. {
  846. PTACHYON fcChip = &cpqfcHBAdata->fcChip;
  847. PFC_LOGGEDIN_PORT pNextLoggedInPort = NULL;
  848. int i;
  849. printk("cpqfcTS: New FC port %06Xh WWN: ", fchs->s_id);
  850. for( i=3; i>=0; i--) // copy the LOGIN port's WWN
  851. printk("%02X", plogi->port_name[i]);
  852. for( i=7; i>3; i--) // copy the LOGIN port's WWN
  853. printk("%02X", plogi->port_name[i]);
  854. // allocate mem for new port
  855. // (these are small and rare allocations...)
  856. pNextLoggedInPort = kmalloc( sizeof( FC_LOGGEDIN_PORT), GFP_ATOMIC );
  857. // allocation succeeded? Fill out NEW PORT
  858. if( pNextLoggedInPort )
  859. {
  860. // clear out any garbage (sometimes exists)
  861. memset( pNextLoggedInPort, 0, sizeof( FC_LOGGEDIN_PORT));
  862. // If we login to a Fabric, we don't want to treat it
  863. // as a SCSI device...
  864. if( (fchs->s_id & 0xFFF000) != 0xFFF000)
  865. {
  866. int i;
  867. // create a unique "virtual" SCSI Nexus (for now, just a
  868. // new target ID) -- we will update channel/target on REPORT_LUNS
  869. // special case for very first SCSI target...
  870. if( cpqfcHBAdata->HostAdapter->max_id == 0)
  871. {
  872. pNextLoggedInPort->ScsiNexus.target = 0;
  873. fcChip->fcPorts.ScsiNexus.target = -1; // don't use "stub"
  874. }
  875. else
  876. {
  877. pNextLoggedInPort->ScsiNexus.target =
  878. cpqfcHBAdata->HostAdapter->max_id;
  879. }
  880. // initialize the lun[] Nexus struct for lun masking
  881. for( i=0; i< CPQFCTS_MAX_LUN; i++)
  882. pNextLoggedInPort->ScsiNexus.lun[i] = 0xFF; // init to NOT USED
  883. pNextLoggedInPort->ScsiNexus.channel = 0; // cpqfcTS has 1 FC port
  884. printk(" SCSI Chan/Trgt %d/%d",
  885. pNextLoggedInPort->ScsiNexus.channel,
  886. pNextLoggedInPort->ScsiNexus.target);
  887. // tell Scsi layers about the new target...
  888. cpqfcHBAdata->HostAdapter->max_id++;
  889. // printk("HostAdapter->max_id = %d\n",
  890. // cpqfcHBAdata->HostAdapter->max_id);
  891. }
  892. else
  893. {
  894. // device is NOT SCSI (in case of Fabric)
  895. pNextLoggedInPort->ScsiNexus.target = -1; // invalid
  896. }
  897. // create forward link to new port
  898. pLastLoggedInPort->pNextPort = pNextLoggedInPort;
  899. printk("\n");
  900. }
  901. return pNextLoggedInPort; // NULL on allocation failure
  902. } // end NEW PORT (WWN) logic
  903. // For certain cases, we want to terminate exchanges without
  904. // sending ABTS to the device. Examples include when an FC
  905. // device changed it's port_id after Loop re-init, or when
  906. // the device sent us a logout. In the case of changed port_id,
  907. // we want to complete the command and return SOFT_ERROR to
  908. // force a re-try. In the case of LOGOut, we might return
  909. // BAD_TARGET if the device is really gone.
  910. // Since we must ensure that Tachyon is not operating on the
  911. // exchange, we have to freeze the chip
  912. // sterminateex
  913. void cpqfcTSTerminateExchange(
  914. CPQFCHBA* cpqfcHBAdata, SCSI_NEXUS *ScsiNexus, int TerminateStatus)
  915. {
  916. PTACHYON fcChip = &cpqfcHBAdata->fcChip;
  917. FC_EXCHANGES *Exchanges = fcChip->Exchanges;
  918. ULONG x_ID;
  919. if( ScsiNexus )
  920. {
  921. // printk("TerminateExchange: ScsiNexus chan/target %d/%d\n",
  922. // ScsiNexus->channel, ScsiNexus->target);
  923. }
  924. for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
  925. {
  926. if( Exchanges->fcExchange[x_ID].type ) // in use?
  927. {
  928. if( ScsiNexus == NULL ) // our HBA changed - term. all
  929. {
  930. Exchanges->fcExchange[x_ID].status = TerminateStatus;
  931. cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID );
  932. }
  933. else
  934. {
  935. // If a device, according to WWN, has been removed, it's
  936. // port_id may be used by another working device, so we
  937. // have to terminate by SCSI target, NOT port_id.
  938. if( Exchanges->fcExchange[x_ID].Cmnd) // Cmnd in progress?
  939. {
  940. if( (Exchanges->fcExchange[x_ID].Cmnd->device->id == ScsiNexus->target)
  941. &&
  942. (Exchanges->fcExchange[x_ID].Cmnd->device->channel == ScsiNexus->channel))
  943. {
  944. Exchanges->fcExchange[x_ID].status = TerminateStatus;
  945. cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID ); // timed-out
  946. }
  947. }
  948. // (in case we ever need it...)
  949. // all SEST structures have a remote node ID at SEST DWORD 2
  950. // if( (fcChip->SEST->u[ x_ID ].TWE.Remote_Node_ID >> 8)
  951. // == port_id)
  952. }
  953. }
  954. }
  955. }
  956. static void ProcessELS_Request(
  957. CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
  958. {
  959. PTACHYON fcChip = &cpqfcHBAdata->fcChip;
  960. // FC_EXCHANGES *Exchanges = fcChip->Exchanges;
  961. // ULONG ox_id = (fchs->ox_rx_id >>16);
  962. PFC_LOGGEDIN_PORT pLoggedInPort=NULL, pLastLoggedInPort;
  963. BOOLEAN NeedReject = FALSE;
  964. ULONG ls_reject_code = 0; // default don'n know??
  965. // Check the incoming frame for a supported ELS type
  966. switch( fchs->pl[0] & 0xFFFF)
  967. {
  968. case 0x0050: // PDISC?
  969. // Payload for PLOGI and PDISC is identical (request & reply)
  970. if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload?
  971. {
  972. LOGIN_PAYLOAD logi; // FC-PH Port Login
  973. // PDISC payload OK. If critical login fields
  974. // (e.g. WWN) matches last login for this port_id,
  975. // we may resume any prior exchanges
  976. // with the other port
  977. BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
  978. pLoggedInPort = fcFindLoggedInPort(
  979. fcChip,
  980. NULL, // don't search Scsi Nexus
  981. 0, // don't search linked list for port_id
  982. &logi.port_name[0], // search linked list for WWN
  983. &pLastLoggedInPort); // must return non-NULL; when a port_id
  984. // is not found, this pointer marks the
  985. // end of the singly linked list
  986. if( pLoggedInPort != NULL) // WWN found (prior login OK)
  987. {
  988. if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id)
  989. {
  990. // Yes. We were expecting PDISC?
  991. if( pLoggedInPort->pdisc )
  992. {
  993. // Yes; set fields accordingly. (PDISC, not Originator)
  994. SetLoginFields( pLoggedInPort, fchs, TRUE, FALSE);
  995. // send 'ACC' reply
  996. cpqfcTSPutLinkQue( cpqfcHBAdata,
  997. ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
  998. fchs );
  999. // OK to resume I/O...
  1000. }
  1001. else
  1002. {
  1003. printk("Not expecting PDISC (pdisc=FALSE)\n");
  1004. NeedReject = TRUE;
  1005. // set reject reason code
  1006. ls_reject_code =
  1007. LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
  1008. }
  1009. }
  1010. else
  1011. {
  1012. if( pLoggedInPort->port_id != 0)
  1013. {
  1014. printk("PDISC PortID change: old %Xh, new %Xh\n",
  1015. pLoggedInPort->port_id, fchs->s_id &0xFFFFFF);
  1016. }
  1017. NeedReject = TRUE;
  1018. // set reject reason code
  1019. ls_reject_code =
  1020. LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
  1021. }
  1022. }
  1023. else
  1024. {
  1025. printk("PDISC Request from unknown WWN\n");
  1026. NeedReject = TRUE;
  1027. // set reject reason code
  1028. ls_reject_code =
  1029. LS_RJT_REASON( LOGICAL_ERROR, INVALID_PORT_NAME);
  1030. }
  1031. }
  1032. else // Payload unacceptable
  1033. {
  1034. printk("payload unacceptable\n");
  1035. NeedReject = TRUE; // reject code already set
  1036. }
  1037. if( NeedReject)
  1038. {
  1039. ULONG port_id;
  1040. // The PDISC failed. Set login struct flags accordingly,
  1041. // terminate any I/O to this port, and Q a PLOGI
  1042. if( pLoggedInPort )
  1043. {
  1044. pLoggedInPort->pdisc = FALSE;
  1045. pLoggedInPort->prli = FALSE;
  1046. pLoggedInPort->plogi = FALSE;
  1047. cpqfcTSTerminateExchange( cpqfcHBAdata,
  1048. &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
  1049. port_id = pLoggedInPort->port_id;
  1050. }
  1051. else
  1052. {
  1053. port_id = fchs->s_id &0xFFFFFF;
  1054. }
  1055. fchs->reserved = ls_reject_code; // borrow this (unused) field
  1056. cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs );
  1057. }
  1058. break;
  1059. case 0x0003: // PLOGI?
  1060. // Payload for PLOGI and PDISC is identical (request & reply)
  1061. if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload?
  1062. {
  1063. LOGIN_PAYLOAD logi; // FC-PH Port Login
  1064. BOOLEAN NeedReject = FALSE;
  1065. // PDISC payload OK. If critical login fields
  1066. // (e.g. WWN) matches last login for this port_id,
  1067. // we may resume any prior exchanges
  1068. // with the other port
  1069. BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
  1070. pLoggedInPort = fcFindLoggedInPort(
  1071. fcChip,
  1072. NULL, // don't search Scsi Nexus
  1073. 0, // don't search linked list for port_id
  1074. &logi.port_name[0], // search linked list for WWN
  1075. &pLastLoggedInPort); // must return non-NULL; when a port_id
  1076. // is not found, this pointer marks the
  1077. // end of the singly linked list
  1078. if( pLoggedInPort == NULL) // WWN not found -New Port
  1079. {
  1080. pLoggedInPort = CreateFcPort(
  1081. cpqfcHBAdata,
  1082. pLastLoggedInPort,
  1083. fchs,
  1084. &logi);
  1085. if( pLoggedInPort == NULL )
  1086. {
  1087. printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
  1088. // Now Q a LOGOut Request, since we won't be talking to that device
  1089. NeedReject = TRUE;
  1090. // set reject reason code
  1091. ls_reject_code =
  1092. LS_RJT_REASON( LOGICAL_ERROR, NO_LOGIN_RESOURCES);
  1093. }
  1094. }
  1095. if( !NeedReject )
  1096. {
  1097. // OK - we have valid fcPort ptr; set fields accordingly.
  1098. // (not PDISC, not Originator)
  1099. SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
  1100. // send 'ACC' reply
  1101. cpqfcTSPutLinkQue( cpqfcHBAdata,
  1102. ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
  1103. fchs );
  1104. }
  1105. }
  1106. else // Payload unacceptable
  1107. {
  1108. printk("payload unacceptable\n");
  1109. NeedReject = TRUE; // reject code already set
  1110. }
  1111. if( NeedReject)
  1112. {
  1113. // The PDISC failed. Set login struct flags accordingly,
  1114. // terminate any I/O to this port, and Q a PLOGI
  1115. pLoggedInPort->pdisc = FALSE;
  1116. pLoggedInPort->prli = FALSE;
  1117. pLoggedInPort->plogi = FALSE;
  1118. fchs->reserved = ls_reject_code; // borrow this (unused) field
  1119. // send 'RJT' reply
  1120. cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs );
  1121. }
  1122. // terminate any exchanges with this device...
  1123. if( pLoggedInPort )
  1124. {
  1125. cpqfcTSTerminateExchange( cpqfcHBAdata,
  1126. &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
  1127. }
  1128. break;
  1129. case 0x1020: // PRLI?
  1130. {
  1131. BOOLEAN NeedReject = TRUE;
  1132. pLoggedInPort = fcFindLoggedInPort(
  1133. fcChip,
  1134. NULL, // don't search Scsi Nexus
  1135. (fchs->s_id & 0xFFFFFF), // search linked list for port_id
  1136. NULL, // DON'T search linked list for WWN
  1137. NULL); // don't care
  1138. if( pLoggedInPort == NULL )
  1139. {
  1140. // huh?
  1141. printk(" Unexpected PRLI Request -not logged in!\n");
  1142. // set reject reason code
  1143. ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
  1144. // Q a LOGOut here?
  1145. }
  1146. else
  1147. {
  1148. // verify the PRLI ACC payload
  1149. if( !verify_PRLI( fchs, &ls_reject_code) )
  1150. {
  1151. // PRLI Reply is acceptable; were we expecting it?
  1152. if( pLoggedInPort->plogi )
  1153. {
  1154. // yes, we expected the PRLI ACC (not PDISC; not Originator)
  1155. SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
  1156. // Q an ACCept Reply
  1157. cpqfcTSPutLinkQue( cpqfcHBAdata,
  1158. ELS_PRLI_ACC,
  1159. fchs );
  1160. NeedReject = FALSE;
  1161. }
  1162. else
  1163. {
  1164. // huh?
  1165. printk(" (unexpected) PRLI REQEST with plogi FALSE\n");
  1166. // set reject reason code
  1167. ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
  1168. // Q a LOGOut here?
  1169. }
  1170. }
  1171. else
  1172. {
  1173. printk(" PRLI REQUEST payload failed verify\n");
  1174. // (reject code set by "verify")
  1175. // Q a LOGOut here?
  1176. }
  1177. }
  1178. if( NeedReject )
  1179. {
  1180. // Q a ReJecT Reply with reason code
  1181. fchs->reserved = ls_reject_code;
  1182. cpqfcTSPutLinkQue( cpqfcHBAdata,
  1183. ELS_RJT, // Q Type
  1184. fchs );
  1185. }
  1186. }
  1187. break;
  1188. case 0x0005: // LOGOut?
  1189. {
  1190. // was this LOGOUT because we sent a ELS_PDISC to an FC device
  1191. // with changed (or new) port_id, or does the port refuse
  1192. // to communicate to us?
  1193. // We maintain a logout counter - if we get 3 consecutive LOGOuts,
  1194. // give up!
  1195. LOGOUT_PAYLOAD logo;
  1196. BOOLEAN GiveUpOnDevice = FALSE;
  1197. ULONG ls_reject_code = 0;
  1198. BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logo, sizeof(logo));
  1199. pLoggedInPort = fcFindLoggedInPort(
  1200. fcChip,
  1201. NULL, // don't search Scsi Nexus
  1202. 0, // don't search linked list for port_id
  1203. &logo.port_name[0], // search linked list for WWN
  1204. NULL); // don't care about end of list
  1205. if( pLoggedInPort ) // found the device?
  1206. {
  1207. // Q an ACC reply
  1208. cpqfcTSPutLinkQue( cpqfcHBAdata,
  1209. ELS_LOGO_ACC, // Q Type
  1210. fchs ); // device to respond to
  1211. // set login struct fields (LOGO_counter increment)
  1212. SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
  1213. // are we an Initiator?
  1214. if( fcChip->Options.initiator)
  1215. {
  1216. // we're an Initiator, so check if we should
  1217. // try (another?) login
  1218. // Fabrics routinely log out from us after
  1219. // getting device info - don't try to log them
  1220. // back in.
  1221. if( (fchs->s_id & 0xFFF000) == 0xFFF000 )
  1222. {
  1223. ; // do nothing
  1224. }
  1225. else if( pLoggedInPort->LOGO_counter <= 3)
  1226. {
  1227. // try (another) login (PLOGI request)
  1228. cpqfcTSPutLinkQue( cpqfcHBAdata,
  1229. ELS_PLOGI, // Q Type
  1230. fchs );
  1231. // Terminate I/O with "retry" potential
  1232. cpqfcTSTerminateExchange( cpqfcHBAdata,
  1233. &pLoggedInPort->ScsiNexus,
  1234. PORTID_CHANGED);
  1235. }
  1236. else
  1237. {
  1238. printk(" Got 3 LOGOuts - terminating comm. with port_id %Xh\n",
  1239. fchs->s_id &&0xFFFFFF);
  1240. GiveUpOnDevice = TRUE;
  1241. }
  1242. }
  1243. else
  1244. {
  1245. GiveUpOnDevice = TRUE;
  1246. }
  1247. if( GiveUpOnDevice == TRUE )
  1248. {
  1249. cpqfcTSTerminateExchange( cpqfcHBAdata,
  1250. &pLoggedInPort->ScsiNexus,
  1251. DEVICE_REMOVED);
  1252. }
  1253. }
  1254. else // we don't know this WWN!
  1255. {
  1256. // Q a ReJecT Reply wit…

Large files files are truncated, but you can click here to view the full file