File: /usr/src/linux/drivers/scsi/cpqfcTSworker.c
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
22 #include <linux/sched.h>
23 #include <linux/timer.h>
24 #include <linux/string.h>
25 #include <linux/slab.h>
26 #include <linux/ioport.h>
27 #include <linux/kernel.h>
28 #include <linux/stat.h>
29 #include <linux/blk.h>
30 #include <linux/interrupt.h>
31 #include <linux/delay.h>
32 #include <linux/smp_lock.h>
33
34 #define __KERNEL_SYSCALLS__
35
36 #define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM))
37
38 #include <linux/unistd.h>
39
40 #include <asm/system.h>
41 #include <asm/irq.h>
42 #include <asm/dma.h>
43
44
45
46 #include "sd.h"
47 #include "hosts.h" // struct Scsi_Host definition for T handler
48 #include "cpqfcTSchip.h"
49 #include "cpqfcTSstructs.h"
50 #include "cpqfcTStrigger.h"
51
52 //#define LOGIN_DBG 1
53
54 // REMARKS:
55 // Since Tachyon chips may be permitted to wait from 500ms up to 2 sec
56 // to empty an outgoing frame from its FIFO to the Fibre Channel stream,
57 // we cannot do everything we need to in the interrupt handler. Specifically,
58 // every time a link re-init (e.g. LIP) takes place, all SCSI I/O has to be
59 // suspended until the login sequences have been completed. Login commands
60 // are frames just like SCSI commands are frames; they are subject to the same
61 // timeout issues and delays. Also, various specs provide up to 2 seconds for
62 // devices to log back in (i.e. respond with ACC to a login frame), so I/O to
63 // that device has to be suspended.
64 // A serious problem here occurs on highly loaded FC-AL systems. If our FC port
65 // has a low priority (e.g. high arbitrated loop physical address, alpa), and
66 // some other device is hogging bandwidth (permissible under FC-AL), we might
67 // time out thinking the link is hung, when it's simply busy. Many such
68 // considerations complicate the design. Although Tachyon assumes control
69 // (in silicon) for many link-specific issues, the Linux driver is left with the
70 // rest, which turns out to be a difficult, time critical chore.
71
72 // These "worker" functions will handle things like FC Logins; all
73 // processes with I/O to our device must wait for the Login to complete
74 // and (if successful) I/O to resume. In the event of a malfunctioning or
75 // very busy loop, it may take hundreds of millisecs or even seconds to complete
76 // a frame send. We don't want to hang up the entire server (and all
77 // processes which don't depend on Fibre) during this wait.
78
79 // The Tachyon chip can have around 30,000 I/O operations ("exchanges")
80 // open at one time. However, each exchange must be initiated
81 // synchronously (i.e. each of the 30k I/O had to be started one at a
82 // time by sending a starting frame via Tachyon's outbound que).
83
84 // To accomodate kernel "module" build, this driver limits the exchanges
85 // to 256, because of the contiguous physical memory limitation of 128M.
86
87 // Typical FC Exchanges are opened presuming the FC frames start without errors,
88 // while Exchange completion is handled in the interrupt handler. This
89 // optimizes performance for the "everything's working" case.
90 // However, when we have FC related errors or hot plugging of FC ports, we pause
91 // I/O and handle FC-specific tasks in the worker thread. These FC-specific
92 // functions will handle things like FC Logins and Aborts. As the Login sequence
93 // completes to each and every target, I/O can resume to that target.
94
95 // Our kernel "worker thread" must share the HBA with threads calling
96 // "queuecommand". We define a "BoardLock" semaphore which indicates
97 // to "queuecommand" that the HBA is unavailable, and Cmnds are added to a
98 // board lock Q. When the worker thread finishes with the board, the board
99 // lock Q commands are completed with status causing immediate retry.
100 // Typically, the board is locked while Logins are in progress after an
101 // FC Link Down condition. When Cmnds are re-queued after board lock, the
102 // particular Scsi channel/target may or may not have logged back in. When
103 // the device is waiting for login, the "prli" flag is clear, in which case
104 // commands are passed to a Link Down Q. Whenever the login finally completes,
105 // the LinkDown Q is completed, again with status causing immediate retry.
106 // When FC devices are logged in, we build and start FC commands to the
107 // devices.
108
109 // NOTE!! As of May 2000, kernel 2.2.14, the error recovery logic for devices
110 // that never log back in (e.g. physically removed) is NOT completely
111 // understood. I've still seen instances of system hangs on failed Write
112 // commands (possibly from the ext2 layer?) on device removal. Such special
113 // cases need to be evaluated from a system/application view - e.g., how
114 // exactly does the system want me to complete commands when the device is
115 // physically removed??
116
117 // local functions
118
119 static void SetLoginFields(
120 PFC_LOGGEDIN_PORT pLoggedInPort,
121 TachFCHDR_GCMND* fchs,
122 BOOLEAN PDisc,
123 BOOLEAN Originator);
124
125 static void AnalyzeIncomingFrame(
126 CPQFCHBA *cpqfcHBAdata,
127 ULONG QNdx );
128
129 static void SendLogins( CPQFCHBA *cpqfcHBAdata, __u32 *FabricPortIds );
130
131 static int verify_PLOGI( PTACHYON fcChip,
132 TachFCHDR_GCMND* fchs, ULONG* reject_explain);
133 static int verify_PRLI( TachFCHDR_GCMND* fchs, ULONG* reject_explain);
134
135 static void LoadWWN( PTACHYON fcChip, UCHAR* dest, UCHAR type);
136 static void BuildLinkServicePayload(
137 PTACHYON fcChip, ULONG type, void* payload);
138
139 static void UnblockScsiDevice( struct Scsi_Host *HostAdapter,
140 PFC_LOGGEDIN_PORT pLoggedInPort);
141
142 static void cpqfcTSCheckandSnoopFCP( PTACHYON fcChip, ULONG x_ID);
143
144 static void CompleteBoardLockCmnd( CPQFCHBA *cpqfcHBAdata);
145
146 static void RevalidateSEST( struct Scsi_Host *HostAdapter,
147 PFC_LOGGEDIN_PORT pLoggedInPort);
148
149 static void IssueReportLunsCommand(
150 CPQFCHBA* cpqfcHBAdata,
151 TachFCHDR_GCMND* fchs);
152
153 // (see scsi_error.c comments on kernel task creation)
154
155 void cpqfcTSWorkerThread( void *host)
156 {
157 struct Scsi_Host *HostAdapter = (struct Scsi_Host*)host;
158 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
159 #ifdef PCI_KERNEL_TRACE
160 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
161 #endif
162 struct fs_struct *fs;
163 DECLARE_MUTEX_LOCKED(fcQueReady);
164 DECLARE_MUTEX_LOCKED(fcTYOBcomplete);
165 DECLARE_MUTEX_LOCKED(TachFrozen);
166 DECLARE_MUTEX_LOCKED(BoardLock);
167
168 ENTER("WorkerThread");
169
170 lock_kernel();
171 /*
172 * If we were started as result of loading a module, close all of the
173 * user space pages. We don't need them, and if we didn't close them
174 * they would be locked into memory.
175 */
176 exit_mm(current);
177
178 current->session = 1;
179 current->pgrp = 1;
180
181 /* Become as one with the init task */
182
183 exit_fs(current); /* current->fs->count--; */
184 fs = init_task.fs;
185 // Some kernels compiled for SMP, while actually running
186 // on a uniproc machine, will return NULL for this call
187 if( !fs)
188 {
189 printk(" cpqfcTS FATAL: fs is NULL! Is this an SMP kernel on uniproc machine?\n ");
190 }
191
192 else
193 {
194 current->fs = fs;
195 atomic_inc(&fs->count);
196 }
197
198 siginitsetinv(¤t->blocked, SHUTDOWN_SIGS);
199
200
201 /*
202 * Set the name of this process.
203 */
204 sprintf(current->comm, "cpqfcTS_wt_%d", HostAdapter->host_no);
205
206 cpqfcHBAdata->fcQueReady = &fcQueReady; // primary wait point
207 cpqfcHBAdata->TYOBcomplete = &fcTYOBcomplete;
208 cpqfcHBAdata->TachFrozen = &TachFrozen;
209
210
211 cpqfcHBAdata->worker_thread = current;
212
213 unlock_kernel();
214
215 if( cpqfcHBAdata->notify_wt != NULL )
216 up( cpqfcHBAdata->notify_wt); // OK to continue
217
218 while(1)
219 {
220 unsigned long flags;
221
222 down_interruptible( &fcQueReady); // wait for something to do
223
224 if (signal_pending(current) )
225 break;
226
227 PCI_TRACE( 0x90)
228 // first, take the IO lock so the SCSI upper layers can't call
229 // into our _quecommand function (this also disables INTs)
230 spin_lock_irqsave( &io_request_lock, flags); // STOP _que function
231 PCI_TRACE( 0x90)
232
233 CPQ_SPINLOCK_HBA( cpqfcHBAdata)
234 // next, set this pointer to indicate to the _quecommand function
235 // that the board is in use, so it should que the command and
236 // immediately return (we don't actually require the semaphore function
237 // in this driver rev)
238
239 cpqfcHBAdata->BoardLock = &BoardLock;
240
241 PCI_TRACE( 0x90)
242
243 // release the IO lock (and re-enable interrupts)
244 spin_unlock_irqrestore( &io_request_lock, flags);
245
246 // disable OUR HBA interrupt (keep them off as much as possible
247 // during error recovery)
248 disable_irq( cpqfcHBAdata->HostAdapter->irq);
249
250 // OK, let's process the Fibre Channel Link Q and do the work
251 cpqfcTS_WorkTask( HostAdapter);
252
253 // hopefully, no more "work" to do;
254 // re-enable our INTs for "normal" completion processing
255 enable_irq( cpqfcHBAdata->HostAdapter->irq);
256
257
258 cpqfcHBAdata->BoardLock = NULL; // allow commands to be queued
259 CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
260
261
262 // Now, complete any Cmnd we Q'd up while BoardLock was held
263
264 CompleteBoardLockCmnd( cpqfcHBAdata);
265
266
267 }
268 // hopefully, the signal was for our module exit...
269 if( cpqfcHBAdata->notify_wt != NULL )
270 up( cpqfcHBAdata->notify_wt); // yep, we're outta here
271 }
272
273
274 // Freeze Tachyon routine.
275 // If Tachyon is already frozen, return FALSE
276 // If Tachyon is not frozen, call freeze function, return TRUE
277 //
278 static BOOLEAN FreezeTach( CPQFCHBA *cpqfcHBAdata)
279 {
280 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
281 BOOLEAN FrozeTach = FALSE;
282 // It's possible that the chip is already frozen; if so,
283 // "Freezing" again will NOT! generate another Freeze
284 // Completion Message.
285
286 if( (fcChip->Registers.TYstatus.value & 0x70000) != 0x70000)
287 { // (need to freeze...)
288 fcChip->FreezeTachyon( fcChip, 2); // both ERQ and FCP assists
289
290 // 2. Get Tach freeze confirmation
291 // (synchronize SEST manipulation with Freeze Completion Message)
292 // we need INTs on so semaphore can be set.
293 enable_irq( cpqfcHBAdata->HostAdapter->irq); // only way to get Semaphore
294 down_interruptible( cpqfcHBAdata->TachFrozen); // wait for INT handler sem.
295 // can we TIMEOUT semaphore wait?? TBD
296 disable_irq( cpqfcHBAdata->HostAdapter->irq);
297
298 FrozeTach = TRUE;
299 } // (else, already frozen)
300
301 return FrozeTach;
302 }
303
304
305
306
307 // This is the kernel worker thread task, which processes FC
308 // tasks which were queued by the Interrupt handler or by
309 // other WorkTask functions.
310
311 #define DBG 1
312 //#undef DBG
313 void cpqfcTS_WorkTask( struct Scsi_Host *HostAdapter)
314 {
315 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
316 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
317 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
318 ULONG QconsumerNdx;
319 LONG ExchangeID;
320 ULONG ulStatus=0;
321 TachFCHDR_GCMND fchs;
322 PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
323
324 ENTER("WorkTask");
325
326 // copy current index to work on
327 QconsumerNdx = fcLQ->consumer;
328
329 PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x90)
330
331
332 // NOTE: when this switch completes, we will "consume" the Que item
333 // printk("Que type %Xh\n", fcLQ->Qitem[QconsumerNdx].Type);
334 switch( fcLQ->Qitem[QconsumerNdx].Type )
335 {
336 // incoming frame - link service (ACC, UNSOL REQ, etc.)
337 // or FCP-SCSI command
338 case SFQ_UNKNOWN:
339 AnalyzeIncomingFrame( cpqfcHBAdata, QconsumerNdx );
340
341 break;
342
343
344
345 case EXCHANGE_QUEUED: // an Exchange (i.e. FCP-SCSI) was previously
346 // Queued because the link was down. The
347 // heartbeat timer detected it and Queued it here.
348 // We attempt to start it again, and if
349 // successful we clear the EXCHANGE_Q flag.
350 // If the link doesn't come up, the Exchange
351 // will eventually time-out.
352
353 ExchangeID = (LONG) // x_ID copied from DPC timeout function
354 fcLQ->Qitem[QconsumerNdx].ulBuff[0];
355
356 // It's possible that a Q'd exchange could have already
357 // been started by other logic (e.g. ABTS process)
358 // Don't start if already started (Q'd flag clear)
359
360 if( Exchanges->fcExchange[ExchangeID].status & EXCHANGE_QUEUED )
361 {
362 // printk(" *Start Q'd x_ID %Xh: type %Xh ",
363 // ExchangeID, Exchanges->fcExchange[ExchangeID].type);
364
365 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID);
366 if( !ulStatus )
367 {
368 // printk("success* ");
369 }
370 else
371 {
372 #ifdef DBG
373
374 if( ulStatus == EXCHANGE_QUEUED)
375 printk("Queued* ");
376 else
377 printk("failed* ");
378
379 #endif
380 }
381 }
382 break;
383
384
385 case LINKDOWN:
386 // (lots of things already done in INT handler) future here?
387 break;
388
389
390 case LINKACTIVE: // Tachyon set the Lup bit in FM status
391 // NOTE: some misbehaving FC ports (like Tach2.1)
392 // can re-LIP immediately after a LIP completes.
393
394 // if "initiator", need to verify LOGs with ports
395 // printk("\n*LNKUP* ");
396
397 if( fcChip->Options.initiator )
398 SendLogins( cpqfcHBAdata, NULL ); // PLOGI or PDISC, based on fcPort data
399 // if SendLogins successfully completes, PortDiscDone
400 // will be set.
401
402
403 // If SendLogins was successful, then we expect to get incoming
404 // ACCepts or REJECTs, which are handled below.
405
406 break;
407
408 // LinkService and Fabric request/reply processing
409 case ELS_FDISC: // need to send Fabric Discovery (Login)
410 case ELS_FLOGI: // need to send Fabric Login
411 case ELS_SCR: // need to send State Change Registration
412 case FCS_NSR: // need to send Name Service Request
413 case ELS_PLOGI: // need to send PLOGI
414 case ELS_ACC: // send generic ACCept
415 case ELS_PLOGI_ACC: // need to send ELS ACCept frame to recv'd PLOGI
416 case ELS_PRLI_ACC: // need to send ELS ACCept frame to recv'd PRLI
417 case ELS_LOGO: // need to send ELS LOGO (logout)
418 case ELS_LOGO_ACC: // need to send ELS ACCept frame to recv'd PLOGI
419 case ELS_RJT: // ReJecT reply
420 case ELS_PRLI: // need to send ELS PRLI
421
422
423 // printk(" *ELS %Xh* ", fcLQ->Qitem[QconsumerNdx].Type);
424 // if PortDiscDone is not set, it means the SendLogins routine
425 // failed to complete -- assume that LDn occurred, so login frames
426 // are invalid
427 if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn
428 {
429 printk("Discard Q'd ELS login frame\n");
430 break;
431 }
432
433 ulStatus = cpqfcTSBuildExchange(
434 cpqfcHBAdata,
435 fcLQ->Qitem[QconsumerNdx].Type, // e.g. PLOGI
436 (TachFCHDR_GCMND*)
437 fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
438 NULL, // no data (no scatter/gather list)
439 &ExchangeID );// fcController->fcExchanges index, -1 if failed
440
441 if( !ulStatus ) // Exchange setup?
442 {
443 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
444 if( !ulStatus )
445 {
446 // submitted to Tach's Outbound Que (ERQ PI incremented)
447 // waited for completion for ELS type (Login frames issued
448 // synchronously)
449 }
450 else
451 // check reason for Exchange not being started - we might
452 // want to Queue and start later, or fail with error
453 {
454
455 }
456 }
457
458 else // Xchange setup failed...
459 printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
460
461 break;
462
463 case SCSI_REPORT_LUNS:
464 // pass the incoming frame (actually, it's a PRLI frame)
465 // so we can send REPORT_LUNS, in order to determine VSA/PDU
466 // FCP-SCSI Lun address mode
467 IssueReportLunsCommand( cpqfcHBAdata, (TachFCHDR_GCMND*)
468 fcLQ->Qitem[QconsumerNdx].ulBuff);
469
470 break;
471
472
473
474
475 case BLS_ABTS: // need to ABORT one or more exchanges
476 {
477 LONG x_ID = fcLQ->Qitem[QconsumerNdx].ulBuff[0];
478 BOOLEAN FrozeTach = FALSE;
479
480 if( x_ID > TACH_SEST_LEN ) // (in)sanity check
481 {
482 // printk( " cpqfcTS ERROR! BOGUS x_ID %Xh", x_ID);
483 break;
484 }
485
486
487 if( Exchanges->fcExchange[ x_ID].Cmnd == NULL ) // should be RARE
488 {
489 // printk(" ABTS %Xh Scsi Cmnd null! ", x_ID);
490
491 break; // nothing to abort!
492 }
493
494 //#define ABTS_DBG
495 #ifdef ABTS_DBG
496 printk("INV SEST[%X] ", x_ID);
497 if( Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT)
498 {
499 printk("FC2TO");
500 }
501 if( Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT)
502 {
503 printk("IA");
504 }
505 if( Exchanges->fcExchange[x_ID].status & PORTID_CHANGED)
506 {
507 printk("PORTID");
508 }
509 if( Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED)
510 {
511 printk("DEVRM");
512 }
513 if( Exchanges->fcExchange[x_ID].status & LINKFAIL_TX)
514 {
515 printk("LKF");
516 }
517 if( Exchanges->fcExchange[x_ID].status & FRAME_TO)
518 {
519 printk("FRMTO");
520 }
521 if( Exchanges->fcExchange[x_ID].status & ABORTSEQ_NOTIFY)
522 {
523 printk("ABSQ");
524 }
525 if( Exchanges->fcExchange[x_ID].status & SFQ_FRAME)
526 {
527 printk("SFQFR");
528 }
529
530 if( Exchanges->fcExchange[ x_ID].type == 0x2000)
531 printk(" WR");
532 else if( Exchanges->fcExchange[ x_ID].type == 0x3000)
533 printk(" RD");
534 else if( Exchanges->fcExchange[ x_ID].type == 0x10)
535 printk(" ABTS");
536 else
537 printk(" %Xh", Exchanges->fcExchange[ x_ID].type);
538
539 if( !(Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT))
540 {
541 printk(" Cmd %p, ",
542 Exchanges->fcExchange[ x_ID].Cmnd);
543
544 printk(" brd/chn/trg/lun %d/%d/%d/%d port_id %06X\n",
545 cpqfcHBAdata->HBAnum,
546 Exchanges->fcExchange[ x_ID].Cmnd->channel,
547 Exchanges->fcExchange[ x_ID].Cmnd->target,
548 Exchanges->fcExchange[ x_ID].Cmnd->lun,
549 Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF);
550 }
551 else // assume that Cmnd ptr is invalid on _abort()
552 {
553 printk(" Cmd ptr invalid\n");
554 }
555
556 #endif
557
558
559 // Steps to ABORT a SEST exchange:
560 // 1. Freeze TL SCSI assists & ERQ (everything)
561 // 2. Receive FROZEN inbound CM (must succeed!)
562 // 3. Invalidate x_ID SEST entry
563 // 4. Resume TL SCSI assists & ERQ (everything)
564 // 5. Build/start on exchange - change "type" to BLS_ABTS,
565 // timeout to X sec (RA_TOV from PLDA is actually 0)
566 // 6. Set Exchange Q'd status if ABTS cannot be started,
567 // or simply complete Exchange in "Terminate" condition
568
569 PCI_TRACEO( x_ID, 0xB4)
570
571 // 1 & 2 . Freeze Tach & get confirmation of freeze
572 FrozeTach = FreezeTach( cpqfcHBAdata);
573
574 // 3. OK, Tachyon is frozen, so we can invalidate SEST exchange.
575 // FC2_TIMEOUT means we are originating the abort, while
576 // TARGET_ABORT means we are ACCepting an abort.
577 // LINKFAIL_TX, ABORTSEQ_NOFITY, INV_ENTRY or FRAME_TO are
578 // all from Tachyon:
579 // Exchange was corrupted by LDn or other FC physical failure
580 // INITIATOR_ABORT means the upper layer driver/application
581 // requested the abort.
582
583
584
585 // clear bit 31 (VALid), to invalidate & take control from TL
586 fcChip->SEST->u[ x_ID].IWE.Hdr_Len &= 0x7FFFFFFF;
587
588
589 // examine and Tach's "Linked List" for IWEs that
590 // received (nearly) simultaneous transfer ready (XRDY)
591 // repair linked list if necessary (TBD!)
592 // (If we ignore the "Linked List", we will time out
593 // WRITE commands where we received the FCP-SCSI XFRDY
594 // frame (because Tachyon didn't processes it). Linked List
595 // management should be done as an optimization.
596
597 // readl( fcChip->Registers.ReMapMemBase+TL_MEM_SEST_LINKED_LIST ));
598
599
600
601
602 // 4. Resume all Tachlite functions (for other open Exchanges)
603 // as quickly as possible to allow other exchanges to other ports
604 // to resume. Freezing Tachyon may cause cascading errors, because
605 // any received SEST frame cannot be processed by the SEST.
606 // Don't "unfreeze" unless Link is operational
607 if( FrozeTach ) // did we just freeze it (above)?
608 fcChip->UnFreezeTachyon( fcChip, 2); // both ERQ and FCP assists
609
610
611 PCI_TRACEO( x_ID, 0xB4)
612
613 // Note there is no confirmation that the chip is "unfrozen". Also,
614 // if the Link is down when unfreeze is called, it has no effect.
615 // Chip will unfreeze when the Link is back up.
616
617 // 5. Now send out Abort commands if possible
618 // Some Aborts can't be "sent" (Port_id changed or gone);
619 // if the device is gone, there is no port_id to send the ABTS to.
620
621 if( !(Exchanges->fcExchange[ x_ID].status & PORTID_CHANGED)
622 &&
623 !(Exchanges->fcExchange[ x_ID].status & DEVICE_REMOVED) )
624 {
625 Exchanges->fcExchange[ x_ID].type = BLS_ABTS;
626 fchs.s_id = Exchanges->fcExchange[ x_ID].fchs.d_id;
627 ulStatus = cpqfcTSBuildExchange(
628 cpqfcHBAdata,
629 BLS_ABTS,
630 &fchs, // (uses only s_id)
631 NULL, // (no scatter/gather list for ABTS)
632 &x_ID );// ABTS on this Exchange ID
633
634 if( !ulStatus ) // Exchange setup build OK?
635 {
636
637 // ABTS may be needed because an Exchange was corrupted
638 // by a Link disruption. If the Link is UP, we can
639 // presume that this ABTS can start immediately; otherwise,
640 // set Que'd status so the Login functions
641 // can restart it when the FC physical Link is restored
642 if( ((fcChip->Registers.FMstatus.value &0xF0) &0x80)) // loop init?
643 {
644 // printk(" *set Q status x_ID %Xh on LDn* ", x_ID);
645 Exchanges->fcExchange[ x_ID].status |= EXCHANGE_QUEUED;
646 }
647
648 else // what FC device (port_id) does the Cmd belong to?
649 {
650 PFC_LOGGEDIN_PORT pLoggedInPort =
651 Exchanges->fcExchange[ x_ID].pLoggedInPort;
652
653 // if Port is logged in, we might start the abort.
654
655 if( (pLoggedInPort != NULL)
656 &&
657 (pLoggedInPort->prli == TRUE) )
658 {
659 // it's possible that an Exchange has already been Queued
660 // to start after Login completes. Check and don't
661 // start it (again) here if Q'd status set
662 // printk(" ABTS xchg %Xh ", x_ID);
663 if( Exchanges->fcExchange[x_ID].status & EXCHANGE_QUEUED)
664 {
665 // printk("already Q'd ");
666 }
667 else
668 {
669 // printk("starting ");
670
671 fcChip->fcStats.FC2aborted++;
672 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, x_ID );
673 if( !ulStatus )
674 {
675 // OK
676 // submitted to Tach's Outbound Que (ERQ PI incremented)
677 }
678 else
679 {
680 /* printk("ABTS exchange start failed -status %Xh, x_ID %Xh ",
681 ulStatus, x_ID);
682 */
683 }
684 }
685 }
686 else
687 {
688 /* printk(" ABTS NOT starting xchg %Xh, %p ",
689 x_ID, pLoggedInPort);
690 if( pLoggedInPort )
691 printk("prli %d ", pLoggedInPort->prli);
692 */
693 }
694 }
695 }
696 else // what the #@!
697 { // how do we fail to build an Exchange for ABTS??
698 printk("ABTS exchange build failed -status %Xh, x_ID %Xh\n",
699 ulStatus, x_ID);
700 }
701 }
702 else // abort without ABTS -- just complete exchange/Cmnd to Linux
703 {
704 // printk(" *Terminating x_ID %Xh on %Xh* ",
705 // x_ID, Exchanges->fcExchange[x_ID].status);
706 cpqfcTSCompleteExchange( fcChip, x_ID);
707
708
709 }
710 } // end of ABTS case
711 break;
712
713
714
715 case BLS_ABTS_ACC: // need to ACCept one ABTS
716 // (NOTE! this code not updated for Linux yet..)
717
718
719 printk(" *ABTS_ACC* ");
720 // 1. Freeze TL
721
722 fcChip->FreezeTachyon( fcChip, 2); // both ERQ and FCP assists
723
724 memcpy( // copy the incoming ABTS frame
725 &fchs,
726 fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
727 sizeof( fchs));
728
729 // 3. OK, Tachyon is frozen so we can invalidate SEST entry
730 // (if necessary)
731 // Status FC2_TIMEOUT means we are originating the abort, while
732 // TARGET_ABORT means we are ACCepting an abort
733
734 ExchangeID = fchs.ox_rx_id & 0x7FFF; // RX_ID for exchange
735 // printk("ABTS ACC for Target ExchangeID %Xh\n", ExchangeID);
736
737
738 // sanity check on received ExchangeID
739 if( Exchanges->fcExchange[ ExchangeID].status == TARGET_ABORT )
740 {
741 // clear bit 31 (VALid), to invalidate & take control from TL
742 // printk("Invalidating SEST exchange %Xh\n", ExchangeID);
743 fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len &= 0x7FFFFFFF;
744 }
745
746
747 // 4. Resume all Tachlite functions (for other open Exchanges)
748 // as quickly as possible to allow other exchanges to other ports
749 // to resume. Freezing Tachyon for too long may royally screw
750 // up everything!
751 fcChip->UnFreezeTachyon( fcChip, 2); // both ERQ and FCP assists
752
753 // Note there is no confirmation that the chip is "unfrozen". Also,
754 // if the Link is down when unfreeze is called, it has no effect.
755 // Chip will unfreeze when the Link is back up.
756
757 // 5. Now send out Abort ACC reply for this exchange
758 Exchanges->fcExchange[ ExchangeID].type = BLS_ABTS_ACC;
759
760 fchs.s_id = Exchanges->fcExchange[ ExchangeID].fchs.d_id;
761 ulStatus = cpqfcTSBuildExchange(
762 cpqfcHBAdata,
763 BLS_ABTS_ACC,
764 &fchs,
765 NULL, // no data (no scatter/gather list)
766 &ExchangeID );// fcController->fcExchanges index, -1 if failed
767
768 if( !ulStatus ) // Exchange setup?
769 {
770 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
771 if( !ulStatus )
772 {
773 // submitted to Tach's Outbound Que (ERQ PI incremented)
774 // waited for completion for ELS type (Login frames issued
775 // synchronously)
776 }
777 else
778 // check reason for Exchange not being started - we might
779 // want to Queue and start later, or fail with error
780 {
781
782 }
783 }
784 break;
785
786
787 case BLS_ABTS_RJT: // need to ReJecT one ABTS; reject implies the
788 // exchange doesn't exist in the TARGET context.
789 // ExchangeID has to come from LinkService space.
790
791 printk(" *ABTS_RJT* ");
792 ulStatus = cpqfcTSBuildExchange(
793 cpqfcHBAdata,
794 BLS_ABTS_RJT,
795 (TachFCHDR_GCMND*)
796 fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
797 NULL, // no data (no scatter/gather list)
798 &ExchangeID );// fcController->fcExchanges index, -1 if failed
799
800 if( !ulStatus ) // Exchange setup OK?
801 {
802 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
803 // If it fails, we aren't required to retry.
804 }
805 if( ulStatus )
806 {
807 printk("Failed to send BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
808 }
809 else
810 {
811 printk("Sent BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
812
813 }
814
815 break;
816
817
818
819 default:
820 break;
821 } // end switch
822 //doNothing:
823 // done with this item - now set the NEXT index
824
825 if( QconsumerNdx+1 >= FC_LINKQ_DEPTH ) // rollover test
826 {
827 fcLQ->consumer = 0;
828 }
829 else
830 {
831 fcLQ->consumer++;
832 }
833
834 PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x94)
835
836 LEAVE("WorkTask");
837 return;
838 }
839
840
841
842
843 // When Tachyon reports link down, bad al_pa, or Link Service (e.g. Login)
844 // commands come in, post to the LinkQ so that action can be taken outside the
845 // interrupt handler.
846 // This circular Q works like Tachyon's que - the producer points to the next
847 // (unused) entry. Called by Interrupt handler, WorkerThread, Timer
848 // sputlinkq
849 void cpqfcTSPutLinkQue( CPQFCHBA *cpqfcHBAdata,
850 int Type,
851 void *QueContent)
852 {
853 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
854 // FC_EXCHANGES *Exchanges = fcChip->Exchanges;
855 PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
856 ULONG ndx;
857
858 ENTER("cpqfcTSPutLinkQ");
859
860 ndx = fcLQ->producer;
861
862 ndx += 1; // test for Que full
863
864
865
866 if( ndx >= FC_LINKQ_DEPTH ) // rollover test
867 ndx = 0;
868
869 if( ndx == fcLQ->consumer ) // QUE full test
870 {
871 // QUE was full! lost LK command (fatal to logic)
872 fcChip->fcStats.lnkQueFull++;
873
874 printk("*LinkQ Full!*");
875 TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
876 /*
877 {
878 int i;
879 printk("LinkQ PI %d, CI %d\n", fcLQ->producer,
880 fcLQ->consumer);
881
882 for( i=0; i< FC_LINKQ_DEPTH; )
883 {
884 printk(" [%d]%Xh ", i, fcLQ->Qitem[i].Type);
885 if( (++i %8) == 0) printk("\n");
886 }
887
888 }
889 */
890 printk( "cpqfcTS: WARNING!! PutLinkQue - FULL!\n"); // we're hung
891 }
892 else // QUE next element
893 {
894 // Prevent certain multiple (back-to-back) requests.
895 // This is important in that we don't want to issue multiple
896 // ABTS for the same Exchange, or do multiple FM inits, etc.
897 // We can never be sure of the timing of events reported to
898 // us by Tach's IMQ, which can depend on system/bus speeds,
899 // FC physical link circumstances, etc.
900
901 if( (fcLQ->producer != fcLQ->consumer)
902 &&
903 (Type == FMINIT) )
904 {
905 LONG lastNdx; // compute previous producer index
906 if( fcLQ->producer)
907 lastNdx = fcLQ->producer- 1;
908 else
909 lastNdx = FC_LINKQ_DEPTH-1;
910
911
912 if( fcLQ->Qitem[lastNdx].Type == FMINIT)
913 {
914 // printk(" *skip FMINIT Q post* ");
915 // goto DoneWithPutQ;
916 }
917
918 }
919
920 // OK, add the Q'd item...
921
922 fcLQ->Qitem[fcLQ->producer].Type = Type;
923
924 memcpy(
925 fcLQ->Qitem[fcLQ->producer].ulBuff,
926 QueContent,
927 sizeof(fcLQ->Qitem[fcLQ->producer].ulBuff));
928
929 fcLQ->producer = ndx; // increment Que producer
930
931 // set semaphore to wake up Kernel (worker) thread
932 //
933 up( cpqfcHBAdata->fcQueReady );
934 }
935
936 //DoneWithPutQ:
937
938 LEAVE("cpqfcTSPutLinkQ");
939 }
940
941
942
943
944 // reset device ext FC link Q
945 void cpqfcTSLinkQReset( CPQFCHBA *cpqfcHBAdata)
946
947 {
948 PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
949 fcLQ->producer = 0;
950 fcLQ->consumer = 0;
951
952 }
953
954
955
956
957
958 // When Tachyon gets an unassisted FCP-SCSI frame, post here so
959 // an arbitrary context thread (e.g. IOCTL loopback test function)
960 // can process it.
961
962 // (NOTE: Not revised for Linux)
963 // This Q works like Tachyon's que - the producer points to the next
964 // (unused) entry.
965 void cpqfcTSPutScsiQue( CPQFCHBA *cpqfcHBAdata,
966 int Type,
967 void *QueContent)
968 {
969 // CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
970 // PTACHYON fcChip = &cpqfcHBAdata->fcChip;
971
972 // ULONG ndx;
973
974 // ULONG *pExchangeID;
975 // LONG ExchangeID;
976
977 /*
978 KeAcquireSpinLockAtDpcLevel( &pDevExt->fcScsiQueLock);
979 ndx = pDevExt->fcScsiQue.producer + 1; // test for Que full
980
981 if( ndx >= FC_SCSIQ_DEPTH ) // rollover test
982 ndx = 0;
983
984 if( ndx == pDevExt->fcScsiQue.consumer ) // QUE full test
985 {
986 // QUE was full! lost LK command (fatal to logic)
987 fcChip->fcStats.ScsiQueFull++;
988 #ifdef DBG
989 printk( "fcPutScsiQue - FULL!\n");
990 #endif
991
992 }
993 else // QUE next element
994 {
995 pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].Type = Type;
996
997 if( Type == FCP_RSP )
998 {
999 // this TL inbound message type means that a TL SEST exchange has
1000 // copied an FCP response frame into a buffer pointed to by the SEST
1001 // entry. That buffer is allocated in the SEST structure at ->RspHDR.
1002 // Copy the RspHDR for use by the Que handler.
1003 pExchangeID = (ULONG *)QueContent;
1004
1005 memcpy(
1006 pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff,
1007 &fcChip->SEST->RspHDR[ *pExchangeID ],
1008 sizeof(pDevExt->fcScsiQue.Qitem[0].ulBuff)); // (any element for size)
1009
1010 }
1011 else
1012 {
1013 memcpy(
1014 pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff,
1015 QueContent,
1016 sizeof(pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff));
1017 }
1018
1019 pDevExt->fcScsiQue.producer = ndx; // increment Que
1020
1021
1022 KeSetEvent( &pDevExt->TYIBscsi, // signal any waiting thread
1023 0, // no priority boost
1024 FALSE ); // no waiting later for this event
1025 }
1026 KeReleaseSpinLockFromDpcLevel( &pDevExt->fcScsiQueLock);
1027 */
1028 }
1029
1030
1031
1032
1033
1034
1035
1036 static void ProcessELS_Request( CPQFCHBA*,TachFCHDR_GCMND*);
1037
1038 static void ProcessELS_Reply( CPQFCHBA*,TachFCHDR_GCMND*);
1039
1040 static void ProcessFCS_Reply( CPQFCHBA*,TachFCHDR_GCMND*);
1041
1042 void cpqfcTSImplicitLogout( CPQFCHBA* cpqfcHBAdata,
1043 PFC_LOGGEDIN_PORT pFcPort)
1044 {
1045 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1046
1047 if( pFcPort->port_id != 0xFFFC01 ) // don't care about Fabric
1048 {
1049 fcChip->fcStats.logouts++;
1050 printk("cpqfcTS: Implicit logout of WWN %08X%08X, port_id %06X\n",
1051 (ULONG)pFcPort->u.liWWN,
1052 (ULONG)(pFcPort->u.liWWN >>32),
1053 pFcPort->port_id);
1054
1055 // Terminate I/O with this (Linux) Scsi target
1056 cpqfcTSTerminateExchange( cpqfcHBAdata,
1057 &pFcPort->ScsiNexus,
1058 DEVICE_REMOVED);
1059 }
1060
1061 // Do an "implicit logout" - we can't really Logout the device
1062 // (i.e. with LOGOut Request) because of port_id confusion
1063 // (i.e. the Other port has no port_id).
1064 // A new login for that WWN will have to re-write port_id (0 invalid)
1065 pFcPort->port_id = 0; // invalid!
1066 pFcPort->pdisc = FALSE;
1067 pFcPort->prli = FALSE;
1068 pFcPort->plogi = FALSE;
1069 pFcPort->flogi = FALSE;
1070 pFcPort->LOGO_timer = 0;
1071 pFcPort->device_blocked = TRUE; // block Scsi Requests
1072 pFcPort->ScsiNexus.VolumeSetAddressing=0;
1073 }
1074
1075
1076 // On FC-AL, there is a chance that a previously known device can
1077 // be quietly removed (e.g. with non-managed hub),
1078 // while a NEW device (with different WWN) took the same alpa or
1079 // even 24-bit port_id. This chance is unlikely but we must always
1080 // check for it.
1081 static void TestDuplicatePortId( CPQFCHBA* cpqfcHBAdata,
1082 PFC_LOGGEDIN_PORT pLoggedInPort)
1083 {
1084 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1085 // set "other port" at beginning of fcPorts list
1086 PFC_LOGGEDIN_PORT pOtherPortWithPortId = fcChip->fcPorts.pNextPort;
1087 while( pOtherPortWithPortId )
1088 {
1089 if( (pOtherPortWithPortId->port_id ==
1090 pLoggedInPort->port_id)
1091 &&
1092 (pOtherPortWithPortId != pLoggedInPort) )
1093 {
1094 // trouble! (Implicitly) Log the other guy out
1095 printk(" *port_id %Xh is duplicated!* ",
1096 pOtherPortWithPortId->port_id);
1097 cpqfcTSImplicitLogout( cpqfcHBAdata, pOtherPortWithPortId);
1098 }
1099 pOtherPortWithPortId = pOtherPortWithPortId->pNextPort;
1100 }
1101 }
1102
1103
1104
1105
1106
1107
1108 // Dynamic Memory Allocation for newly discovered FC Ports.
1109 // For simplicity, maintain fcPorts structs for ALL
1110 // for discovered devices, including those we never do I/O with
1111 // (e.g. Fabric addresses)
1112
1113 static PFC_LOGGEDIN_PORT CreateFcPort(
1114 CPQFCHBA* cpqfcHBAdata,
1115 PFC_LOGGEDIN_PORT pLastLoggedInPort,
1116 TachFCHDR_GCMND* fchs,
1117 LOGIN_PAYLOAD* plogi)
1118 {
1119 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1120 PFC_LOGGEDIN_PORT pNextLoggedInPort = NULL;
1121 int i;
1122
1123
1124 printk("cpqfcTS: New FC port %06Xh WWN: ", fchs->s_id);
1125 for( i=3; i>=0; i--) // copy the LOGIN port's WWN
1126 printk("%02X", plogi->port_name[i]);
1127 for( i=7; i>3; i--) // copy the LOGIN port's WWN
1128 printk("%02X", plogi->port_name[i]);
1129
1130
1131 // allocate mem for new port
1132 // (these are small and rare allocations...)
1133 pNextLoggedInPort = kmalloc( sizeof( FC_LOGGEDIN_PORT), GFP_ATOMIC );
1134
1135
1136 // allocation succeeded? Fill out NEW PORT
1137 if( pNextLoggedInPort )
1138 {
1139 // clear out any garbage (sometimes exists)
1140 memset( pNextLoggedInPort, 0, sizeof( FC_LOGGEDIN_PORT));
1141
1142
1143 // If we login to a Fabric, we don't want to treat it
1144 // as a SCSI device...
1145 if( (fchs->s_id & 0xFFF000) != 0xFFF000)
1146 {
1147 int i;
1148
1149 // create a unique "virtual" SCSI Nexus (for now, just a
1150 // new target ID) -- we will update channel/target on REPORT_LUNS
1151 // special case for very first SCSI target...
1152 if( cpqfcHBAdata->HostAdapter->max_id == 0)
1153 {
1154 pNextLoggedInPort->ScsiNexus.target = 0;
1155 fcChip->fcPorts.ScsiNexus.target = -1; // don't use "stub"
1156 }
1157 else
1158 {
1159 pNextLoggedInPort->ScsiNexus.target =
1160 cpqfcHBAdata->HostAdapter->max_id;
1161 }
1162
1163 // initialize the lun[] Nexus struct for lun masking
1164 for( i=0; i< CPQFCTS_MAX_LUN; i++)
1165 pNextLoggedInPort->ScsiNexus.lun[i] = 0xFF; // init to NOT USED
1166
1167 pNextLoggedInPort->ScsiNexus.channel = 0; // cpqfcTS has 1 FC port
1168
1169 printk(" SCSI Chan/Trgt %d/%d",
1170 pNextLoggedInPort->ScsiNexus.channel,
1171 pNextLoggedInPort->ScsiNexus.target);
1172
1173 // tell Scsi layers about the new target...
1174 cpqfcHBAdata->HostAdapter->max_id++;
1175 // printk("HostAdapter->max_id = %d\n",
1176 // cpqfcHBAdata->HostAdapter->max_id);
1177 }
1178 else
1179 {
1180 // device is NOT SCSI (in case of Fabric)
1181 pNextLoggedInPort->ScsiNexus.target = -1; // invalid
1182 }
1183
1184 // create forward link to new port
1185 pLastLoggedInPort->pNextPort = pNextLoggedInPort;
1186 printk("\n");
1187
1188 }
1189 return pNextLoggedInPort; // NULL on allocation failure
1190 } // end NEW PORT (WWN) logic
1191
1192
1193
1194 // For certain cases, we want to terminate exchanges without
1195 // sending ABTS to the device. Examples include when an FC
1196 // device changed it's port_id after Loop re-init, or when
1197 // the device sent us a logout. In the case of changed port_id,
1198 // we want to complete the command and return SOFT_ERROR to
1199 // force a re-try. In the case of LOGOut, we might return
1200 // BAD_TARGET if the device is really gone.
1201 // Since we must ensure that Tachyon is not operating on the
1202 // exchange, we have to freeze the chip
1203 // sterminateex
1204 void cpqfcTSTerminateExchange(
1205 CPQFCHBA* cpqfcHBAdata, SCSI_NEXUS *ScsiNexus, int TerminateStatus)
1206 {
1207 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1208 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1209 ULONG x_ID;
1210
1211 if( ScsiNexus )
1212 {
1213 // printk("TerminateExchange: ScsiNexus chan/target %d/%d\n",
1214 // ScsiNexus->channel, ScsiNexus->target);
1215
1216 }
1217
1218 for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
1219 {
1220 if( Exchanges->fcExchange[x_ID].type ) // in use?
1221 {
1222 if( ScsiNexus == NULL ) // our HBA changed - term. all
1223 {
1224 Exchanges->fcExchange[x_ID].status = TerminateStatus;
1225 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID );
1226 }
1227 else
1228 {
1229 // If a device, according to WWN, has been removed, it's
1230 // port_id may be used by another working device, so we
1231 // have to terminate by SCSI target, NOT port_id.
1232 if( Exchanges->fcExchange[x_ID].Cmnd) // Cmnd in progress?
1233 {
1234 if( (Exchanges->fcExchange[x_ID].Cmnd->target == ScsiNexus->target)
1235 &&
1236 (Exchanges->fcExchange[x_ID].Cmnd->channel == ScsiNexus->channel))
1237 {
1238 Exchanges->fcExchange[x_ID].status = TerminateStatus;
1239 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID ); // timed-out
1240 }
1241 }
1242
1243 // (in case we ever need it...)
1244 // all SEST structures have a remote node ID at SEST DWORD 2
1245 // if( (fcChip->SEST->u[ x_ID ].TWE.Remote_Node_ID >> 8)
1246 // == port_id)
1247 }
1248 }
1249 }
1250 }
1251
1252
1253 static void ProcessELS_Request(
1254 CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
1255 {
1256 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1257 // FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1258 // ULONG ox_id = (fchs->ox_rx_id >>16);
1259 PFC_LOGGEDIN_PORT pLoggedInPort=NULL, pLastLoggedInPort;
1260 BOOLEAN NeedReject = FALSE;
1261 ULONG ls_reject_code = 0; // default don'n know??
1262
1263
1264 // Check the incoming frame for a supported ELS type
1265 switch( fchs->pl[0] & 0xFFFF)
1266 {
1267 case 0x0050: // PDISC?
1268
1269 // Payload for PLOGI and PDISC is identical (request & reply)
1270 if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload?
1271 {
1272 LOGIN_PAYLOAD logi; // FC-PH Port Login
1273
1274 // PDISC payload OK. If critical login fields
1275 // (e.g. WWN) matches last login for this port_id,
1276 // we may resume any prior exchanges
1277 // with the other port
1278
1279
1280 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
1281
1282 pLoggedInPort = fcFindLoggedInPort(
1283 fcChip,
1284 NULL, // don't search Scsi Nexus
1285 0, // don't search linked list for port_id
1286 &logi.port_name[0], // search linked list for WWN
1287 &pLastLoggedInPort); // must return non-NULL; when a port_id
1288 // is not found, this pointer marks the
1289 // end of the singly linked list
1290
1291 if( pLoggedInPort != NULL) // WWN found (prior login OK)
1292 {
1293
1294 if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id)
1295 {
1296 // Yes. We were expecting PDISC?
1297 if( pLoggedInPort->pdisc )
1298 {
1299 // Yes; set fields accordingly. (PDISC, not Originator)
1300 SetLoginFields( pLoggedInPort, fchs, TRUE, FALSE);
1301
1302 // send 'ACC' reply
1303 cpqfcTSPutLinkQue( cpqfcHBAdata,
1304 ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
1305 fchs );
1306
1307 // OK to resume I/O...
1308 }
1309 else
1310 {
1311 printk("Not expecting PDISC (pdisc=FALSE)\n");
1312 NeedReject = TRUE;
1313 // set reject reason code
1314 ls_reject_code =
1315 LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
1316 }
1317 }
1318 else
1319 {
1320 if( pLoggedInPort->port_id != 0)
1321 {
1322 printk("PDISC PortID change: old %Xh, new %Xh\n",
1323 pLoggedInPort->port_id, fchs->s_id &0xFFFFFF);
1324 }
1325 NeedReject = TRUE;
1326 // set reject reason code
1327 ls_reject_code =
1328 LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
1329
1330 }
1331 }
1332 else
1333 {
1334 printk("PDISC Request from unknown WWN\n");
1335 NeedReject = TRUE;
1336
1337 // set reject reason code
1338 ls_reject_code =
1339 LS_RJT_REASON( LOGICAL_ERROR, INVALID_PORT_NAME);
1340 }
1341
1342 }
1343 else // Payload unacceptable
1344 {
1345 printk("payload unacceptable\n");
1346 NeedReject = TRUE; // reject code already set
1347
1348 }
1349
1350 if( NeedReject)
1351 {
1352 ULONG port_id;
1353 // The PDISC failed. Set login struct flags accordingly,
1354 // terminate any I/O to this port, and Q a PLOGI
1355 if( pLoggedInPort )
1356 {
1357 pLoggedInPort->pdisc = FALSE;
1358 pLoggedInPort->prli = FALSE;
1359 pLoggedInPort->plogi = FALSE;
1360
1361 cpqfcTSTerminateExchange( cpqfcHBAdata,
1362 &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1363 port_id = pLoggedInPort->port_id;
1364 }
1365 else
1366 {
1367 port_id = fchs->s_id &0xFFFFFF;
1368 }
1369 fchs->reserved = ls_reject_code; // borrow this (unused) field
1370 cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs );
1371 }
1372
1373 break;
1374
1375
1376
1377 case 0x0003: // PLOGI?
1378
1379 // Payload for PLOGI and PDISC is identical (request & reply)
1380 if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload?
1381 {
1382 LOGIN_PAYLOAD logi; // FC-PH Port Login
1383 BOOLEAN NeedReject = FALSE;
1384
1385 // PDISC payload OK. If critical login fields
1386 // (e.g. WWN) matches last login for this port_id,
1387 // we may resume any prior exchanges
1388 // with the other port
1389
1390
1391 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
1392
1393 pLoggedInPort = fcFindLoggedInPort(
1394 fcChip,
1395 NULL, // don't search Scsi Nexus
1396 0, // don't search linked list for port_id
1397 &logi.port_name[0], // search linked list for WWN
1398 &pLastLoggedInPort); // must return non-NULL; when a port_id
1399 // is not found, this pointer marks the
1400 // end of the singly linked list
1401
1402 if( pLoggedInPort == NULL) // WWN not found -New Port
1403 {
1404 pLoggedInPort = CreateFcPort(
1405 cpqfcHBAdata,
1406 pLastLoggedInPort,
1407 fchs,
1408 &logi);
1409 if( pLoggedInPort == NULL )
1410 {
1411 printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
1412 // Now Q a LOGOut Request, since we won't be talking to that device
1413
1414 NeedReject = TRUE;
1415
1416 // set reject reason code
1417 ls_reject_code =
1418 LS_RJT_REASON( LOGICAL_ERROR, NO_LOGIN_RESOURCES);
1419
1420 }
1421 }
1422 if( !NeedReject )
1423 {
1424
1425 // OK - we have valid fcPort ptr; set fields accordingly.
1426 // (not PDISC, not Originator)
1427 SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
1428
1429 // send 'ACC' reply
1430 cpqfcTSPutLinkQue( cpqfcHBAdata,
1431 ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
1432 fchs );
1433 }
1434 }
1435 else // Payload unacceptable
1436 {
1437 printk("payload unacceptable\n");
1438 NeedReject = TRUE; // reject code already set
1439 }
1440
1441 if( NeedReject)
1442 {
1443 // The PDISC failed. Set login struct flags accordingly,
1444 // terminate any I/O to this port, and Q a PLOGI
1445 pLoggedInPort->pdisc = FALSE;
1446 pLoggedInPort->prli = FALSE;
1447 pLoggedInPort->plogi = FALSE;
1448
1449 fchs->reserved = ls_reject_code; // borrow this (unused) field
1450
1451 // send 'RJT' reply
1452 cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs );
1453 }
1454
1455 // terminate any exchanges with this device...
1456 if( pLoggedInPort )
1457 {
1458 cpqfcTSTerminateExchange( cpqfcHBAdata,
1459 &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1460 }
1461 break;
1462
1463
1464
1465 case 0x1020: // PRLI?
1466 {
1467 BOOLEAN NeedReject = TRUE;
1468 pLoggedInPort = fcFindLoggedInPort(
1469 fcChip,
1470 NULL, // don't search Scsi Nexus
1471 (fchs->s_id & 0xFFFFFF), // search linked list for port_id
1472 NULL, // DON'T search linked list for WWN
1473 NULL); // don't care
1474
1475 if( pLoggedInPort == NULL )
1476 {
1477 // huh?
1478 printk(" Unexpected PRLI Request -not logged in!\n");
1479
1480 // set reject reason code
1481 ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
1482
1483 // Q a LOGOut here?
1484 }
1485 else
1486 {
1487 // verify the PRLI ACC payload
1488 if( !verify_PRLI( fchs, &ls_reject_code) )
1489 {
1490 // PRLI Reply is acceptable; were we expecting it?
1491 if( pLoggedInPort->plogi )
1492 {
1493 // yes, we expected the PRLI ACC (not PDISC; not Originator)
1494 SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
1495
1496 // Q an ACCept Reply
1497 cpqfcTSPutLinkQue( cpqfcHBAdata,
1498 ELS_PRLI_ACC,
1499 fchs );
1500
1501 NeedReject = FALSE;
1502 }
1503 else
1504 {
1505 // huh?
1506 printk(" (unexpected) PRLI REQEST with plogi FALSE\n");
1507
1508 // set reject reason code
1509 ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
1510
1511 // Q a LOGOut here?
1512
1513 }
1514 }
1515 else
1516 {
1517 printk(" PRLI REQUEST payload failed verify\n");
1518 // (reject code set by "verify")
1519
1520 // Q a LOGOut here?
1521 }
1522 }
1523
1524 if( NeedReject )
1525 {
1526 // Q a ReJecT Reply with reason code
1527 fchs->reserved = ls_reject_code;
1528 cpqfcTSPutLinkQue( cpqfcHBAdata,
1529 ELS_RJT, // Q Type
1530 fchs );
1531 }
1532 }
1533 break;
1534
1535
1536
1537
1538 case 0x0005: // LOGOut?
1539 {
1540 // was this LOGOUT because we sent a ELS_PDISC to an FC device
1541 // with changed (or new) port_id, or does the port refuse
1542 // to communicate to us?
1543 // We maintain a logout counter - if we get 3 consecutive LOGOuts,
1544 // give up!
1545 LOGOUT_PAYLOAD logo;
1546 BOOLEAN GiveUpOnDevice = FALSE;
1547 ULONG ls_reject_code = 0;
1548
1549 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logo, sizeof(logo));
1550
1551 pLoggedInPort = fcFindLoggedInPort(
1552 fcChip,
1553 NULL, // don't search Scsi Nexus
1554 0, // don't search linked list for port_id
1555 &logo.port_name[0], // search linked list for WWN
1556 NULL); // don't care about end of list
1557
1558 if( pLoggedInPort ) // found the device?
1559 {
1560 // Q an ACC reply
1561 cpqfcTSPutLinkQue( cpqfcHBAdata,
1562 ELS_LOGO_ACC, // Q Type
1563 fchs ); // device to respond to
1564
1565 // set login struct fields (LOGO_counter increment)
1566 SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
1567
1568 // are we an Initiator?
1569 if( fcChip->Options.initiator)
1570 {
1571 // we're an Initiator, so check if we should
1572 // try (another?) login
1573
1574 // Fabrics routinely log out from us after
1575 // getting device info - don't try to log them
1576 // back in.
1577 if( (fchs->s_id & 0xFFF000) == 0xFFF000 )
1578 {
1579 ; // do nothing
1580 }
1581 else if( pLoggedInPort->LOGO_counter <= 3)
1582 {
1583 // try (another) login (PLOGI request)
1584
1585 cpqfcTSPutLinkQue( cpqfcHBAdata,
1586 ELS_PLOGI, // Q Type
1587 fchs );
1588
1589 // Terminate I/O with "retry" potential
1590 cpqfcTSTerminateExchange( cpqfcHBAdata,
1591 &pLoggedInPort->ScsiNexus,
1592 PORTID_CHANGED);
1593 }
1594 else
1595 {
1596 printk(" Got 3 LOGOuts - terminating comm. with port_id %Xh\n",
1597 fchs->s_id &&0xFFFFFF);
1598 GiveUpOnDevice = TRUE;
1599 }
1600 }
1601 else
1602 {
1603 GiveUpOnDevice = TRUE;
1604 }
1605
1606
1607 if( GiveUpOnDevice == TRUE )
1608 {
1609 cpqfcTSTerminateExchange( cpqfcHBAdata,
1610 &pLoggedInPort->ScsiNexus,
1611 DEVICE_REMOVED);
1612 }
1613 }
1614 else // we don't know this WWN!
1615 {
1616 // Q a ReJecT Reply with reason code
1617 fchs->reserved = ls_reject_code;
1618 cpqfcTSPutLinkQue( cpqfcHBAdata,
1619 ELS_RJT, // Q Type
1620 fchs );
1621 }
1622 }
1623 break;
1624
1625
1626
1627
1628 // FABRIC only case
1629 case 0x0461: // ELS RSCN (Registered State Change Notification)?
1630 {
1631 int Ports;
1632 int i;
1633 __u32 Buff;
1634 // Typically, one or more devices have been added to or dropped
1635 // from the Fabric.
1636 // The format of this frame is defined in FC-FLA (Rev 2.7, Aug 1997)
1637 // The first 32-bit word has a 2-byte Payload Length, which
1638 // includes the 4 bytes of the first word. Consequently,
1639 // this PL len must never be less than 4, must be a multiple of 4,
1640 // and has a specified max value 256.
1641 // (Endianess!)
1642 Ports = ((fchs->pl[0] >>24) - 4) / 4;
1643 Ports = Ports > 63 ? 63 : Ports;
1644
1645 printk(" RSCN ports: %d\n", Ports);
1646 if( Ports <= 0 ) // huh?
1647 {
1648 // ReJecT the command
1649 fchs->reserved = LS_RJT_REASON( UNABLE_TO_PERFORM, 0);
1650
1651 cpqfcTSPutLinkQue( cpqfcHBAdata,
1652 ELS_RJT, // Q Type
1653 fchs );
1654
1655 break;
1656 }
1657 else // Accept the command
1658 {
1659 cpqfcTSPutLinkQue( cpqfcHBAdata,
1660 ELS_ACC, // Q Type
1661 fchs );
1662 }
1663
1664 // Check the "address format" to determine action.
1665 // We have 3 cases:
1666 // 0 = Port Address; 24-bit address of affected device
1667 // 1 = Area Address; MS 16 bits valid
1668 // 2 = Domain Address; MS 8 bits valid
1669 for( i=0; i<Ports; i++)
1670 {
1671 BigEndianSwap( (UCHAR*)&fchs->pl[i+1],(UCHAR*)&Buff, 4);
1672 switch( Buff & 0xFF000000)
1673 {
1674
1675 case 0: // Port Address?
1676
1677 case 0x01000000: // Area Domain?
1678 case 0x02000000: // Domain Address
1679 // For example, "port_id" 0x201300
1680 // OK, let's try a Name Service Request (Query)
1681 fchs->s_id = 0xFFFFFC; // Name Server Address
1682 cpqfcTSPutLinkQue( cpqfcHBAdata, FCS_NSR, fchs);
1683
1684 break;
1685
1686
1687 default: // huh? new value on version change?
1688 break;
1689 }
1690 }
1691 }
1692 break;
1693
1694
1695
1696
1697 default: // don't support this request (yet)
1698 // set reject reason code
1699 fchs->reserved = LS_RJT_REASON( UNABLE_TO_PERFORM,
1700 REQUEST_NOT_SUPPORTED);
1701
1702 cpqfcTSPutLinkQue( cpqfcHBAdata,
1703 ELS_RJT, // Q Type
1704 fchs );
1705 break;
1706 }
1707 }
1708
1709
1710 static void ProcessELS_Reply(
1711 CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
1712 {
1713 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1714 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1715 ULONG ox_id = (fchs->ox_rx_id >>16);
1716 ULONG ls_reject_code;
1717 PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
1718
1719 // If this is a valid reply, then we MUST have sent a request.
1720 // Verify that we can find a valid request OX_ID corresponding to
1721 // this reply
1722
1723
1724 if( Exchanges->fcExchange[(fchs->ox_rx_id >>16)].type == 0)
1725 {
1726 printk(" *Discarding ACC/RJT frame, xID %04X/%04X* ",
1727 ox_id, fchs->ox_rx_id & 0xffff);
1728 goto Quit; // exit this routine
1729 }
1730
1731
1732 // Is the reply a RJT (reject)?
1733 if( (fchs->pl[0] & 0xFFFFL) == 0x01) // Reject reply?
1734 {
1735 // ****** REJECT REPLY ********
1736 switch( Exchanges->fcExchange[ox_id].type )
1737 {
1738
1739 case ELS_FDISC: // we sent out Fabric Discovery
1740 case ELS_FLOGI: // we sent out FLOGI
1741
1742 printk("RJT received on Fabric Login from %Xh, reason %Xh\n",
1743 fchs->s_id, fchs->pl[1]);
1744
1745 break;
1746
1747 default:
1748 break;
1749 }
1750
1751 goto Done;
1752 }
1753
1754 // OK, we have an ACCept...
1755 // What's the ACC type? (according to what we sent)
1756 switch( Exchanges->fcExchange[ox_id].type )
1757 {
1758
1759 case ELS_PLOGI: // we sent out PLOGI
1760 if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) )
1761 {
1762 LOGIN_PAYLOAD logi; // FC-PH Port Login
1763
1764 // login ACC payload acceptable; search for WWN in our list
1765 // of fcPorts
1766
1767 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
1768
1769 pLoggedInPort = fcFindLoggedInPort(
1770 fcChip,
1771 NULL, // don't search Scsi Nexus
1772 0, // don't search linked list for port_id
1773 &logi.port_name[0], // search linked list for WWN
1774 &pLastLoggedInPort); // must return non-NULL; when a port_id
1775 // is not found, this pointer marks the
1776 // end of the singly linked list
1777
1778 if( pLoggedInPort == NULL) // WWN not found - new port
1779 {
1780
1781 pLoggedInPort = CreateFcPort(
1782 cpqfcHBAdata,
1783 pLastLoggedInPort,
1784 fchs,
1785 &logi);
1786
1787 if( pLoggedInPort == NULL )
1788 {
1789 printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
1790 // Now Q a LOGOut Request, since we won't be talking to that device
1791
1792 goto Done; // exit with error! dropped login frame
1793 }
1794 }
1795 else // WWN was already known. Ensure that any open
1796 // exchanges for this WWN are terminated.
1797 // NOTE: It's possible that a device can change its
1798 // 24-bit port_id after a Link init or Fabric change
1799 // (e.g. LIP or Fabric RSCN). In that case, the old
1800 // 24-bit port_id may be duplicated, or no longer exist.
1801 {
1802
1803 cpqfcTSTerminateExchange( cpqfcHBAdata,
1804 &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1805 }
1806
1807 // We have an fcPort struct - set fields accordingly
1808 // not PDISC, originator
1809 SetLoginFields( pLoggedInPort, fchs, FALSE, TRUE);
1810
1811 // We just set a "port_id"; is it duplicated?
1812 TestDuplicatePortId( cpqfcHBAdata, pLoggedInPort);
1813
1814 // For Fabric operation, we issued PLOGI to 0xFFFFFC
1815 // so we can send SCR (State Change Registration)
1816 // Check for this special case...
1817 if( fchs->s_id == 0xFFFFFC )
1818 {
1819 // PLOGI ACC was a Fabric response... issue SCR
1820 fchs->s_id = 0xFFFFFD; // address for SCR
1821 cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_SCR, fchs);
1822 }
1823
1824 else
1825 {
1826 // Now we need a PRLI to enable FCP-SCSI operation
1827 // set flags and Q up a ELS_PRLI
1828 cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PRLI, fchs);
1829 }
1830 }
1831 else
1832 {
1833 // login payload unacceptable - reason in ls_reject_code
1834 // Q up a Logout Request
1835 printk("Login Payload unacceptable\n");
1836
1837 }
1838 break;
1839
1840
1841 // PDISC logic very similar to PLOGI, except we never want
1842 // to allocate mem for "new" port, and we set flags differently
1843 // (might combine later with PLOGI logic for efficiency)
1844 case ELS_PDISC: // we sent out PDISC
1845 if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) )
1846 {
1847 LOGIN_PAYLOAD logi; // FC-PH Port Login
1848 BOOLEAN NeedLogin = FALSE;
1849
1850 // login payload acceptable; search for WWN in our list
1851 // of (previously seen) fcPorts
1852
1853 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
1854
1855 pLoggedInPort = fcFindLoggedInPort(
1856 fcChip,
1857 NULL, // don't search Scsi Nexus
1858 0, // don't search linked list for port_id
1859 &logi.port_name[0], // search linked list for WWN
1860 &pLastLoggedInPort); // must return non-NULL; when a port_id
1861 // is not found, this pointer marks the
1862 // end of the singly linked list
1863
1864 if( pLoggedInPort != NULL) // WWN found?
1865 {
1866 // WWN has same port_id as last login? (Of course, a properly
1867 // working FC device should NEVER ACCept a PDISC if it's
1868 // port_id changed, but check just in case...)
1869 if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id)
1870 {
1871 // Yes. We were expecting PDISC?
1872 if( pLoggedInPort->pdisc )
1873 {
1874 int i;
1875
1876
1877 // PDISC expected -- set fields. (PDISC, Originator)
1878 SetLoginFields( pLoggedInPort, fchs, TRUE, TRUE);
1879
1880 // We are ready to resume FCP-SCSI to this device...
1881 // Do we need to start anything that was Queued?
1882
1883 for( i=0; i< TACH_SEST_LEN; i++)
1884 {
1885 // see if any exchange for this PDISC'd port was queued
1886 if( ((fchs->s_id &0xFFFFFF) ==
1887 (Exchanges->fcExchange[i].fchs.d_id & 0xFFFFFF))
1888 &&
1889 (Exchanges->fcExchange[i].status & EXCHANGE_QUEUED))
1890 {
1891 fchs->reserved = i; // copy ExchangeID
1892 // printk(" *Q x_ID %Xh after PDISC* ",i);
1893
1894 cpqfcTSPutLinkQue( cpqfcHBAdata, EXCHANGE_QUEUED, fchs );
1895 }
1896 }
1897
1898 // Complete commands Q'd while we were waiting for Login
1899
1900 UnblockScsiDevice( cpqfcHBAdata->HostAdapter, pLoggedInPort);
1901 }
1902 else
1903 {
1904 printk("Not expecting PDISC (pdisc=FALSE)\n");
1905 NeedLogin = TRUE;
1906 }
1907 }
1908 else
1909 {
1910 printk("PDISC PortID change: old %Xh, new %Xh\n",
1911 pLoggedInPort->port_id, fchs->s_id &0xFFFFFF);
1912 NeedLogin = TRUE;
1913
1914 }
1915 }
1916 else
1917 {
1918 printk("PDISC ACC from unknown WWN\n");
1919 NeedLogin = TRUE;
1920 }
1921
1922 if( NeedLogin)
1923 {
1924
1925 // The PDISC failed. Set login struct flags accordingly,
1926 // terminate any I/O to this port, and Q a PLOGI
1927 if( pLoggedInPort ) // FC device previously known?
1928 {
1929
1930 cpqfcTSPutLinkQue( cpqfcHBAdata,
1931 ELS_LOGO, // Q Type
1932 fchs ); // has port_id to send to
1933
1934 // There are a variety of error scenarios which can result
1935 // in PDISC failure, so as a catchall, add the check for
1936 // duplicate port_id.
1937 TestDuplicatePortId( cpqfcHBAdata, pLoggedInPort);
1938
1939 // TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
1940 pLoggedInPort->pdisc = FALSE;
1941 pLoggedInPort->prli = FALSE;
1942 pLoggedInPort->plogi = FALSE;
1943
1944 cpqfcTSTerminateExchange( cpqfcHBAdata,
1945 &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
1946 }
1947 cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, fchs );
1948 }
1949 }
1950 else
1951 {
1952 // login payload unacceptable - reason in ls_reject_code
1953 // Q up a Logout Request
1954 printk("ERROR: Login Payload unacceptable!\n");
1955
1956 }
1957
1958 break;
1959
1960
1961
1962 case ELS_PRLI: // we sent out PRLI
1963
1964
1965 pLoggedInPort = fcFindLoggedInPort(
1966 fcChip,
1967 NULL, // don't search Scsi Nexus
1968 (fchs->s_id & 0xFFFFFF), // search linked list for port_id
1969 NULL, // DON'T search linked list for WWN
1970 NULL); // don't care
1971
1972 if( pLoggedInPort == NULL )
1973 {
1974 // huh?
1975 printk(" Unexpected PRLI ACCept frame!\n");
1976
1977 // Q a LOGOut here?
1978
1979 goto Done;
1980 }
1981
1982 // verify the PRLI ACC payload
1983 if( !verify_PRLI( fchs, &ls_reject_code) )
1984 {
1985 // PRLI Reply is acceptable; were we expecting it?
1986 if( pLoggedInPort->plogi )
1987 {
1988 // yes, we expected the PRLI ACC (not PDISC; Originator)
1989 SetLoginFields( pLoggedInPort, fchs, FALSE, TRUE);
1990
1991 // OK, let's send a REPORT_LUNS command to determine
1992 // whether VSA or PDA FCP-LUN addressing is used.
1993
1994 cpqfcTSPutLinkQue( cpqfcHBAdata, SCSI_REPORT_LUNS, fchs );
1995
1996 // It's possible that a device we were talking to changed
1997 // port_id, and has logged back in. This function ensures
1998 // that I/O will resume.
1999 UnblockScsiDevice( cpqfcHBAdata->HostAdapter, pLoggedInPort);
2000
2001 }
2002 else
2003 {
2004 // huh?
2005 printk(" (unexpected) PRLI ACCept with plogi FALSE\n");
2006
2007 // Q a LOGOut here?
2008 goto Done;
2009 }
2010 }
2011 else
2012 {
2013 printk(" PRLI ACCept payload failed verify\n");
2014
2015 // Q a LOGOut here?
2016 }
2017
2018 break;
2019
2020 case ELS_FLOGI: // we sent out FLOGI (Fabric Login)
2021
2022 // update the upper 16 bits of our port_id in Tachyon
2023 // the switch adds those upper 16 bits when responding
2024 // to us (i.e. we are the destination_id)
2025 fcChip->Registers.my_al_pa = (fchs->d_id & 0xFFFFFF);
2026 writel( fcChip->Registers.my_al_pa,
2027 fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
2028
2029 // now send out a PLOGI to the well known port_id 0xFFFFFC
2030 fchs->s_id = 0xFFFFFC;
2031 cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, fchs);
2032
2033 break;
2034
2035
2036 case ELS_FDISC: // we sent out FDISC (Fabric Discovery (Login))
2037
2038 printk( " ELS_FDISC success ");
2039 break;
2040
2041
2042 case ELS_SCR: // we sent out State Change Registration
2043 // now we can issue Name Service Request to find any
2044 // Fabric-connected devices we might want to login to.
2045
2046
2047 fchs->s_id = 0xFFFFFC; // Name Server Address
2048 cpqfcTSPutLinkQue( cpqfcHBAdata, FCS_NSR, fchs);
2049
2050
2051 break;
2052
2053
2054 default:
2055 printk(" *Discarding unknown ACC frame, xID %04X/%04X* ",
2056 ox_id, fchs->ox_rx_id & 0xffff);
2057 break;
2058 }
2059
2060
2061 Done:
2062 // Regardless of whether the Reply is valid or not, the
2063 // the exchange is done - complete
2064 cpqfcTSCompleteExchange( fcChip, (fchs->ox_rx_id >>16)); // complete
2065
2066 Quit:
2067 return;
2068 }
2069
2070
2071
2072
2073
2074
2075 // **************** Fibre Channel Services **************
2076 // This is where we process the Directory (Name) Service Reply
2077 // to know which devices are on the Fabric
2078
2079 static void ProcessFCS_Reply(
2080 CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
2081 {
2082 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2083 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
2084 ULONG ox_id = (fchs->ox_rx_id >>16);
2085 // ULONG ls_reject_code;
2086 // PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
2087
2088 // If this is a valid reply, then we MUST have sent a request.
2089 // Verify that we can find a valid request OX_ID corresponding to
2090 // this reply
2091
2092 if( Exchanges->fcExchange[(fchs->ox_rx_id >>16)].type == 0)
2093 {
2094 printk(" *Discarding Reply frame, xID %04X/%04X* ",
2095 ox_id, fchs->ox_rx_id & 0xffff);
2096 goto Quit; // exit this routine
2097 }
2098
2099
2100 // OK, we were expecting it. Now check to see if it's a
2101 // "Name Service" Reply, and if so force a re-validation of
2102 // Fabric device logins (i.e. Start the login timeout and
2103 // send PDISC or PLOGI)
2104 // (Endianess Byte Swap?)
2105 if( fchs->pl[1] == 0x02FC ) // Name Service
2106 {
2107 // got a new (or NULL) list of Fabric attach devices...
2108 // Invalidate current logins
2109
2110 PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
2111 while( pLoggedInPort ) // for all ports which are expecting
2112 // PDISC after the next LIP, set the
2113 // logoutTimer
2114 {
2115
2116 if( (pLoggedInPort->port_id & 0xFFFF00) // Fabric device?
2117 &&
2118 (pLoggedInPort->port_id != 0xFFFFFC) ) // NOT the F_Port
2119 {
2120 pLoggedInPort->LOGO_timer = 6; // what's the Fabric timeout??
2121 // suspend any I/O in progress until
2122 // PDISC received...
2123 pLoggedInPort->prli = FALSE; // block FCP-SCSI commands
2124 }
2125
2126 pLoggedInPort = pLoggedInPort->pNextPort;
2127 }
2128
2129 if( fchs->pl[2] == 0x0280) // ACCept?
2130 {
2131 // Send PLOGI or PDISC to these Fabric devices
2132 SendLogins( cpqfcHBAdata, &fchs->pl[4] );
2133 }
2134
2135
2136 // As of this writing, the only reason to reject is because NO
2137 // devices are left on the Fabric. We already started
2138 // "logged out" timers; if the device(s) don't come
2139 // back, we'll do the implicit logout in the heart beat
2140 // timer routine
2141 else // ReJecT
2142 {
2143 // this just means no Fabric device is visible at this instant
2144 }
2145 }
2146
2147 // Regardless of whether the Reply is valid or not, the
2148 // the exchange is done - complete
2149 cpqfcTSCompleteExchange( fcChip, (fchs->ox_rx_id >>16)); // complete
2150
2151 Quit:
2152 return;
2153 }
2154
2155
2156
2157
2158
2159
2160
2161 static void AnalyzeIncomingFrame(
2162 CPQFCHBA *cpqfcHBAdata,
2163 ULONG QNdx )
2164 {
2165 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2166 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
2167 PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
2168 TachFCHDR_GCMND* fchs =
2169 (TachFCHDR_GCMND*)fcLQ->Qitem[QNdx].ulBuff;
2170 // ULONG ls_reject_code; // reason for rejecting login
2171 LONG ExchangeID;
2172 // FC_LOGGEDIN_PORT *pLoggedInPort;
2173 BOOLEAN AbortAccept;
2174
2175 ENTER("AnalyzeIncomingFrame");
2176
2177
2178
2179 switch( fcLQ->Qitem[QNdx].Type) // FCP or Unknown
2180 {
2181
2182 case SFQ_UNKNOWN: // unknown frame (e.g. LIP position frame, NOP, etc.)
2183
2184
2185 // ********* FC-4 Device Data/ Fibre Channel Service *************
2186 if( ((fchs->d_id &0xF0000000) == 0) // R_CTL (upper nibble) 0x0?
2187 &&
2188 (fchs->f_ctl & 0x20000000) ) // TYPE 20h is Fibre Channel Service
2189 {
2190
2191 // ************** FCS Reply **********************
2192
2193 if( (fchs->d_id & 0xff000000L) == 0x03000000L) // (31:23 R_CTL)
2194 {
2195 ProcessFCS_Reply( cpqfcHBAdata, fchs );
2196
2197 } // end of FCS logic
2198
2199 }
2200
2201
2202 // *********** Extended Link Service **************
2203
2204 else if( fchs->d_id & 0x20000000 // R_CTL 0x2?
2205 &&
2206 (fchs->f_ctl & 0x01000000) ) // TYPE = 1
2207 {
2208
2209 // these frames are either a response to
2210 // something we sent (0x23) or "unsolicited"
2211 // frames (0x22).
2212
2213
2214 // **************Extended Link REPLY **********************
2215 // R_CTL Solicited Control Reply
2216
2217 if( (fchs->d_id & 0xff000000L) == 0x23000000L) // (31:23 R_CTL)
2218 {
2219
2220 ProcessELS_Reply( cpqfcHBAdata, fchs );
2221
2222 } // end of "R_CTL Solicited Control Reply"
2223
2224
2225
2226
2227 // **************Extended Link REQUEST **********************
2228 // (unsolicited commands from another port or task...)
2229
2230 // R_CTL Ext Link REQUEST
2231 else if( (fchs->d_id & 0xff000000L) == 0x22000000L &&
2232 (fchs->ox_rx_id != 0xFFFFFFFFL) ) // (ignore LIP frame)
2233 {
2234
2235
2236
2237 ProcessELS_Request( cpqfcHBAdata, fchs );
2238
2239 }
2240
2241
2242
2243 // ************** LILP **********************
2244 else if( (fchs->d_id & 0xff000000L) == 0x22000000L &&
2245 (fchs->ox_rx_id == 0xFFFFFFFFL)) // (e.g., LIP frames)
2246
2247 {
2248 // SANMark specifies that when available, we must use
2249 // the LILP frame to determine which ALPAs to send Port Discovery
2250 // to...
2251
2252 if( fchs->pl[0] == 0x0711L) // ELS_PLOGI?
2253 {
2254 // UCHAR *ptr = (UCHAR*)&fchs->pl[1];
2255 // printk(" %d ALPAs found\n", *ptr);
2256 memcpy( fcChip->LILPmap, &fchs->pl[1], 32*4); // 32 DWORDs
2257 fcChip->Options.LILPin = 1; // our LILPmap is valid!
2258 // now post to make Port Discovery happen...
2259 cpqfcTSPutLinkQue( cpqfcHBAdata, LINKACTIVE, fchs);
2260 }
2261 }
2262 }
2263
2264
2265 // ***************** BASIC LINK SERVICE *****************
2266
2267 else if( fchs->d_id & 0x80000000 // R_CTL:
2268 && // Basic Link Service Request
2269 !(fchs->f_ctl & 0xFF000000) ) // type=0 for BLS
2270 {
2271
2272 // Check for ABTS (Abort Sequence)
2273 if( (fchs->d_id & 0x8F000000) == 0x81000000)
2274 {
2275 // look for OX_ID, S_ID pair that matches in our
2276 // fcExchanges table; if found, reply with ACCept and complete
2277 // the exchange
2278
2279 // Per PLDA, an ABTS is sent by an initiator; therefore
2280 // assume that if we have an exhange open to the port who
2281 // sent ABTS, it will be the d_id of what we sent.
2282 for( ExchangeID = 0, AbortAccept=FALSE;
2283 ExchangeID < TACH_SEST_LEN; ExchangeID++)
2284 {
2285 // Valid "target" exchange 24-bit port_id matches?
2286 // NOTE: For the case of handling Intiator AND Target
2287 // functions on the same chip, we can have TWO Exchanges
2288 // with the same OX_ID -- OX_ID/FFFF for the CMND, and
2289 // OX_ID/RX_ID for the XRDY or DATA frame(s). Ideally,
2290 // we would like to support ABTS from Initiators or Targets,
2291 // but it's not clear that can be supported on Tachyon for
2292 // all cases (requires more investigation).
2293
2294 if( (Exchanges->fcExchange[ ExchangeID].type == SCSI_TWE ||
2295 Exchanges->fcExchange[ ExchangeID].type == SCSI_TRE)
2296 &&
2297 ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
2298 (fchs->s_id & 0xFFFFFF)) )
2299 {
2300
2301 // target xchnge port_id matches -- how about OX_ID?
2302 if( (Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id &0xFFFF0000)
2303 == (fchs->ox_rx_id & 0xFFFF0000) )
2304 // yes! post ACCept response; will be completed by fcStart
2305 {
2306 Exchanges->fcExchange[ ExchangeID].status = TARGET_ABORT;
2307
2308 // copy (add) rx_id field for simplified ACCept reply
2309 fchs->ox_rx_id =
2310 Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id;
2311
2312 cpqfcTSPutLinkQue( cpqfcHBAdata,
2313 BLS_ABTS_ACC, // Q Type
2314 fchs ); // void QueContent
2315 AbortAccept = TRUE;
2316 printk("ACCepting ABTS for x_ID %8.8Xh, SEST pair %8.8Xh\n",
2317 fchs->ox_rx_id, Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id);
2318 break; // ABTS can affect only ONE exchange -exit loop
2319 }
2320 }
2321 } // end of FOR loop
2322 if( !AbortAccept ) // can't ACCept ABTS - send Reject
2323 {
2324 printk("ReJecTing: can't find ExchangeID %8.8Xh for ABTS command\n",
2325 fchs->ox_rx_id);
2326 if( Exchanges->fcExchange[ ExchangeID].type
2327 &&
2328 !(fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len
2329 & 0x80000000))
2330 {
2331 cpqfcTSCompleteExchange( fcChip, ExchangeID);
2332 }
2333 else
2334 {
2335 printk("Unexpected ABTS ReJecT! SEST[%X] Dword 0: %Xh\n",
2336 ExchangeID, fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len);
2337 }
2338 }
2339 }
2340
2341 // Check for BLS {ABTS? (Abort Sequence)} ACCept
2342 else if( (fchs->d_id & 0x8F000000) == 0x84000000)
2343 {
2344 // target has responded with ACC for our ABTS;
2345 // complete the indicated exchange with ABORTED status
2346 // Make no checks for correct RX_ID, since
2347 // all we need to conform ABTS ACC is the OX_ID.
2348 // Verify that the d_id matches!
2349
2350 ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC
2351 // printk("ABTS ACC x_ID 0x%04X 0x%04X, status %Xh\n",
2352 // fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff,
2353 // Exchanges->fcExchange[ExchangeID].status);
2354
2355
2356
2357 if( ExchangeID < TACH_SEST_LEN ) // x_ID makes sense
2358 {
2359 // Does "target" exchange 24-bit port_id match?
2360 // (See "NOTE" above for handling Intiator AND Target in
2361 // the same device driver)
2362 // First, if this is a target response, then we originated
2363 // (initiated) it with BLS_ABTS:
2364
2365 if( (Exchanges->fcExchange[ ExchangeID].type == BLS_ABTS)
2366
2367 &&
2368 // Second, does the source of this ACC match the destination
2369 // of who we originally sent it to?
2370 ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
2371 (fchs->s_id & 0xFFFFFF)) )
2372 {
2373 cpqfcTSCompleteExchange( fcChip, ExchangeID );
2374 }
2375 }
2376 }
2377 // Check for BLS {ABTS? (Abort Sequence)} ReJecT
2378 else if( (fchs->d_id & 0x8F000000) == 0x85000000)
2379 {
2380 // target has responded with RJT for our ABTS;
2381 // complete the indicated exchange with ABORTED status
2382 // Make no checks for correct RX_ID, since
2383 // all we need to conform ABTS ACC is the OX_ID.
2384 // Verify that the d_id matches!
2385
2386 ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC
2387 // printk("BLS_ABTS RJT on Exchange 0x%04X 0x%04X\n",
2388 // fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff);
2389
2390 if( ExchangeID < TACH_SEST_LEN ) // x_ID makes sense
2391 {
2392 // Does "target" exchange 24-bit port_id match?
2393 // (See "NOTE" above for handling Intiator AND Target in
2394 // the same device driver)
2395 // First, if this is a target response, then we originated
2396 // (initiated) it with BLS_ABTS:
2397
2398 if( (Exchanges->fcExchange[ ExchangeID].type == BLS_ABTS)
2399
2400 &&
2401 // Second, does the source of this ACC match the destination
2402 // of who we originally sent it to?
2403 ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
2404 (fchs->s_id & 0xFFFFFF)) )
2405 {
2406 // YES! NOTE: There is a bug in CPQ's RA-4000 box
2407 // where the "reason code" isn't returned in the payload
2408 // For now, simply presume the reject is because the target
2409 // already completed the exchange...
2410
2411 // printk("complete x_ID %Xh on ABTS RJT\n", ExchangeID);
2412 cpqfcTSCompleteExchange( fcChip, ExchangeID );
2413 }
2414 }
2415 } // end of ABTS check
2416 } // end of Basic Link Service Request
2417 break;
2418
2419 default:
2420 printk("AnalyzeIncomingFrame: unknown type: %Xh(%d)\n",
2421 fcLQ->Qitem[QNdx].Type,
2422 fcLQ->Qitem[QNdx].Type);
2423 break;
2424 }
2425 }
2426
2427
2428 // Function for Port Discovery necessary after every FC
2429 // initialization (e.g. LIP).
2430 // Also may be called if from Fabric Name Service logic.
2431
2432 static void SendLogins( CPQFCHBA *cpqfcHBAdata, __u32 *FabricPortIds )
2433 {
2434 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2435 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
2436 ULONG ulStatus=0;
2437 TachFCHDR_GCMND fchs; // copy fields for transmission
2438 int i;
2439 ULONG loginType;
2440 LONG ExchangeID;
2441 PFC_LOGGEDIN_PORT pLoggedInPort;
2442 __u32 PortIds[ number_of_al_pa];
2443 int NumberOfPorts=0;
2444
2445 // We're going to presume (for now) that our limit of Fabric devices
2446 // is the same as the number of alpa on a private loop (126 devices).
2447 // (Of course this could be changed to support however many we have
2448 // memory for).
2449 memset( &PortIds[0], 0, sizeof(PortIds));
2450
2451 // First, check if this login is for our own Link Initialization
2452 // (e.g. LIP on FC-AL), or if we have knowledge of Fabric devices
2453 // from a switch. If we are logging into Fabric devices, we'll
2454 // have a non-NULL FabricPortId pointer
2455
2456 if( FabricPortIds != NULL) // may need logins
2457 {
2458 int LastPort=FALSE;
2459 i = 0;
2460 while( !LastPort)
2461 {
2462 // port IDs From NSR payload; byte swap needed?
2463 BigEndianSwap( (UCHAR*)FabricPortIds, (UCHAR*)&PortIds[i], 4);
2464
2465 // printk("FPortId[%d] %Xh ", i, PortIds[i]);
2466 if( PortIds[i] & 0x80000000)
2467 LastPort = TRUE;
2468
2469 PortIds[i] &= 0xFFFFFF; // get 24-bit port_id
2470 // some non-Fabric devices (like the Crossroads Fibre/Scsi bridge)
2471 // erroneously use ALPA 0.
2472 if( PortIds[i] ) // need non-zero port_id...
2473 i++;
2474
2475 if( i >= number_of_al_pa ) // (in)sanity check
2476 break;
2477 FabricPortIds++; // next...
2478 }
2479
2480 NumberOfPorts = i;
2481 // printk("NumberOf Fabric ports %d", NumberOfPorts);
2482 }
2483
2484 else // need to send logins on our "local" link
2485 {
2486
2487 // are we a loop port? If so, check for reception of LILP frame,
2488 // and if received use it (SANMark requirement)
2489 if( fcChip->Options.LILPin )
2490 {
2491 int j=0;
2492 // sanity check on number of ALPAs from LILP frame...
2493 // For format of LILP frame, see FC-AL specs or
2494 // "Fibre Channel Bench Reference", J. Stai, 1995 (ISBN 1-879936-17-8)
2495 // First byte is number of ALPAs
2496 i = fcChip->LILPmap[0] >= (32*4) ? 32*4 : fcChip->LILPmap[0];
2497 NumberOfPorts = i;
2498 // printk(" LILP alpa count %d ", i);
2499 while( i > 0)
2500 {
2501 PortIds[j] = fcChip->LILPmap[1+ j];
2502 j++; i--;
2503 }
2504 }
2505 else // have to send login to everybody
2506 {
2507 int j=0;
2508 i = number_of_al_pa;
2509 NumberOfPorts = i;
2510 while( i > 0)
2511 {
2512 PortIds[j] = valid_al_pa[j]; // all legal ALPAs
2513 j++; i--;
2514 }
2515 }
2516 }
2517
2518
2519 // Now we have a copy of the port_ids (and how many)...
2520 for( i = 0; i < NumberOfPorts; i++)
2521 {
2522 // 24-bit FC Port ID
2523 fchs.s_id = PortIds[i]; // note: only 8-bits used for ALPA
2524
2525
2526 // don't log into ourselves (Linux Scsi disk scan will stop on
2527 // no TARGET support error on us, and quit trying for rest of devices)
2528 if( (fchs.s_id & 0xFF ) == (fcChip->Registers.my_al_pa & 0xFF) )
2529 continue;
2530
2531 // fabric login needed?
2532 if( (fchs.s_id == 0) ||
2533 (fcChip->Options.fabric == 1) )
2534 {
2535 fcChip->Options.flogi = 1; // fabric needs longer for login
2536 // Do we need FLOGI or FDISC?
2537 pLoggedInPort = fcFindLoggedInPort(
2538 fcChip,
2539 NULL, // don't search SCSI Nexus
2540 0xFFFFFC, // search linked list for Fabric port_id
2541 NULL, // don't search WWN
2542 NULL); // (don't care about end of list)
2543
2544 if( pLoggedInPort ) // If found, we have prior experience with
2545 // this port -- check whether PDISC is needed
2546 {
2547 if( pLoggedInPort->flogi )
2548 {
2549 // does the switch support FDISC?? (FLOGI for now...)
2550 loginType = ELS_FLOGI; // prior FLOGI still valid
2551 }
2552 else
2553 loginType = ELS_FLOGI; // expired FLOGI
2554 }
2555 else // first FLOGI?
2556 loginType = ELS_FLOGI;
2557
2558
2559 fchs.s_id = 0xFFFFFE; // well known F_Port address
2560
2561 // Fabrics are not required to support FDISC, and
2562 // it's not clear if that helps us anyway, since
2563 // we'll want a Name Service Request to re-verify
2564 // visible devices...
2565 // Consequently, we always want our upper 16 bit
2566 // port_id to be zero (we'll be rejected if we
2567 // use our prior port_id if we've been plugged into
2568 // a different switch port).
2569 // Trick Tachyon to send to ALPA 0 (see TL/TS UG, pg 87)
2570 // If our ALPA is 55h for instance, we want the FC frame
2571 // s_id to be 0x000055, while Tach's my_al_pa register
2572 // must be 0x000155, to force an OPN at ALPA 0
2573 // (the Fabric port)
2574 fcChip->Registers.my_al_pa &= 0xFF; // only use ALPA for FLOGI
2575 writel( fcChip->Registers.my_al_pa | 0x0100,
2576 fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
2577 }
2578
2579 else // not FLOGI...
2580 {
2581 // should we send PLOGI or PDISC? Check if any prior port_id
2582 // (e.g. alpa) completed a PLOGI/PRLI exchange by checking
2583 // the pdisc flag.
2584
2585 pLoggedInPort = fcFindLoggedInPort(
2586 fcChip,
2587 NULL, // don't search SCSI Nexus
2588 fchs.s_id, // search linked list for al_pa
2589 NULL, // don't search WWN
2590 NULL); // (don't care about end of list)
2591
2592
2593
2594 if( pLoggedInPort ) // If found, we have prior experience with
2595 // this port -- check whether PDISC is needed
2596 {
2597 if( pLoggedInPort->pdisc )
2598 {
2599 loginType = ELS_PDISC; // prior PLOGI and PRLI maybe still valid
2600
2601 }
2602 else
2603 loginType = ELS_PLOGI; // prior knowledge, but can't use PDISC
2604 }
2605 else // never talked to this port_id before
2606 loginType = ELS_PLOGI; // prior knowledge, but can't use PDISC
2607 }
2608
2609
2610
2611 ulStatus = cpqfcTSBuildExchange(
2612 cpqfcHBAdata,
2613 loginType, // e.g. PLOGI
2614 &fchs, // no incoming frame (we are originator)
2615 NULL, // no data (no scatter/gather list)
2616 &ExchangeID );// fcController->fcExchanges index, -1 if failed
2617
2618 if( !ulStatus ) // Exchange setup OK?
2619 {
2620 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
2621 if( !ulStatus )
2622 {
2623 // submitted to Tach's Outbound Que (ERQ PI incremented)
2624 // waited for completion for ELS type (Login frames issued
2625 // synchronously)
2626
2627 if( loginType == ELS_PDISC )
2628 {
2629 // now, we really shouldn't Revalidate SEST exchanges until
2630 // we get an ACC reply from our target and verify that
2631 // the target address/WWN is unchanged. However, when a fast
2632 // target gets the PDISC, they can send SEST Exchange data
2633 // before we even get around to processing the PDISC ACC.
2634 // Consequently, we lose the I/O.
2635 // To avoid this, go ahead and Revalidate when the PDISC goes
2636 // out, anticipating that the ACC will be truly acceptable
2637 // (this happens 99.9999....% of the time).
2638 // If we revalidate a SEST write, and write data goes to a
2639 // target that is NOT the one we originated the WRITE to,
2640 // that target is required (FCP-SCSI specs, etc) to discard
2641 // our WRITE data.
2642
2643 // Re-validate SEST entries (Tachyon hardware assists)
2644 RevalidateSEST( cpqfcHBAdata->HostAdapter, pLoggedInPort);
2645 //TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
2646 }
2647 }
2648 else // give up immediately on error
2649 {
2650 #ifdef LOGIN_DBG
2651 printk("SendLogins: fcStartExchange failed: %Xh\n", ulStatus );
2652 #endif
2653 break;
2654 }
2655
2656
2657 if( fcChip->Registers.FMstatus.value & 0x080 ) // LDn during Port Disc.
2658 {
2659 ulStatus = LNKDWN_OSLS;
2660 #ifdef LOGIN_DBG
2661 printk("SendLogins: PortDisc aborted (LDn) @alpa %Xh\n", fchs.s_id);
2662 #endif
2663 break;
2664 }
2665 // Check the exchange for bad status (i.e. FrameTimeOut),
2666 // and complete on bad status (most likely due to BAD_ALPA)
2667 // on LDn, DPC function may already complete (ABORT) a started
2668 // exchange, so check type first (type = 0 on complete).
2669 if( Exchanges->fcExchange[ExchangeID].status )
2670 {
2671 #ifdef LOGIN_DBG
2672 printk("completing x_ID %X on status %Xh\n",
2673 ExchangeID, Exchanges->fcExchange[ExchangeID].status);
2674 #endif
2675 cpqfcTSCompleteExchange( fcChip, ExchangeID);
2676 }
2677 }
2678 else // Xchange setup failed...
2679 {
2680 #ifdef LOGIN_DBG
2681 printk("FC: cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
2682 #endif
2683 break;
2684 }
2685 }
2686 if( !ulStatus )
2687 {
2688 // set the event signifying that all ALPAs were sent out.
2689 #ifdef LOGIN_DBG
2690 printk("SendLogins: PortDiscDone\n");
2691 #endif
2692 cpqfcHBAdata->PortDiscDone = 1;
2693
2694
2695 // TL/TS UG, pg. 184
2696 // 0x0065 = 100ms for RT_TOV
2697 // 0x01f5 = 500ms for ED_TOV
2698 fcChip->Registers.ed_tov.value = 0x006501f5L;
2699 writel( fcChip->Registers.ed_tov.value,
2700 (fcChip->Registers.ed_tov.address));
2701
2702 // set the LP_TOV back to ED_TOV (i.e. 500 ms)
2703 writel( 0x00000010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);
2704 }
2705 else
2706 {
2707 printk("SendLogins: failed at xchng %Xh, alpa %Xh, status %Xh\n",
2708 ExchangeID, fchs.s_id, ulStatus);
2709 }
2710 LEAVE("SendLogins");
2711
2712 }
2713
2714
2715 // for REPORT_LUNS documentation, see "In-Depth Exploration of Scsi",
2716 // D. Deming, 1994, pg 7-19 (ISBN 1-879936-08-9)
2717 static void ScsiReportLunsDone(Scsi_Cmnd *Cmnd)
2718 {
2719 struct Scsi_Host *HostAdapter = Cmnd->host;
2720 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
2721 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2722 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
2723 PFC_LOGGEDIN_PORT pLoggedInPort;
2724 int LunListLen=0;
2725 int i;
2726 ULONG x_ID = 0xFFFFFFFF;
2727 UCHAR *ucBuff = Cmnd->request_buffer;
2728
2729 // printk("cpqfcTS: ReportLunsDone \n");
2730 // first, we need to find the Exchange for this command,
2731 // so we can find the fcPort struct to make the indicated
2732 // changes.
2733 for( i=0; i< TACH_SEST_LEN; i++)
2734 {
2735 if( Exchanges->fcExchange[i].type // exchange defined?
2736 &&
2737 (Exchanges->fcExchange[i].Cmnd == Cmnd) ) // matches?
2738
2739 {
2740 x_ID = i; // found exchange!
2741 break;
2742 }
2743 }
2744 if( x_ID == 0xFFFFFFFF)
2745 {
2746 // printk("cpqfcTS: ReportLuns failed - no FC Exchange\n");
2747 goto Done; // Report Luns FC Exchange gone;
2748 // exchange probably Terminated by Implicit logout
2749 }
2750
2751
2752 // search linked list for the port_id we sent INQUIRY to
2753 pLoggedInPort = fcFindLoggedInPort( fcChip,
2754 NULL, // DON'T search Scsi Nexus (we will set it)
2755 Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF,
2756 NULL, // DON'T search linked list for FC WWN
2757 NULL); // DON'T care about end of list
2758
2759 if( !pLoggedInPort )
2760 {
2761 // printk("cpqfcTS: ReportLuns failed - device gone\n");
2762 goto Done; // error! can't find logged in Port
2763 }
2764 LunListLen = ucBuff[3];
2765 LunListLen += ucBuff[2]>>8;
2766
2767 if( !LunListLen ) // failed
2768 {
2769 // generically speaking, a soft error means we should retry...
2770 if( (Cmnd->result >> 16) == DID_SOFT_ERROR )
2771 {
2772 if( ((Cmnd->sense_buffer[2] & 0xF) == 0x6) &&
2773 (Cmnd->sense_buffer[12] == 0x29) ) // Sense Code "reset"
2774 {
2775 TachFCHDR_GCMND *fchs = &Exchanges->fcExchange[ x_ID].fchs;
2776 // did we fail because of "check condition, device reset?"
2777 // e.g. the device was reset (i.e., at every power up)
2778 // retry the Report Luns
2779
2780 // who are we sending it to?
2781 // we know this because we have a copy of the command
2782 // frame from the original Report Lun command -
2783 // switch the d_id/s_id fields, because the Exchange Build
2784 // context is "reply to source".
2785
2786 fchs->s_id = fchs->d_id; // (temporarily re-use the struct)
2787 cpqfcTSPutLinkQue( cpqfcHBAdata, SCSI_REPORT_LUNS, fchs );
2788 }
2789 }
2790 else // probably, the device doesn't support Report Luns
2791 pLoggedInPort->ScsiNexus.VolumeSetAddressing = 0;
2792 }
2793 else // we have LUN info - check VSA mode
2794 {
2795 // for now, assume all LUNs will have same addr mode
2796 // for VSA, payload byte 8 will be 0x40; otherwise, 0
2797 pLoggedInPort->ScsiNexus.VolumeSetAddressing = ucBuff[8];
2798
2799 // Since we got a Report Luns answer, set lun masking flag
2800 pLoggedInPort->ScsiNexus.LunMasking = 1;
2801
2802 if( LunListLen > 8*CPQFCTS_MAX_LUN) // We expect CPQFCTS_MAX_LUN max
2803 LunListLen = 8*CPQFCTS_MAX_LUN;
2804
2805 /*
2806 printk("Device WWN %08X%08X Reports Luns @: ",
2807 (ULONG)(pLoggedInPort->u.liWWN &0xFFFFFFFF),
2808 (ULONG)(pLoggedInPort->u.liWWN>>32));
2809
2810 for( i=8; i<LunListLen+8; i+=8)
2811 {
2812 printk("%02X%02X ", ucBuff[i], ucBuff[i+1] );
2813 }
2814 printk("\n");
2815 */
2816
2817 // Since the device was kind enough to tell us where the
2818 // LUNs are, lets ensure they are contiguous for Linux's
2819 // SCSI driver scan, which expects them to start at 0.
2820 // Since Linux only supports 8 LUNs, only copy the first
2821 // eight from the report luns command
2822
2823 // e.g., the Compaq RA4x00 f/w Rev 2.54 and above may report
2824 // LUNs 4001, 4004, etc., because other LUNs are masked from
2825 // this HBA (owned by someone else). We'll make those appear as
2826 // LUN 0, 1... to Linux
2827 {
2828 int j;
2829 int AppendLunList = 0;
2830 // Walk through the LUN list. The 'j' array number is
2831 // Linux's lun #, while the value of .lun[j] is the target's
2832 // lun #.
2833 // Once we build a LUN list, it's possible for a known device
2834 // to go offline while volumes (LUNs) are added. Later,
2835 // the device will do another PLOGI ... Report Luns command,
2836 // and we must not alter the existing Linux Lun map.
2837 // (This will be very rare).
2838 for( j=0; j < CPQFCTS_MAX_LUN; j++)
2839 {
2840 if( pLoggedInPort->ScsiNexus.lun[j] != 0xFF )
2841 {
2842 AppendLunList = 1;
2843 break;
2844 }
2845 }
2846 if( AppendLunList )
2847 {
2848 int k;
2849 int FreeLunIndex;
2850 // printk("cpqfcTS: AppendLunList\n");
2851
2852 // If we get a new Report Luns, we cannot change
2853 // any existing LUN mapping! (Only additive entry)
2854 // For all LUNs in ReportLun list
2855 // if RL lun != ScsiNexus lun
2856 // if RL lun present in ScsiNexus lun[], continue
2857 // else find ScsiNexus lun[]==FF and add, continue
2858
2859 for( i=8, j=0; i<LunListLen+8 && j< CPQFCTS_MAX_LUN; i+=8, j++)
2860 {
2861 if( pLoggedInPort->ScsiNexus.lun[j] != ucBuff[i+1] )
2862 {
2863 // something changed from the last Report Luns
2864 printk(" cpqfcTS: Report Lun change!\n");
2865 for( k=0, FreeLunIndex=CPQFCTS_MAX_LUN;
2866 k < CPQFCTS_MAX_LUN; k++)
2867 {
2868 if( pLoggedInPort->ScsiNexus.lun[k] == 0xFF)
2869 {
2870 FreeLunIndex = k;
2871 break;
2872 }
2873 if( pLoggedInPort->ScsiNexus.lun[k] == ucBuff[i+1] )
2874 break; // we already masked this lun
2875 }
2876 if( k >= CPQFCTS_MAX_LUN )
2877 {
2878 printk(" no room for new LUN %d\n", ucBuff[i+1]);
2879 }
2880 else if( k == FreeLunIndex ) // need to add LUN
2881 {
2882 pLoggedInPort->ScsiNexus.lun[k] = ucBuff[i+1];
2883 // printk("add [%d]->%02d\n", k, pLoggedInPort->ScsiNexus.lun[k]);
2884
2885 }
2886 else
2887 {
2888 // lun already known
2889 }
2890 break;
2891 }
2892 }
2893 // print out the new list...
2894 for( j=0; j< CPQFCTS_MAX_LUN; j++)
2895 {
2896 if( pLoggedInPort->ScsiNexus.lun[j] == 0xFF)
2897 break; // done
2898 // printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
2899 }
2900 }
2901 else
2902 {
2903 // printk("Linux SCSI LUNs[] -> Device LUNs: ");
2904 // first time - this is easy
2905 for( i=8, j=0; i<LunListLen+8 && j< CPQFCTS_MAX_LUN; i+=8, j++)
2906 {
2907 pLoggedInPort->ScsiNexus.lun[j] = ucBuff[i+1];
2908 // printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
2909 }
2910 // printk("\n");
2911 }
2912 }
2913 }
2914
2915 Done:
2916 }
2917
2918 // After successfully getting a "Process Login" (PRLI) from an
2919 // FC port, we want to Discover the LUNs so that we know the
2920 // addressing type (e.g., FCP-SCSI Volume Set Address, Peripheral
2921 // Unit Device), and whether SSP (Selective Storage Presentation or
2922 // Lun Masking) has made the LUN numbers non-zero based or
2923 // non-contiguous. To remain backward compatible with the SCSI-2
2924 // driver model, which expects a contiguous LUNs starting at 0,
2925 // will use the ReportLuns info to map from "device" to "Linux"
2926 // LUNs.
2927 static void IssueReportLunsCommand(
2928 CPQFCHBA* cpqfcHBAdata,
2929 TachFCHDR_GCMND* fchs)
2930 {
2931 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
2932 PFC_LOGGEDIN_PORT pLoggedInPort;
2933 Scsi_Cmnd *Cmnd;
2934 LONG x_ID;
2935 ULONG ulStatus;
2936 UCHAR *ucBuff;
2937
2938 if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn
2939 {
2940 printk("Discard Q'd ReportLun command\n");
2941 goto Done;
2942 }
2943
2944 // find the device (from port_id) we're talking to
2945 pLoggedInPort = fcFindLoggedInPort( fcChip,
2946 NULL, // DON'T search Scsi Nexus
2947 fchs->s_id & 0xFFFFFF,
2948 NULL, // DON'T search linked list for FC WWN
2949 NULL); // DON'T care about end of list
2950 if( pLoggedInPort ) // we'd BETTER find it!
2951 {
2952
2953
2954 if( !(pLoggedInPort->fcp_info & TARGET_FUNCTION) )
2955 goto Done; // forget it - FC device not a "target"
2956
2957 // now use the port's Scsi Command buffer for the
2958 // Report Luns Command
2959
2960 Cmnd = &pLoggedInPort->ScsiCmnd;
2961 ucBuff = pLoggedInPort->ReportLunsPayload;
2962
2963 memset( Cmnd, 0, sizeof(Scsi_Cmnd));
2964 memset( ucBuff, 0, REPORT_LUNS_PL);
2965
2966 Cmnd->scsi_done = ScsiReportLunsDone;
2967 Cmnd->host = cpqfcHBAdata->HostAdapter;
2968
2969 Cmnd->request_buffer = pLoggedInPort->ReportLunsPayload;
2970 Cmnd->request_bufflen = REPORT_LUNS_PL;
2971
2972 Cmnd->cmnd[0] = 0xA0;
2973 Cmnd->cmnd[8] = REPORT_LUNS_PL >> 8;
2974 Cmnd->cmnd[9] = (UCHAR)REPORT_LUNS_PL;
2975 Cmnd->cmd_len = 12;
2976
2977 Cmnd->channel = pLoggedInPort->ScsiNexus.channel;
2978 Cmnd->target = pLoggedInPort->ScsiNexus.target;
2979
2980
2981 ulStatus = cpqfcTSBuildExchange(
2982 cpqfcHBAdata,
2983 SCSI_IRE,
2984 fchs,
2985 Cmnd, // buffer for Report Lun data
2986 &x_ID );// fcController->fcExchanges index, -1 if failed
2987
2988 if( !ulStatus ) // Exchange setup?
2989 {
2990 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, x_ID );
2991 if( !ulStatus )
2992 {
2993 // submitted to Tach's Outbound Que (ERQ PI incremented)
2994 // waited for completion for ELS type (Login frames issued
2995 // synchronously)
2996 }
2997 else
2998 // check reason for Exchange not being started - we might
2999 // want to Queue and start later, or fail with error
3000 {
3001
3002 }
3003 }
3004
3005 else // Xchange setup failed...
3006 printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
3007 }
3008 else // like, we just got a PRLI ACC, and now the port is gone?
3009 {
3010 printk(" can't send ReportLuns - no login for port_id %Xh\n",
3011 fchs->s_id & 0xFFFFFF);
3012 }
3013
3014
3015
3016 Done:
3017
3018 }
3019
3020
3021
3022
3023
3024
3025
3026 static void CompleteBoardLockCmnd( CPQFCHBA *cpqfcHBAdata)
3027 {
3028 int i;
3029 for( i = CPQFCTS_REQ_QUEUE_LEN-1; i>= 0; i--)
3030 {
3031 if( cpqfcHBAdata->BoardLockCmnd[i] != NULL )
3032 {
3033 Scsi_Cmnd *Cmnd = cpqfcHBAdata->BoardLockCmnd[i];
3034 cpqfcHBAdata->BoardLockCmnd[i] = NULL;
3035 Cmnd->result = (DID_SOFT_ERROR << 16); // ask for retry
3036 // printk(" BoardLockCmnd[%d] %p Complete, chnl/target/lun %d/%d/%d\n",
3037 // i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
3038 if( Cmnd->scsi_done != NULL)
3039 (*Cmnd->scsi_done)(Cmnd);
3040 }
3041 }
3042 }
3043
3044
3045
3046
3047
3048
3049 // runs every 1 second for FC exchange timeouts and implicit FC device logouts
3050
3051 void cpqfcTSheartbeat( unsigned long ptr )
3052 {
3053 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)ptr;
3054 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
3055 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
3056 PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
3057 ULONG i;
3058 unsigned long flags;
3059 DECLARE_MUTEX_LOCKED(BoardLock);
3060
3061 PCI_TRACE( 0xA8)
3062
3063 if( cpqfcHBAdata->BoardLock) // Worker Task Running?
3064 goto Skip;
3065
3066 spin_lock_irqsave( &io_request_lock, flags); // STOP _que function
3067
3068 PCI_TRACE( 0xA8)
3069
3070
3071 cpqfcHBAdata->BoardLock = &BoardLock; // stop Linux SCSI command queuing
3072
3073 // release the IO lock (and re-enable interrupts)
3074 spin_unlock_irqrestore( &io_request_lock, flags);
3075
3076 // Ensure no contention from _quecommand or Worker process
3077 CPQ_SPINLOCK_HBA( cpqfcHBAdata)
3078
3079 PCI_TRACE( 0xA8)
3080
3081
3082 disable_irq( cpqfcHBAdata->HostAdapter->irq); // our IRQ
3083
3084 // Complete the "bad target" commands (normally only used during
3085 // initialization, since we aren't supposed to call "scsi_done"
3086 // inside the queuecommand() function).
3087
3088 for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++)
3089 {
3090 if( cpqfcHBAdata->BadTargetCmnd[i] )
3091 {
3092 Scsi_Cmnd *Cmnd = cpqfcHBAdata->BadTargetCmnd[i];
3093 cpqfcHBAdata->BadTargetCmnd[i] = NULL;
3094 Cmnd->result = (DID_BAD_TARGET << 16);
3095 if( Cmnd->scsi_done != NULL)
3096 (*Cmnd->scsi_done)(Cmnd);
3097 }
3098 else
3099 break;
3100 }
3101
3102
3103 // logged in ports -- re-login check (ports required to verify login with
3104 // PDISC after LIP within 2 secs)
3105
3106 // prevent contention
3107 while( pLoggedInPort ) // for all ports which are expecting
3108 // PDISC after the next LIP, check to see if
3109 // time is up!
3110 {
3111 // Important: we only detect "timeout" condition on TRANSITION
3112 // from non-zero to zero
3113 if( pLoggedInPort->LOGO_timer ) // time-out "armed"?
3114 {
3115 if( !(--pLoggedInPort->LOGO_timer) ) // DEC from 1 to 0?
3116 {
3117 // LOGOUT time! Per PLDA, PDISC hasn't complete in 2 secs, so
3118 // issue LOGO request and destroy all I/O with other FC port(s).
3119
3120 /*
3121 printk(" ~cpqfcTS heartbeat: LOGOut!~ ");
3122 printk("Linux SCSI Chanl/Target %d/%d (port_id %06Xh) WWN %08X%08X\n",
3123 pLoggedInPort->ScsiNexus.channel,
3124 pLoggedInPort->ScsiNexus.target,
3125 pLoggedInPort->port_id,
3126 (ULONG)(pLoggedInPort->u.liWWN &0xFFFFFFFF),
3127 (ULONG)(pLoggedInPort->u.liWWN>>32));
3128
3129 */
3130 cpqfcTSImplicitLogout( cpqfcHBAdata, pLoggedInPort);
3131
3132 }
3133 // else simply decremented - maybe next time...
3134 }
3135 pLoggedInPort = pLoggedInPort->pNextPort;
3136 }
3137
3138
3139
3140
3141
3142 // ************ FC EXCHANGE TIMEOUT CHECK **************
3143
3144 for( i=0; i< TACH_MAX_XID; i++)
3145 {
3146 if( Exchanges->fcExchange[i].type ) // exchange defined?
3147 {
3148
3149 if( !Exchanges->fcExchange[i].timeOut ) // time expired
3150 {
3151 // Set Exchange timeout status
3152 Exchanges->fcExchange[i].status |= FC2_TIMEOUT;
3153
3154 if( i >= TACH_SEST_LEN ) // Link Service Exchange
3155 {
3156 cpqfcTSCompleteExchange( fcChip, i); // Don't "abort" LinkService
3157 }
3158
3159 else // SEST Exchange TO -- may post ABTS to Worker Thread Que
3160 {
3161 // (Make sure we don't keep timing it out; let other functions
3162 // complete it or set the timeOut as needed)
3163 Exchanges->fcExchange[i].timeOut = 30000; // seconds default
3164
3165 if( Exchanges->fcExchange[i].type
3166 &
3167 (BLS_ABTS | BLS_ABTS_ACC ) )
3168 {
3169 // For BLS_ABTS*, an upper level might still have
3170 // an outstanding command waiting for low-level completion.
3171 // Also, in the case of a WRITE, we MUST get confirmation
3172 // of either ABTS ACC or RJT before re-using the Exchange.
3173 // It's possible that the RAID cache algorithm can hang
3174 // if we fail to complete a WRITE to a LBA, when a READ
3175 // comes later to that same LBA. Therefore, we must
3176 // ensure that the target verifies receipt of ABTS for
3177 // the exchange
3178
3179 printk("~TO Q'd ABTS (x_ID %Xh)~ ", i);
3180 // TriggerHBA( fcChip->Registers.ReMapMemBase);
3181
3182 // On timeout of a ABTS exchange, check to
3183 // see if the FC device has a current valid login.
3184 // If so, restart it.
3185 pLoggedInPort = fcFindLoggedInPort( fcChip,
3186 Exchanges->fcExchange[i].Cmnd, // find Scsi Nexus
3187 0, // DON'T search linked list for FC port id
3188 NULL, // DON'T search linked list for FC WWN
3189 NULL); // DON'T care about end of list
3190
3191 // device exists?
3192 if( pLoggedInPort ) // device exists?
3193 {
3194 if( pLoggedInPort->prli ) // logged in for FCP-SCSI?
3195 {
3196 // attempt to restart the ABTS
3197 printk(" ~restarting ABTS~ ");
3198 cpqfcTSStartExchange( cpqfcHBAdata, i );
3199
3200 }
3201 }
3202 }
3203 else // not an ABTS
3204 {
3205
3206 // We expect the WorkerThread to change the xchng type to
3207 // abort and set appropriate timeout.
3208 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &i ); // timed-out
3209 }
3210 }
3211 }
3212 else // time not expired...
3213 {
3214 // decrement timeout: 1 or more seconds left
3215 --Exchanges->fcExchange[i].timeOut;
3216 }
3217 }
3218 }
3219
3220
3221 enable_irq( cpqfcHBAdata->HostAdapter->irq);
3222
3223
3224 CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
3225
3226 cpqfcHBAdata->BoardLock = NULL; // Linux SCSI commands may be queued
3227
3228 // Now, complete any Cmnd we Q'd up while BoardLock was held
3229
3230 CompleteBoardLockCmnd( cpqfcHBAdata);
3231
3232
3233 // restart the timer to run again (1 sec later)
3234 Skip:
3235 mod_timer( &cpqfcHBAdata->cpqfcTStimer, jiffies + HZ);
3236
3237 PCI_TRACEO( i, 0xA8)
3238 return;
3239 }
3240
3241
3242 // put valid FC-AL physical address in spec order
3243 static const UCHAR valid_al_pa[]={
3244 0xef, 0xe8, 0xe4, 0xe2,
3245 0xe1, 0xE0, 0xDC, 0xDA,
3246 0xD9, 0xD6, 0xD5, 0xD4,
3247 0xD3, 0xD2, 0xD1, 0xCe,
3248 0xCd, 0xCc, 0xCb, 0xCa,
3249 0xC9, 0xC7, 0xC6, 0xC5,
3250 0xC3, 0xBc, 0xBa, 0xB9,
3251 0xB6, 0xB5, 0xB4, 0xB3,
3252 0xB2, 0xB1, 0xae, 0xad,
3253 0xAc, 0xAb, 0xAa, 0xA9,
3254
3255 0xA7, 0xA6, 0xA5, 0xA3,
3256 0x9f, 0x9e, 0x9d, 0x9b,
3257 0x98, 0x97, 0x90, 0x8f,
3258 0x88, 0x84, 0x82, 0x81,
3259 0x80, 0x7c, 0x7a, 0x79,
3260 0x76, 0x75, 0x74, 0x73,
3261 0x72, 0x71, 0x6e, 0x6d,
3262 0x6c, 0x6b, 0x6a, 0x69,
3263 0x67, 0x66, 0x65, 0x63,
3264 0x5c, 0x5a, 0x59, 0x56,
3265
3266 0x55, 0x54, 0x53, 0x52,
3267 0x51, 0x4e, 0x4d, 0x4c,
3268 0x4b, 0x4a, 0x49, 0x47,
3269 0x46, 0x45, 0x43, 0x3c,
3270 0x3a, 0x39, 0x36, 0x35,
3271 0x34, 0x33, 0x32, 0x31,
3272 0x2e, 0x2d, 0x2c, 0x2b,
3273 0x2a, 0x29, 0x27, 0x26,
3274 0x25, 0x23, 0x1f, 0x1E,
3275 0x1d, 0x1b, 0x18, 0x17,
3276
3277 0x10, 0x0f, 8, 4, 2, 1 }; // ALPA 0 (Fabric) is special case
3278
3279 const int number_of_al_pa = (sizeof(valid_al_pa) );
3280
3281
3282
3283 // this function looks up an al_pa from the table of valid al_pa's
3284 // we decrement from the last decimal loop ID, because soft al_pa
3285 // (our typical case) are assigned with highest priority (and high al_pa)
3286 // first. See "In-Depth FC-AL", R. Kembel pg. 38
3287 // INPUTS:
3288 // al_pa - 24 bit port identifier (8 bit al_pa on private loop)
3289 // RETURN:
3290 // Loop ID - serves are index to array of logged in ports
3291 // -1 - invalid al_pa (not all 8 bit values are legal)
3292
3293 #if (0)
3294 static int GetLoopID( ULONG al_pa )
3295 {
3296 int i;
3297
3298 for( i = number_of_al_pa -1; i >= 0; i--) // dec.
3299 {
3300 if( valid_al_pa[i] == (UCHAR)al_pa ) // take lowest 8 bits
3301 return i; // success - found valid al_pa; return decimal LoopID
3302 }
3303 return -1; // failed - not found
3304 }
3305 #endif
3306
3307
3308 // Search the singly (forward) linked list "fcPorts" looking for
3309 // either the SCSI target (if != -1), port_id (if not NULL),
3310 // or WWN (if not null), in that specific order.
3311 // If we find a SCSI nexus (from Cmnd arg), set the SCp.phase
3312 // field according to VSA or PDU
3313 // RETURNS:
3314 // Ptr to logged in port struct if found
3315 // (NULL if not found)
3316 // pLastLoggedInPort - ptr to last struct (for adding new ones)
3317 //
3318 PFC_LOGGEDIN_PORT fcFindLoggedInPort(
3319 PTACHYON fcChip,
3320 Scsi_Cmnd *Cmnd, // search linked list for Scsi Nexus (channel/target/lun)
3321 ULONG port_id, // search linked list for al_pa, or
3322 UCHAR wwn[8], // search linked list for WWN, or...
3323 PFC_LOGGEDIN_PORT *pLastLoggedInPort )
3324
3325 {
3326 PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
3327 BOOLEAN target_id_valid=FALSE;
3328 BOOLEAN port_id_valid=FALSE;
3329 BOOLEAN wwn_valid=FALSE;
3330 int i;
3331
3332
3333 if( Cmnd != NULL )
3334 target_id_valid = TRUE;
3335
3336 else if( port_id ) // note! 24-bit NULL address is illegal
3337 port_id_valid = TRUE;
3338
3339 else
3340 {
3341 if( wwn ) // non-null arg? (OK to pass NULL when not searching WWN)
3342 {
3343 for( i=0; i<8; i++) // valid WWN passed? NULL WWN invalid
3344 {
3345 if( wwn[i] != 0 )
3346 wwn_valid = TRUE; // any non-zero byte makes (presumably) valid
3347 }
3348 }
3349 }
3350 // check other options ...
3351
3352
3353 // In case multiple search options are given, we use a priority
3354 // scheme:
3355 // While valid pLoggedIn Ptr
3356 // If port_id is valid
3357 // if port_id matches, return Ptr
3358 // If wwn is valid
3359 // if wwn matches, return Ptr
3360 // Next Ptr in list
3361 //
3362 // Return NULL (not found)
3363
3364
3365 while( pLoggedInPort ) // NULL marks end of list (1st ptr always valid)
3366 {
3367 if( pLastLoggedInPort ) // caller's pointer valid?
3368 *pLastLoggedInPort = pLoggedInPort; // end of linked list
3369
3370 if( target_id_valid )
3371 {
3372 // check Linux Scsi Cmnd for channel/target Nexus match
3373 // (all luns are accessed through matching "pLoggedInPort")
3374 if( (pLoggedInPort->ScsiNexus.target == Cmnd->target)
3375 &&
3376 (pLoggedInPort->ScsiNexus.channel == Cmnd->channel))
3377 {
3378 // For "passthru" modes, the IOCTL caller is responsible
3379 // for setting the FCP-LUN addressing
3380 if( !Cmnd->SCp.sent_command ) // NOT passthru?
3381 {
3382
3383 // set the FCP-LUN addressing type
3384 Cmnd->SCp.phase = pLoggedInPort->ScsiNexus.VolumeSetAddressing;
3385
3386 // set the Device Type we got from the snooped INQUIRY string
3387 Cmnd->SCp.Message = pLoggedInPort->ScsiNexus.InqDeviceType;
3388
3389 // handle LUN masking; if not "default" (illegal) lun value,
3390 // the use it. These lun values are set by a successful
3391 // Report Luns command
3392 if( pLoggedInPort->ScsiNexus.LunMasking == 1)
3393 {
3394 // we KNOW all the valid LUNs... 0xFF is invalid!
3395 Cmnd->SCp.have_data_in = pLoggedInPort->ScsiNexus.lun[Cmnd->lun];
3396 if (pLoggedInPort->ScsiNexus.lun[Cmnd->lun] == 0xFF)
3397 return NULL;
3398 // printk("xlating lun %d to 0x%02x\n", Cmnd->lun,
3399 // pLoggedInPort->ScsiNexus.lun[Cmnd->lun]);
3400 }
3401 else
3402 Cmnd->SCp.have_data_in = Cmnd->lun; // Linux & target luns match
3403 }
3404 break; // found it!
3405 }
3406 }
3407
3408 if( port_id_valid ) // look for alpa first
3409 {
3410 if( pLoggedInPort->port_id == port_id )
3411 break; // found it!
3412 }
3413 if( wwn_valid ) // look for wwn second
3414 {
3415
3416 if( !memcmp( &pLoggedInPort->u.ucWWN[0], &wwn[0], 8))
3417 {
3418 // all 8 bytes of WWN match
3419 break; // found it!
3420 }
3421 }
3422
3423 pLoggedInPort = pLoggedInPort->pNextPort; // try next port
3424 }
3425
3426 return pLoggedInPort;
3427 }
3428
3429
3430
3431
3432 //
3433 // We need to examine the SEST table and re-validate
3434 // any open Exchanges for this LoggedInPort
3435 // To make Tachyon pay attention, Freeze FCP assists,
3436 // set VAL bits, Unfreeze FCP assists
3437 static void RevalidateSEST( struct Scsi_Host *HostAdapter,
3438 PFC_LOGGEDIN_PORT pLoggedInPort)
3439 {
3440 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
3441 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
3442 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
3443 ULONG x_ID;
3444 BOOLEAN TachFroze = FALSE;
3445
3446
3447 // re-validate any SEST exchanges that are permitted
3448 // to survive the link down (e.g., good PDISC performed)
3449 for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
3450 {
3451
3452 // If the SEST entry port_id matches the pLoggedInPort,
3453 // we need to re-validate
3454 if( (Exchanges->fcExchange[ x_ID].type == SCSI_IRE)
3455 ||
3456 (Exchanges->fcExchange[ x_ID].type == SCSI_IWE))
3457 {
3458
3459 if( (Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF) // (24-bit port ID)
3460 == pLoggedInPort->port_id)
3461 {
3462 // printk(" re-val xID %Xh ", x_ID);
3463 if( !TachFroze ) // freeze if not already frozen
3464 TachFroze |= FreezeTach( cpqfcHBAdata);
3465 fcChip->SEST->u[ x_ID].IWE.Hdr_Len |= 0x80000000; // set VAL bit
3466 }
3467 }
3468 }
3469
3470 if( TachFroze)
3471 {
3472 fcChip->UnFreezeTachyon( fcChip, 2); // both ERQ and FCP assists
3473 }
3474 }
3475
3476
3477 // Complete an Linux Cmnds that we Queued because
3478 // our FC link was down (cause immediate retry)
3479
3480 static void UnblockScsiDevice( struct Scsi_Host *HostAdapter,
3481 PFC_LOGGEDIN_PORT pLoggedInPort)
3482 {
3483 // Scsi_Device *sdev = HostAdapter->host_queue;
3484 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
3485 Scsi_Cmnd* *SCptr = &cpqfcHBAdata->LinkDnCmnd[0];
3486 Scsi_Cmnd *Cmnd;
3487 int indx;
3488
3489
3490
3491 // if the device was previously "blocked", make sure
3492 // we unblock it so Linux SCSI will resume
3493
3494 pLoggedInPort->device_blocked = FALSE; // clear our flag
3495
3496 // check the Link Down command ptr buffer;
3497 // we can complete now causing immediate retry
3498 for( indx=0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++, SCptr++)
3499 {
3500 if( *SCptr != NULL ) // scsi command to complete?
3501 {
3502 #ifdef DUMMYCMND_DBG
3503 printk("complete Cmnd %p in LinkDnCmnd[%d]\n", *SCptr,indx);
3504 #endif
3505 Cmnd = *SCptr;
3506
3507
3508 // Are there any Q'd commands for this target?
3509 if( (Cmnd->target == pLoggedInPort->ScsiNexus.target)
3510 &&
3511 (Cmnd->channel == pLoggedInPort->ScsiNexus.channel) )
3512 {
3513 Cmnd->result = (DID_SOFT_ERROR <<16); // force retry
3514 if( Cmnd->scsi_done != NULL)
3515 (*Cmnd->scsi_done)(Cmnd);
3516 else
3517 printk("LinkDnCmnd scsi_done ptr null, port_id %Xh\n",
3518 pLoggedInPort->port_id);
3519 *SCptr = NULL; // free this slot for next use
3520 }
3521 }
3522 }
3523 }
3524
3525
3526 //#define WWN_DBG 1
3527
3528 static void SetLoginFields(
3529 PFC_LOGGEDIN_PORT pLoggedInPort,
3530 TachFCHDR_GCMND* fchs,
3531 BOOLEAN PDisc,
3532 BOOLEAN Originator)
3533 {
3534 LOGIN_PAYLOAD logi; // FC-PH Port Login
3535 PRLI_REQUEST prli; // copy for BIG ENDIAN switch
3536 int i;
3537 #ifdef WWN_DBG
3538 ULONG ulBuff;
3539 #endif
3540
3541 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
3542
3543 pLoggedInPort->Originator = Originator;
3544 pLoggedInPort->port_id = fchs->s_id & 0xFFFFFF;
3545
3546 switch( fchs->pl[0] & 0xffff )
3547 {
3548 case 0x00000002: // PLOGI or PDISC ACCept?
3549 if( PDisc ) // PDISC accept
3550 goto PDISC_case;
3551
3552 case 0x00000003: // ELS_PLOGI or ELS_PLOGI_ACC
3553
3554 // Login BB_credit typically 0 for Tachyons
3555 pLoggedInPort->BB_credit = logi.cmn_services.bb_credit;
3556
3557 // e.g. 128, 256, 1024, 2048 per FC-PH spec
3558 // We have to use this when setting up SEST Writes,
3559 // since that determines frame size we send.
3560 pLoggedInPort->rx_data_size = logi.class3.rx_data_size;
3561 pLoggedInPort->plogi = TRUE;
3562 pLoggedInPort->pdisc = FALSE;
3563 pLoggedInPort->prli = FALSE; // ELS_PLOGI resets
3564 pLoggedInPort->flogi = FALSE; // ELS_PLOGI resets
3565 pLoggedInPort->logo = FALSE; // ELS_PLOGI resets
3566 pLoggedInPort->LOGO_counter = 0;// ELS_PLOGI resets
3567 pLoggedInPort->LOGO_timer = 0;// ELS_PLOGI resets
3568
3569 // was this PLOGI to a Fabric?
3570 if( pLoggedInPort->port_id == 0xFFFFFC ) // well know address
3571 pLoggedInPort->flogi = TRUE;
3572
3573
3574 for( i=0; i<8; i++) // copy the LOGIN port's WWN
3575 pLoggedInPort->u.ucWWN[i] = logi.port_name[i];
3576
3577 #ifdef WWN_DBG
3578 ulBuff = (ULONG)pLoggedInPort->u.liWWN;
3579 if( pLoggedInPort->Originator)
3580 printk("o");
3581 else
3582 printk("r");
3583 printk("PLOGI port_id %Xh, WWN %08X",
3584 pLoggedInPort->port_id, ulBuff);
3585
3586 ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
3587 printk("%08Xh fcPort %p\n", ulBuff, pLoggedInPort);
3588 #endif
3589 break;
3590
3591
3592
3593
3594 case 0x00000005: // ELS_LOGO (logout)
3595
3596
3597 pLoggedInPort->plogi = FALSE;
3598 pLoggedInPort->pdisc = FALSE;
3599 pLoggedInPort->prli = FALSE; // ELS_PLOGI resets
3600 pLoggedInPort->flogi = FALSE; // ELS_PLOGI resets
3601 pLoggedInPort->logo = TRUE; // ELS_PLOGI resets
3602 pLoggedInPort->LOGO_counter++; // ELS_PLOGI resets
3603 pLoggedInPort->LOGO_timer = 0;
3604 #ifdef WWN_DBG
3605 ulBuff = (ULONG)pLoggedInPort->u.liWWN;
3606 if( pLoggedInPort->Originator)
3607 printk("o");
3608 else
3609 printk("r");
3610 printk("LOGO port_id %Xh, WWN %08X",
3611 pLoggedInPort->port_id, ulBuff);
3612
3613 ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
3614 printk("%08Xh\n", ulBuff);
3615 #endif
3616 break;
3617
3618
3619
3620 PDISC_case:
3621 case 0x00000050: // ELS_PDISC or ELS_PDISC_ACC
3622 pLoggedInPort->LOGO_timer = 0; // stop the time-out
3623
3624 pLoggedInPort->prli = TRUE; // ready to accept FCP-SCSI I/O
3625
3626
3627
3628 #ifdef WWN_DBG
3629 ulBuff = (ULONG)pLoggedInPort->u.liWWN;
3630 if( pLoggedInPort->Originator)
3631 printk("o");
3632 else
3633 printk("r");
3634 printk("PDISC port_id %Xh, WWN %08X",
3635 pLoggedInPort->port_id, ulBuff);
3636
3637 ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
3638 printk("%08Xh\n", ulBuff);
3639 #endif
3640
3641
3642
3643 break;
3644
3645
3646
3647 case 0x1020L: // PRLI?
3648 case 0x1002L: // PRLI ACCept?
3649 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&prli, sizeof(prli));
3650
3651 pLoggedInPort->fcp_info = prli.fcp_info; // target/initiator flags
3652 pLoggedInPort->prli = TRUE; // PLOGI resets, PDISC doesn't
3653
3654 pLoggedInPort->pdisc = TRUE; // expect to send (or receive) PDISC
3655 // next time
3656 pLoggedInPort->LOGO_timer = 0; // will be set next LinkDown
3657 #ifdef WWN_DBG
3658 ulBuff = (ULONG)pLoggedInPort->u.liWWN;
3659 if( pLoggedInPort->Originator)
3660 printk("o");
3661 else
3662 printk("r");
3663 printk("PRLI port_id %Xh, WWN %08X",
3664 pLoggedInPort->port_id, ulBuff);
3665
3666 ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
3667 printk("%08Xh\n", ulBuff);
3668 #endif
3669
3670 break;
3671
3672 }
3673
3674 return;
3675 }
3676
3677
3678
3679
3680
3681
3682 static void BuildLinkServicePayload( PTACHYON fcChip, ULONG type, void* payload)
3683 {
3684 LOGIN_PAYLOAD *plogi; // FC-PH Port Login
3685 LOGIN_PAYLOAD PlogiPayload; // copy for BIG ENDIAN switch
3686 PRLI_REQUEST *prli; // FCP-SCSI Process Login
3687 PRLI_REQUEST PrliPayload; // copy for BIG ENDIAN switch
3688 LOGOUT_PAYLOAD *logo;
3689 LOGOUT_PAYLOAD LogoutPayload;
3690 // PRLO_REQUEST *prlo;
3691 // PRLO_REQUEST PrloPayload;
3692 REJECT_MESSAGE rjt, *prjt;
3693
3694 memset( &PlogiPayload, 0, sizeof( PlogiPayload));
3695 plogi = &PlogiPayload; // load into stack buffer,
3696 // then BIG-ENDIAN switch a copy to caller
3697
3698
3699 switch( type ) // payload type can be ELS_PLOGI, ELS_PRLI, ADISC, ...
3700 {
3701 case ELS_FDISC:
3702 case ELS_FLOGI:
3703 case ELS_PLOGI_ACC: // FC-PH PORT Login Accept
3704 case ELS_PLOGI: // FC-PH PORT Login
3705 case ELS_PDISC: // FC-PH2 Port Discovery - same payload as ELS_PLOGI
3706 plogi->login_cmd = LS_PLOGI;
3707 if( type == ELS_PDISC)
3708 plogi->login_cmd = LS_PDISC;
3709 else if( type == ELS_PLOGI_ACC )
3710 plogi->login_cmd = LS_ACC;
3711
3712 plogi->cmn_services.bb_credit = 0x00;
3713 plogi->cmn_services.lowest_ver = fcChip->lowest_FCPH_ver;
3714 plogi->cmn_services.highest_ver = fcChip->highest_FCPH_ver;
3715 plogi->cmn_services.bb_rx_size = TACHLITE_TS_RX_SIZE;
3716 plogi->cmn_services.common_features = CONTINUOSLY_INCREASING |
3717 RANDOM_RELATIVE_OFFSET;
3718
3719 // fill in with World Wide Name based Port Name - 8 UCHARs
3720 // get from Tach registers WWN hi & lo
3721 LoadWWN( fcChip, plogi->port_name, 0);
3722 // fill in with World Wide Name based Node/Fabric Name - 8 UCHARs
3723 // get from Tach registers WWN hi & lo
3724 LoadWWN( fcChip, plogi->node_name, 1);
3725
3726 // For Seagate Drives.
3727 //
3728 plogi->cmn_services.common_features |= 0x800;
3729 plogi->cmn_services.rel_offset = 0xFE;
3730 plogi->cmn_services.concurrent_seq = 1;
3731 plogi->class1.service_options = 0x00;
3732 plogi->class2.service_options = 0x00;
3733 plogi->class3.service_options = CLASS_VALID;
3734 plogi->class3.initiator_control = 0x00;
3735 plogi->class3.rx_data_size = MAX_RX_PAYLOAD;
3736 plogi->class3.recipient_control =
3737 ERROR_DISCARD | ONE_CATEGORY_SEQUENCE;
3738 plogi->class3.concurrent_sequences = 1;
3739 plogi->class3.open_sequences = 1;
3740 plogi->vendor_id[0] = 'C'; plogi->vendor_id[1] = 'Q';
3741 plogi->vendor_version[0] = 'C'; plogi->vendor_version[1] = 'Q';
3742 plogi->vendor_version[2] = ' '; plogi->vendor_version[3] = '0';
3743 plogi->vendor_version[4] = '0'; plogi->vendor_version[5] = '0';
3744
3745
3746 // FLOGI specific fields... (see FC-FLA, Rev 2.7, Aug 1999, sec 5.1)
3747 if( (type == ELS_FLOGI) || (type == ELS_FDISC) )
3748 {
3749 if( type == ELS_FLOGI )
3750 plogi->login_cmd = LS_FLOGI;
3751 else
3752 plogi->login_cmd = LS_FDISC;
3753
3754 plogi->cmn_services.lowest_ver = 0x20;
3755 plogi->cmn_services.common_features = 0x0800;
3756 plogi->cmn_services.rel_offset = 0;
3757 plogi->cmn_services.concurrent_seq = 0;
3758
3759 plogi->class3.service_options = 0x8800;
3760 plogi->class3.rx_data_size = 0;
3761 plogi->class3.recipient_control = 0;
3762 plogi->class3.concurrent_sequences = 0;
3763 plogi->class3.open_sequences = 0;
3764 }
3765
3766 // copy back to caller's buff, w/ BIG ENDIAN swap
3767 BigEndianSwap( (UCHAR*)&PlogiPayload, payload, sizeof(PlogiPayload));
3768 break;
3769
3770
3771 case ELS_ACC: // generic Extended Link Service ACCept
3772 plogi->login_cmd = LS_ACC;
3773 // copy back to caller's buff, w/ BIG ENDIAN swap
3774 BigEndianSwap( (UCHAR*)&PlogiPayload, payload, 4);
3775 break;
3776
3777
3778
3779 case ELS_SCR: // Fabric State Change Registration
3780 {
3781 SCR_PL scr; // state change registration
3782
3783 memset( &scr, 0, sizeof(scr));
3784
3785 scr.command = LS_SCR; // 0x62000000
3786 // see FC-FLA, Rev 2.7, Table A.22 (pg 82)
3787 scr.function = 3; // 1 = Events detected by Fabric
3788 // 2 = N_Port detected registration
3789 // 3 = Full registration
3790
3791 // copy back to caller's buff, w/ BIG ENDIAN swap
3792 BigEndianSwap( (UCHAR*)&scr, payload, sizeof(SCR_PL));
3793 }
3794
3795 break;
3796
3797
3798 case FCS_NSR: // Fabric Name Service Request
3799 {
3800 NSR_PL nsr; // Name Server Req. payload
3801
3802 memset( &nsr, 0, sizeof(NSR_PL));
3803
3804 // see Brocade Fabric Programming Guide,
3805 // Rev 1.3, pg 4-44
3806 nsr.CT_Rev = 0x01000000;
3807 nsr.FCS_Type = 0xFC020000;
3808 nsr.Command_code = 0x01710000;
3809 nsr.FCP = 8;
3810
3811 // copy back to caller's buff, w/ BIG ENDIAN swap
3812 BigEndianSwap( (UCHAR*)&nsr, payload, sizeof(NSR_PL));
3813 }
3814
3815 break;
3816
3817
3818
3819
3820 case ELS_LOGO: // FC-PH PORT LogOut
3821 logo = &LogoutPayload; // load into stack buffer,
3822 // then BIG-ENDIAN switch a copy to caller
3823 logo->cmd = LS_LOGO;
3824 // load the 3 UCHARs of the node name
3825 // (if private loop, upper two UCHARs 0)
3826 logo->reserved = 0;
3827
3828 logo->n_port_identifier[0] = (UCHAR)(fcChip->Registers.my_al_pa);
3829 logo->n_port_identifier[1] =
3830 (UCHAR)(fcChip->Registers.my_al_pa>>8);
3831 logo->n_port_identifier[2] =
3832 (UCHAR)(fcChip->Registers.my_al_pa>>16);
3833 // fill in with World Wide Name based Port Name - 8 UCHARs
3834 // get from Tach registers WWN hi & lo
3835 LoadWWN( fcChip, logo->port_name, 0);
3836
3837 BigEndianSwap( (UCHAR*)&LogoutPayload,
3838 payload, sizeof(LogoutPayload) ); // 16 UCHAR struct
3839 break;
3840
3841
3842 case ELS_LOGO_ACC: // Logout Accept (FH-PH pg 149, table 74)
3843 logo = &LogoutPayload; // load into stack buffer,
3844 // then BIG-ENDIAN switch a copy to caller
3845 logo->cmd = LS_ACC;
3846 BigEndianSwap( (UCHAR*)&LogoutPayload, payload, 4 ); // 4 UCHAR cmnd
3847 break;
3848
3849
3850 case ELS_RJT: // ELS_RJT link service reject (FH-PH pg 155)
3851
3852 prjt = (REJECT_MESSAGE*)payload; // pick up passed data
3853 rjt.command_code = ELS_RJT;
3854 // reverse fields, because of Swap that follows...
3855 rjt.vendor = prjt->reserved; // vendor specific
3856 rjt.explain = prjt->reason; //
3857 rjt.reason = prjt->explain; //
3858 rjt.reserved = prjt->vendor; //
3859 // BIG-ENDIAN switch a copy to caller
3860 BigEndianSwap( (UCHAR*)&rjt, payload, 8 ); // 8 UCHAR cmnd
3861 break;
3862
3863
3864
3865
3866
3867 case ELS_PRLI_ACC: // Process Login ACCept
3868 case ELS_PRLI: // Process Login
3869 case ELS_PRLO: // Process Logout
3870 memset( &PrliPayload, 0, sizeof( PrliPayload));
3871 prli = &PrliPayload; // load into stack buffer,
3872
3873 if( type == ELS_PRLI )
3874 prli->cmd = 0x20; // Login
3875 else if( type == ELS_PRLO )
3876 prli->cmd = 0x21; // Logout
3877 else if( type == ELS_PRLI_ACC )
3878 {
3879 prli->cmd = 0x02; // Login ACCept
3880 prli->valid = REQUEST_EXECUTED;
3881 }
3882
3883
3884 prli->valid |= SCSI_FCP | ESTABLISH_PAIR;
3885 prli->fcp_info = READ_XFER_RDY;
3886 prli->page_length = 0x10;
3887 prli->payload_length = 20;
3888 // Can be initiator AND target
3889
3890 if( fcChip->Options.initiator )
3891 prli->fcp_info |= INITIATOR_FUNCTION;
3892 if( fcChip->Options.target )
3893 prli->fcp_info |= TARGET_FUNCTION;
3894
3895 BigEndianSwap( (UCHAR*)&PrliPayload, payload, prli->payload_length);
3896 break;
3897
3898
3899
3900 default: // no can do - programming error
3901 printk(" BuildLinkServicePayload unknown!\n");
3902 break;
3903 }
3904 }
3905
3906 // loads 8 UCHARs for PORT name or NODE name base on
3907 // controller's WWN.
3908 void LoadWWN( PTACHYON fcChip, UCHAR* dest, UCHAR type)
3909 {
3910 UCHAR* bPtr, i;
3911
3912 switch( type )
3913 {
3914 case 0: // Port_Name
3915 bPtr = (UCHAR*)&fcChip->Registers.wwn_hi;
3916 for( i =0; i<4; i++)
3917 dest[i] = *bPtr++;
3918 bPtr = (UCHAR*)&fcChip->Registers.wwn_lo;
3919 for( i =4; i<8; i++)
3920 dest[i] = *bPtr++;
3921 break;
3922 case 1: // Node/Fabric _Name
3923 bPtr = (UCHAR*)&fcChip->Registers.wwn_hi;
3924 for( i =0; i<4; i++)
3925 dest[i] = *bPtr++;
3926 bPtr = (UCHAR*)&fcChip->Registers.wwn_lo;
3927 for( i =4; i<8; i++)
3928 dest[i] = *bPtr++;
3929 break;
3930 }
3931
3932 }
3933
3934
3935
3936 // We check the Port Login payload for required values. Note that
3937 // ELS_PLOGI and ELS_PDISC (Port DISCover) use the same payload.
3938
3939
3940 int verify_PLOGI( PTACHYON fcChip,
3941 TachFCHDR_GCMND* fchs,
3942 ULONG* reject_explain)
3943 {
3944 LOGIN_PAYLOAD login;
3945
3946 // source, dest, len (should be mult. of 4)
3947 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&login, sizeof(login));
3948
3949 // check FC version
3950 // if other port's highest supported version
3951 // is less than our lowest, and
3952 // if other port's lowest
3953 if( login.cmn_services.highest_ver < fcChip->lowest_FCPH_ver ||
3954 login.cmn_services.lowest_ver > fcChip->highest_FCPH_ver )
3955 {
3956 *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, OPTIONS_ERROR);
3957 return LOGICAL_ERROR;
3958 }
3959
3960 // Receive Data Field Size must be >=128
3961 // per FC-PH
3962 if (login.cmn_services.bb_rx_size < 128)
3963 {
3964 *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, DATA_FIELD_SIZE_ERROR);
3965 return LOGICAL_ERROR;
3966 }
3967
3968 // Only check Class 3 params
3969 if( login.class3.service_options & CLASS_VALID)
3970 {
3971 if (login.class3.rx_data_size < 128)
3972 {
3973 *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, INVALID_CSP);
3974 return LOGICAL_ERROR;
3975 }
3976 if( login.class3.initiator_control & XID_REQUIRED)
3977 {
3978 *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, INITIATOR_CTL_ERROR);
3979 return LOGICAL_ERROR;
3980 }
3981 }
3982 return 0; // success
3983 }
3984
3985
3986
3987
3988 int verify_PRLI( TachFCHDR_GCMND* fchs, ULONG* reject_explain)
3989 {
3990 PRLI_REQUEST prli; // buffer for BIG ENDIAN
3991
3992 // source, dest, len (should be mult. of 4)
3993 BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&prli, sizeof(prli));
3994
3995 if( prli.fcp_info == 0 ) // i.e., not target or initiator?
3996 {
3997 *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, OPTIONS_ERROR);
3998 return LOGICAL_ERROR;
3999 }
4000
4001 return 0; // success
4002 }
4003
4004
4005 // SWAP UCHARs as required by Fibre Channel (i.e. BIG ENDIAN)
4006 // INPUTS:
4007 // source - ptr to LITTLE ENDIAN ULONGS
4008 // cnt - number of UCHARs to switch (should be mult. of ULONG)
4009 // OUTPUTS:
4010 // dest - ptr to BIG ENDIAN copy
4011 // RETURN:
4012 // none
4013 //
4014 void BigEndianSwap( UCHAR *source, UCHAR *dest, USHORT cnt)
4015 {
4016 int i,j;
4017
4018 source+=3; // start at MSB of 1st ULONG
4019 for( j=0; j < cnt; j+=4, source+=4, dest+=4) // every ULONG
4020 {
4021 for( i=0; i<4; i++) // every UCHAR in ULONG
4022 *(dest+i) = *(source-i);
4023 }
4024 }
4025
4026
4027
4028
4029 // Build FC Exchanges............
4030
4031 static void buildFCPstatus(
4032 PTACHYON fcChip,
4033 ULONG ExchangeID);
4034
4035 static LONG FindFreeExchange( PTACHYON fcChip, ULONG type );
4036
4037 static ULONG build_SEST_sgList(
4038 ULONG *SESTalPairStart,
4039 Scsi_Cmnd *Cmnd,
4040 ULONG *sgPairs,
4041 PSGPAGES sgPages // link list of TL Ext. S/G pages from O/S Pool
4042 );
4043
4044 static int build_FCP_payload( Scsi_Cmnd *Cmnd,
4045 UCHAR* payload, ULONG type, ULONG fcp_dl );
4046
4047
4048 /*
4049 IRB
4050 ERQ __________________
4051 | | / | Req_A_SFS_Len | ____________________
4052 |----------| / | Req_A_SFS_Addr |------->| Reserved |
4053 | IRB | / | Req_A_D_ID | | SOF EOF TimeStamp |
4054 |-----------/ | Req_A_SEST_Index |-+ | R_CTL | D_ID |
4055 | IRB | | Req_B... | | | CS_CTL| S_ID |
4056 |-----------\ | | | | TYPE | F_CTL |
4057 | IRB | \ | | | | SEQ_ID | SEQ_CNT |
4058 |----------- \ | | +-->+--| OX_ID | RX_ID |
4059 | | \ |__________________| | | RO |
4060 | | pl (payload/cmnd) |
4061 | | ..... |
4062 | |___________________|
4063 |
4064 |
4065 +-------------------------------------------+
4066 |
4067 |
4068 | e.g. IWE
4069 | SEST __________________ for FCP_DATA
4070 | | | / | | Hdr_Len | ____________________
4071 | |----------| / | Hdr_Addr_Addr |------->| Reserved |
4072 | | [0] | / |Remote_ID| RSP_Len| | SOF EOF TimeStamp |
4073 | |-----------/ | RSP_Addr |---+ | R_CTL | D_ID |
4074 +-> [1] | | | Buff_Off | | | CS_CTL| S_ID |
4075 |-----------\ |BuffIndex| Link | | | TYPE | F_CTL |
4076 | [2] | \ | Rsvd | RX_ID | | | SEQ_ID | SEQ_CNT |
4077 |----------- \ | Data_Len | | | OX_ID | RX_ID |
4078 | ... | \ | Exp_RO | | | RO |
4079 |----------| | Exp_Byte_Cnt | | |___________________|
4080 | SEST_LEN | +--| Len | |
4081 |__________| | | Address | |
4082 | | ... | | for FCP_RSP
4083 | |__________________| | ____________________
4084 | +----| Reserved |
4085 | | SOF EOF TimeStamp |
4086 | | R_CTL | D_ID |
4087 | | CS_CTL| S_ID |
4088 +--- local or extended | .... |
4089 scatter/gather lists
4090 defining upper-layer
4091 data (e.g. from user's App)
4092
4093
4094 */
4095 // All TachLite commands must start with a SFS (Single Frame Sequence)
4096 // command. In the simplest case (a NOP Basic Link command),
4097 // only one frame header and ERQ entry is required. The most complex
4098 // case is the SCSI assisted command, which requires an ERQ entry,
4099 // SEST entry, and several frame headers and data buffers all
4100 // logically linked together.
4101 // Inputs:
4102 // cpqfcHBAdata - controller struct
4103 // type - PLOGI, SCSI_IWE, etc.
4104 // InFCHS - Incoming Tachlite FCHS which prompted this exchange
4105 // (only s_id set if we are originating)
4106 // Data - PVOID to data struct consistent with "type"
4107 // fcExchangeIndex - pointer to OX/RD ID value of built exchange
4108 // Return:
4109 // fcExchangeIndex - OX/RD ID value if successful
4110 // 0 - success
4111 // INVALID_ARGS - NULL/ invalid passed args
4112 // BAD_ALPA - Bad source al_pa address
4113 // LNKDWN_OSLS - Link Down (according to this controller)
4114 // OUTQUE_FULL - Outbound Que full
4115 // DRIVERQ_FULL - controller's Exchange array full
4116 // SEST_FULL - SEST table full
4117 //
4118 // Remarks:
4119 // Psuedo code:
4120 // Check for NULL pointers / bad args
4121 // Build outgoing FCHS - the header/payload struct
4122 // Build IRB (for ERQ entry)
4123 // if SCSI command, build SEST entry (e.g. IWE, TRE,...)
4124 // return success
4125
4126 //sbuildex
4127 ULONG cpqfcTSBuildExchange(
4128 CPQFCHBA *cpqfcHBAdata,
4129 ULONG type, // e.g. PLOGI
4130 TachFCHDR_GCMND* InFCHS, // incoming FCHS
4131 void *Data, // the CDB, scatter/gather, etc.
4132 LONG *fcExchangeIndex ) // points to allocated exchange,
4133 {
4134 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
4135 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
4136 ULONG ulStatus = 0; // assume OK
4137 USHORT ox_ID, rx_ID=0xFFFF;
4138 ULONG SfsLen=0L;
4139 TachLiteIRB* pIRB;
4140 IRBflags IRB_flags;
4141 UCHAR *pIRB_flags = (UCHAR*)&IRB_flags;
4142 TachFCHDR_GCMND* CMDfchs;
4143 TachFCHDR* dataHDR; // 32 byte HEADER ONLY FCP-DATA buffer
4144 TachFCHDR_RSP* rspHDR; // 32 byte header + RSP payload
4145 Scsi_Cmnd *Cmnd = (Scsi_Cmnd*)Data; // Linux Scsi CDB, S/G, ...
4146 TachLiteIWE* pIWE;
4147 TachLiteIRE* pIRE;
4148 TachLiteTWE* pTWE;
4149 TachLiteTRE* pTRE;
4150 ULONG fcp_dl; // total byte length of DATA transferred
4151 ULONG fl; // frame length (FC frame size, 128, 256, 512, 1024)
4152 ULONG sgPairs; // number of valid scatter/gather pairs
4153 int FCP_SCSI_command;
4154 BA_ACC_PAYLOAD *ba_acc;
4155 BA_RJT_PAYLOAD *ba_rjt;
4156
4157 // check passed ARGS
4158 if( !fcChip->ERQ ) // NULL ptr means uninitialized Tachlite chip
4159 return INVALID_ARGS;
4160
4161
4162 if( type == SCSI_IRE ||
4163 type == SCSI_TRE ||
4164 type == SCSI_IWE ||
4165 type == SCSI_TWE)
4166 FCP_SCSI_command = 1;
4167
4168 else
4169 FCP_SCSI_command = 0;
4170
4171
4172 // for commands that pass payload data (e.g. SCSI write)
4173 // examine command struct - verify that the
4174 // length of s/g buffers is adequate for total payload
4175 // length (end of list is NULL address)
4176
4177 if( FCP_SCSI_command )
4178 {
4179 if( Data ) // must have data descriptor (S/G list -- at least
4180 // one address with at least 1 byte of data)
4181 {
4182 // something to do (later)?
4183 }
4184
4185 else
4186 return INVALID_ARGS; // invalid DATA ptr
4187 }
4188
4189
4190
4191 // we can build an Exchange for later Queuing (on the TL chip)
4192 // if an empty slot is available in the DevExt for this controller
4193 // look for available Exchange slot...
4194
4195 if( type != FCP_RESPONSE &&
4196 type != BLS_ABTS &&
4197 type != BLS_ABTS_ACC ) // already have Exchange slot!
4198 *fcExchangeIndex = FindFreeExchange( fcChip, type );
4199
4200 if( *fcExchangeIndex != -1 ) // Exchange is available?
4201 {
4202 // assign tmp ptr (shorthand)
4203 CMDfchs = &Exchanges->fcExchange[ *fcExchangeIndex].fchs;
4204
4205
4206 if( Cmnd != NULL ) // (necessary for ABTS cases)
4207 {
4208 Exchanges->fcExchange[ *fcExchangeIndex].Cmnd = Cmnd; // Linux Scsi
4209 Exchanges->fcExchange[ *fcExchangeIndex].pLoggedInPort =
4210 fcFindLoggedInPort( fcChip,
4211 Exchanges->fcExchange[ *fcExchangeIndex].Cmnd, // find Scsi Nexus
4212 0, // DON'T search linked list for FC port id
4213 NULL, // DON'T search linked list for FC WWN
4214 NULL); // DON'T care about end of list
4215
4216 }
4217
4218
4219 // Build the command frame header (& data) according
4220 // to command type
4221
4222 // fields common for all SFS frame types
4223 CMDfchs->reserved = 0L; // must clear
4224 CMDfchs->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; LCr=0, no TS
4225
4226 // get the destination port_id from incoming FCHS
4227 // (initialized before calling if we're Originator)
4228 // Frame goes to port it was from - the source_id
4229
4230 CMDfchs->d_id = InFCHS->s_id &0xFFFFFF; // destination (add R_CTL later)
4231 CMDfchs->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4232
4233
4234 // now enter command-specific fields
4235 switch( type )
4236 {
4237
4238 case BLS_NOP: // FC defined basic link service command NO-OP
4239 // ensure unique X_IDs! (use tracking function)
4240
4241 *pIRB_flags = 0; // clear IRB flags
4242 IRB_flags.SFA = 1; // send SFS (not SEST index)
4243 SfsLen = *pIRB_flags;
4244
4245 SfsLen <<= 24; // shift flags to MSB
4246 SfsLen += 32L; // add len to LSB (header only - no payload)
4247
4248 // TYPE[31-24] 00 Basic Link Service
4249 // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4250 CMDfchs->d_id |= 0x80000000L; // R_CTL = 80 for NOP (Basic Link Ser.)
4251 CMDfchs->f_ctl = 0x00310000L; // xchng originator, 1st seq,....
4252 CMDfchs->seq_cnt = 0x0L;
4253 CMDfchs->ox_rx_id = 0xFFFF; // RX_ID for now; OX_ID on start
4254 CMDfchs->ro = 0x0L; // relative offset (n/a)
4255 CMDfchs->pl[0] = 0xaabbccddL; // words 8-15 frame data payload (n/a)
4256 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 1; // seconds
4257 // (NOP should complete ~instantly)
4258 break;
4259
4260
4261
4262
4263 case BLS_ABTS_ACC: // Abort Sequence ACCept
4264 *pIRB_flags = 0; // clear IRB flags
4265 IRB_flags.SFA = 1; // send SFS (not SEST index)
4266 SfsLen = *pIRB_flags;
4267
4268 SfsLen <<= 24; // shift flags to MSB
4269 SfsLen += 32 + 12; // add len to LSB (header + 3 DWORD payload)
4270
4271 CMDfchs->d_id |= 0x84000000L; // R_CTL = 84 for BASIC ACCept
4272 // TYPE[31-24] 00 Basic Link Service
4273 // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
4274 CMDfchs->f_ctl = 0x00910000L; // xchnge responder, last seq, xfer SI
4275 // CMDfchs->seq_id & count might be set from DataHdr?
4276 CMDfchs->ro = 0x0L; // relative offset (n/a)
4277 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 5; // seconds
4278 // (Timeout in case of weird error)
4279
4280 // now set the ACCept payload...
4281 ba_acc = (BA_ACC_PAYLOAD*)&CMDfchs->pl[0];
4282 memset( ba_acc, 0, sizeof( BA_ACC_PAYLOAD));
4283 // Since PLDA requires (only) entire Exchange aborts, we don't need
4284 // to worry about what the last sequence was.
4285
4286 // We expect that a "target" task is accepting the abort, so we
4287 // can use the OX/RX ID pair
4288 ba_acc->ox_rx_id = CMDfchs->ox_rx_id;
4289
4290 // source, dest, #bytes
4291 BigEndianSwap((UCHAR *)&CMDfchs->ox_rx_id, (UCHAR *)&ba_acc->ox_rx_id, 4);
4292
4293 ba_acc->low_seq_cnt = 0;
4294 ba_acc->high_seq_cnt = 0xFFFF;
4295
4296
4297 break;
4298
4299
4300 case BLS_ABTS_RJT: // Abort Sequence ACCept
4301 *pIRB_flags = 0; // clear IRB flags
4302 IRB_flags.SFA = 1; // send SFS (not SEST index)
4303 SfsLen = *pIRB_flags;
4304
4305 SfsLen <<= 24; // shift flags to MSB
4306 SfsLen += 32 + 12; // add len to LSB (header + 3 DWORD payload)
4307
4308 CMDfchs->d_id |= 0x85000000L; // R_CTL = 85 for BASIC ReJecT
4309 // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
4310 // TYPE[31-24] 00 Basic Link Service
4311 CMDfchs->f_ctl = 0x00910000L; // xchnge responder, last seq, xfer SI
4312 // CMDfchs->seq_id & count might be set from DataHdr?
4313 CMDfchs->ro = 0x0L; // relative offset (n/a)
4314 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 5; // seconds
4315 // (Timeout in case of weird error)
4316
4317 CMDfchs->ox_rx_id = InFCHS->ox_rx_id; // copy from sender!
4318
4319 // now set the ReJecT payload...
4320 ba_rjt = (BA_RJT_PAYLOAD*)&CMDfchs->pl[0];
4321 memset( ba_rjt, 0, sizeof( BA_RJT_PAYLOAD));
4322
4323 // We expect that a "target" task couldn't find the Exhange in the
4324 // array of active exchanges, so we use a new LinkService X_ID.
4325 // See Reject payload description in FC-PH (Rev 4.3), pg. 140
4326 ba_rjt->reason_code = 0x09; // "unable to perform command request"
4327 ba_rjt->reason_explain = 0x03; // invalid OX/RX ID pair
4328
4329
4330 break;
4331
4332
4333 case BLS_ABTS: // FC defined basic link service command ABTS
4334 // Abort Sequence
4335
4336
4337 *pIRB_flags = 0; // clear IRB flags
4338 IRB_flags.SFA = 1; // send SFS (not SEST index)
4339 SfsLen = *pIRB_flags;
4340
4341 SfsLen <<= 24; // shift flags to MSB
4342 SfsLen += 32L; // add len to LSB (header only - no payload)
4343
4344 // TYPE[31-24] 00 Basic Link Service
4345 // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
4346 CMDfchs->d_id |= 0x81000000L; // R_CTL = 81 for ABTS
4347 CMDfchs->f_ctl = 0x00110000L; // xchnge originator, last seq, xfer SI
4348 // CMDfchs->seq_id & count might be set from DataHdr?
4349 CMDfchs->ro = 0x0L; // relative offset (n/a)
4350 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
4351 // (ABTS must timeout when responder is gone)
4352 break;
4353
4354
4355
4356 case FCS_NSR: // Fabric Name Service Request
4357 Exchanges->fcExchange[ *fcExchangeIndex].reTries = 2;
4358
4359
4360 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
4361 // OX_ID, linked to Driver Transaction ID
4362 // (fix-up at Queing time)
4363 CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify
4364 // OX_ID set at ERQueing time
4365 *pIRB_flags = 0; // clear IRB flags
4366 IRB_flags.SFA = 1; // send SFS (not SEST index)
4367 SfsLen = *pIRB_flags;
4368
4369 SfsLen <<= 24; // shift flags to MSB
4370 SfsLen += (32L + sizeof(NSR_PL)); // add len (header & NSR payload)
4371
4372 CMDfchs->d_id |= 0x02000000L; // R_CTL = 02 for -
4373 // Name Service Request: Unsolicited
4374 // TYPE[31-24] 01 Extended Link Service
4375 // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4376 CMDfchs->f_ctl = 0x20210000L;
4377 // OX_ID will be fixed-up at Tachyon enqueing time
4378 CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt
4379 CMDfchs->ro = 0x0L; // relative offset (n/a)
4380
4381 BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
4382
4383
4384
4385
4386
4387
4388 break;
4389
4390
4391
4392
4393 case ELS_PLOGI: // FC-PH extended link service command Port Login
4394 // (May, 2000)
4395 // NOTE! This special case facilitates SANMark testing. The SANMark
4396 // test script for initialization-timeout.fcal.SANMark-1.fc
4397 // "eats" the OPN() primitive without issuing an R_RDY, causing
4398 // Tachyon to report LST (loop state timeout), which causes a
4399 // LIP. To avoid this, simply send out the frame (i.e. assuming a
4400 // buffer credit of 1) without waiting for R_RDY. Many FC devices
4401 // (other than Tachyon) have been doing this for years. We don't
4402 // ever want to do this for non-Link Service frames unless the
4403 // other device really did report non-zero login BB credit (i.e.
4404 // in the PLOGI ACCept frame).
4405 // CMDfchs->sof_eof |= 0x00000400L; // LCr=1
4406
4407 case ELS_FDISC: // Fabric Discovery (Login)
4408 case ELS_FLOGI: // Fabric Login
4409 case ELS_SCR: // Fabric State Change Registration
4410 case ELS_LOGO: // FC-PH extended link service command Port Logout
4411 case ELS_PDISC: // FC-PH extended link service cmnd Port Discovery
4412 case ELS_PRLI: // FC-PH extended link service cmnd Process Login
4413
4414 Exchanges->fcExchange[ *fcExchangeIndex].reTries = 2;
4415
4416
4417 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
4418 // OX_ID, linked to Driver Transaction ID
4419 // (fix-up at Queing time)
4420 CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify
4421 // OX_ID set at ERQueing time
4422 *pIRB_flags = 0; // clear IRB flags
4423 IRB_flags.SFA = 1; // send SFS (not SEST index)
4424 SfsLen = *pIRB_flags;
4425
4426 SfsLen <<= 24; // shift flags to MSB
4427 if( type == ELS_LOGO )
4428 SfsLen += (32L + 16L); // add len (header & PLOGI payload)
4429 else if( type == ELS_PRLI )
4430 SfsLen += (32L + 20L); // add len (header & PRLI payload)
4431 else if( type == ELS_SCR )
4432 SfsLen += (32L + sizeof(SCR_PL)); // add len (header & SCR payload)
4433 else
4434 SfsLen += (32L + 116L); // add len (header & PLOGI payload)
4435
4436 CMDfchs->d_id |= 0x22000000L; // R_CTL = 22 for -
4437 // Extended Link_Data: Unsolicited Control
4438 // TYPE[31-24] 01 Extended Link Service
4439 // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4440 CMDfchs->f_ctl = 0x01210000L;
4441 // OX_ID will be fixed-up at Tachyon enqueing time
4442 CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt
4443 CMDfchs->ro = 0x0L; // relative offset (n/a)
4444
4445 BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
4446
4447 break;
4448
4449
4450
4451 case ELS_LOGO_ACC: // FC-PH extended link service logout accept
4452 case ELS_RJT: // extended link service reject (add reason)
4453 case ELS_ACC: // ext. link service generic accept
4454 case ELS_PLOGI_ACC:// ext. link service login accept (PLOGI or PDISC)
4455 case ELS_PRLI_ACC: // ext. link service process login accept
4456
4457
4458 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 1; // assume done
4459 // ensure unique X_IDs! (use tracking function)
4460 // OX_ID from initiator cmd
4461 ox_ID = (USHORT)(InFCHS->ox_rx_id >> 16);
4462 rx_ID = 0xFFFF; // RX_ID, linked to Driver Exchange ID
4463
4464 *pIRB_flags = 0; // clear IRB flags
4465 IRB_flags.SFA = 1; // send SFS (not SEST index)
4466 SfsLen = *pIRB_flags;
4467
4468 SfsLen <<= 24; // shift flags to MSB
4469 if( type == ELS_RJT )
4470 {
4471 SfsLen += (32L + 8L); // add len (header + payload)
4472
4473 // ELS_RJT reason codes (utilize unused "reserved" field)
4474 CMDfchs->pl[0] = 1;
4475 CMDfchs->pl[1] = InFCHS->reserved;
4476
4477 }
4478 else if( (type == ELS_LOGO_ACC) || (type == ELS_ACC) )
4479 SfsLen += (32L + 4L); // add len (header + payload)
4480 else if( type == ELS_PLOGI_ACC )
4481 SfsLen += (32L + 116L); // add len (header + payload)
4482 else if( type == ELS_PRLI_ACC )
4483 SfsLen += (32L + 20L); // add len (header + payload)
4484
4485 CMDfchs->d_id |= 0x23000000L; // R_CTL = 23 for -
4486 // Extended Link_Data: Control Reply
4487 // TYPE[31-24] 01 Extended Link Service
4488 // f_ctl[23:0] exchg responder, last seq, e_s, tsi
4489 CMDfchs->f_ctl = 0x01990000L;
4490 CMDfchs->seq_cnt = 0x0L;
4491 CMDfchs->ox_rx_id = 0L; // clear
4492 CMDfchs->ox_rx_id = ox_ID; // load upper 16 bits
4493 CMDfchs->ox_rx_id <<= 16; // shift them
4494
4495 CMDfchs->ro = 0x0L; // relative offset (n/a)
4496
4497 BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
4498
4499 break;
4500
4501
4502 // Fibre Channel SCSI 'originator' sequences...
4503 // (originator means 'initiator' in FCP-SCSI)
4504
4505 case SCSI_IWE: // TachLite Initiator Write Entry
4506 {
4507 PFC_LOGGEDIN_PORT pLoggedInPort =
4508 Exchanges->fcExchange[ *fcExchangeIndex].pLoggedInPort;
4509
4510 Exchanges->fcExchange[ *fcExchangeIndex].reTries = 1;
4511 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 7; // FC2 timeout
4512
4513 // first, build FCP_CMND
4514 // unique X_ID fix-ups in StartExchange
4515
4516 *pIRB_flags = 0; // clear IRB flags
4517 IRB_flags.SFA = 1; // send SFS FCP-CMND (not SEST index)
4518
4519 // NOTE: unlike FC LinkService login frames, normal
4520 // SCSI commands are sent without outgoing verification
4521 IRB_flags.DCM = 1; // Disable completion message for Cmnd frame
4522 SfsLen = *pIRB_flags;
4523
4524 SfsLen <<= 24; // shift flags to MSB
4525 SfsLen += 64L; // add len to LSB (header & CMND payload)
4526
4527 CMDfchs->d_id |= (0x06000000L); // R_CTL = 6 for command
4528
4529 // TYPE[31-24] 8 for FCP SCSI
4530 // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4531 // valid RO
4532 CMDfchs->f_ctl = 0x08210008L;
4533 CMDfchs->seq_cnt = 0x0L;
4534 CMDfchs->ox_rx_id = 0L; // clear for now (-or- in later)
4535 CMDfchs->ro = 0x0L; // relative offset (n/a)
4536
4537 // now, fill out FCP-DATA header
4538 // (use buffer inside SEST object)
4539 dataHDR = &fcChip->SEST->DataHDR[ *fcExchangeIndex ];
4540 dataHDR->reserved = 0L; // must clear
4541 dataHDR->sof_eof = 0x75002000L; // SOFi3:EOFn no UAM; no CLS, noLCr, no TS
4542 dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA
4543 dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4544 // TYPE[31-24] 8 for FCP SCSI
4545 // f_ctl[23:0] xfer S.I.| valid RO
4546 dataHDR->f_ctl = 0x08010008L;
4547 dataHDR->seq_cnt = 0x02000000L; // sequence ID: df_ctl : seqence count
4548 dataHDR->ox_rx_id = 0L; // clear; fix-up dataHDR fields later
4549 dataHDR->ro = 0x0L; // relative offset (n/a)
4550
4551 // Now setup the SEST entry
4552 pIWE = &fcChip->SEST->u[ *fcExchangeIndex ].IWE;
4553
4554 // fill out the IWE:
4555
4556 // VALid entry:Dir outbound:DCM:enable CM:enal INT: FC frame len
4557 pIWE->Hdr_Len = 0x8e000020L; // data frame Len always 32 bytes
4558
4559
4560 // from login parameters with other port, what's the largest frame
4561 // we can send?
4562 if( pLoggedInPort == NULL)
4563 {
4564 ulStatus = INVALID_ARGS; // failed! give up
4565 break;
4566 }
4567 if( pLoggedInPort->rx_data_size >= 2048)
4568 fl = 0x00020000; // 2048 code (only support 1024!)
4569 else if( pLoggedInPort->rx_data_size >= 1024)
4570 fl = 0x00020000; // 1024 code
4571 else if( pLoggedInPort->rx_data_size >= 512)
4572 fl = 0x00010000; // 512 code
4573 else
4574 fl = 0; // 128 bytes -- should never happen
4575
4576
4577 pIWE->Hdr_Len |= fl; // add xmit FC frame len for data phase
4578 pIWE->Hdr_Addr = virt_to_bus( dataHDR );
4579 pIWE->RSP_Len = sizeof(TachFCHDR_RSP) ; // hdr+data (recv'd RSP frame)
4580 pIWE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
4581
4582 memset( &fcChip->SEST->RspHDR[ *fcExchangeIndex].pl, 0,
4583 sizeof( FCP_STATUS_RESPONSE) ); // clear out previous status
4584
4585 pIWE->RSP_Addr = virt_to_bus(
4586 &fcChip->SEST->RspHDR[ *fcExchangeIndex ]);
4587
4588 // Do we need local or extended gather list?
4589 // depends on size - we can handle 3 len/addr pairs
4590 // locally.
4591
4592 fcp_dl = build_SEST_sgList(
4593 &pIWE->GLen1,
4594 Cmnd, // S/G list
4595 &sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
4596 &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
4597
4598 if( !fcp_dl ) // error building S/G list?
4599 {
4600 ulStatus = MEMPOOL_FAIL;
4601 break; // give up
4602 }
4603
4604 // Now that we know total data length in
4605 // the passed S/G buffer, set FCP CMND frame
4606 build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
4607
4608
4609
4610 if( sgPairs > 3 ) // need extended s/g list
4611 pIWE->Buff_Off = 0x78000000L; // extended data | (no offset)
4612 else // local data pointers (in SEST)
4613 pIWE->Buff_Off = 0xf8000000L; // local data | (no offset)
4614
4615 // ULONG 5
4616 pIWE->Link = 0x0000ffffL; // Buff_Index | Link
4617
4618 pIWE->RX_ID = 0x0L; // DWord 6: RX_ID set by target XFER_RDY
4619
4620 // DWord 7
4621 pIWE->Data_Len = 0L; // TL enters rcv'd XFER_RDY BURST_LEN
4622 pIWE->Exp_RO = 0L; // DWord 8
4623 // DWord 9
4624 pIWE->Exp_Byte_Cnt = fcp_dl; // sum of gather buffers
4625 }
4626 break;
4627
4628
4629
4630
4631
4632 case SCSI_IRE: // TachLite Initiator Read Entry
4633
4634 if( Cmnd->timeout != 0)
4635 {
4636 // printk("Cmnd->timeout %d\n", Cmnd->timeout);
4637 // per Linux Scsi
4638 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = Cmnd->timeout;
4639 }
4640 else // use our best guess, based on FC & device
4641 {
4642
4643 if( Cmnd->SCp.Message == 1 ) // Tape device? (from INQUIRY)
4644 {
4645 // turn off our timeouts (for now...)
4646 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 0xFFFFFFFF;
4647 }
4648 else
4649 {
4650 Exchanges->fcExchange[ *fcExchangeIndex].reTries = 1;
4651 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 7; // per SCSI req.
4652 }
4653 }
4654
4655
4656 // first, build FCP_CMND
4657
4658
4659 *pIRB_flags = 0; // clear IRB flags
4660 IRB_flags.SFA = 1; // send SFS FCP-CMND (not SEST index)
4661 // NOTE: unlike FC LinkService login frames,
4662 // normal SCSI commands are sent "open loop"
4663 IRB_flags.DCM = 1; // Disable completion message for Cmnd frame
4664 SfsLen = *pIRB_flags;
4665
4666 SfsLen <<= 24; // shift flags to MSB
4667 SfsLen += 64L; // add len to LSB (header & CMND payload)
4668
4669 CMDfchs->d_id |= (0x06000000L); // R_CTL = 6 for command
4670
4671 // TYPE[31-24] 8 for FCP SCSI
4672 // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
4673 // valid RO
4674 CMDfchs->f_ctl = 0x08210008L;
4675 CMDfchs->seq_cnt = 0x0L;
4676 // x_ID & data direction bit set later
4677 CMDfchs->ox_rx_id = 0xFFFF; // clear
4678 CMDfchs->ro = 0x0L; // relative offset (n/a)
4679
4680
4681
4682 // Now setup the SEST entry
4683 pIRE = &fcChip->SEST->u[ *fcExchangeIndex ].IRE;
4684
4685 // fill out the IRE:
4686 // VALid entry:Dir outbound:enable CM:enal INT:
4687 pIRE->Seq_Accum = 0xCE000000L; // VAL,DIR inbound,DCM| INI,DAT,RSP
4688
4689 pIRE->reserved = 0L;
4690 pIRE->RSP_Len = sizeof(TachFCHDR_RSP) ; // hdr+data (recv'd RSP frame)
4691 pIRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
4692
4693
4694 pIRE->RSP_Addr = virt_to_bus(
4695 &fcChip->SEST->RspHDR[ *fcExchangeIndex ]);
4696
4697
4698 // Do we need local or extended gather list?
4699 // depends on size - we can handle 3 len/addr pairs
4700 // locally.
4701
4702 fcp_dl = build_SEST_sgList(
4703 &pIRE->SLen1,
4704 Cmnd, // SCSI command Data desc. with S/G list
4705 &sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
4706 &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
4707
4708
4709 if( !fcp_dl ) // error building S/G list?
4710 {
4711 // It is permissible to have a ZERO LENGTH Read command.
4712 // If there is the case, simply set fcp_dl (and Exp_Byte_Cnt)
4713 // to 0 and continue.
4714 if( Cmnd->request_bufflen == 0 )
4715 {
4716 fcp_dl = 0; // no FC DATA frames expected
4717
4718 }
4719 else
4720 {
4721 ulStatus = MEMPOOL_FAIL;
4722 break; // give up
4723 }
4724 }
4725
4726 // now that we know the S/G length, build CMND payload
4727 build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
4728
4729
4730 if( sgPairs > 3 ) // need extended s/g list
4731 pIRE->Buff_Off = 0x00000000; // DWord 4: extended s/g list, no offset
4732 else
4733 pIRE->Buff_Off = 0x80000000; // local data, no offset
4734
4735 pIRE->Buff_Index = 0x0L; // DWord 5: Buff_Index | Reserved
4736
4737 pIRE->Exp_RO = 0x0L; // DWord 6: Expected Rel. Offset
4738
4739 pIRE->Byte_Count = 0; // DWord 7: filled in by TL on err
4740 pIRE->reserved_ = 0; // DWord 8: reserved
4741 // NOTE: 0 length READ is OK.
4742 pIRE->Exp_Byte_Cnt = fcp_dl;// DWord 9: sum of scatter buffers
4743
4744 break;
4745
4746
4747
4748
4749 // Fibre Channel SCSI 'responder' sequences...
4750 // (originator means 'target' in FCP-SCSI)
4751 case SCSI_TWE: // TachLite Target Write Entry
4752
4753 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 10; // per SCSI req.
4754
4755 // first, build FCP_CMND
4756
4757 *pIRB_flags = 0; // clear IRB flags
4758 IRB_flags.SFA = 1; // send SFS (XFER_RDY)
4759 SfsLen = *pIRB_flags;
4760
4761 SfsLen <<= 24; // shift flags to MSB
4762 SfsLen += (32L + 12L);// add SFS len (header & XFER_RDY payload)
4763
4764 CMDfchs->d_id |= (0x05000000L); // R_CTL = 5 for XFER_RDY
4765
4766 // TYPE[31-24] 8 for FCP SCSI
4767 // f_ctl[23:0] exchg responder, 1st seq, xfer S.I.
4768 // valid RO
4769 CMDfchs->f_ctl = 0x08810008L;
4770 CMDfchs->seq_cnt = 0x01000000; // sequence ID: df_ctl: sequence count
4771 // use originator (other port's) OX_ID
4772 CMDfchs->ox_rx_id = InFCHS->ox_rx_id; // we want upper 16 bits
4773 CMDfchs->ro = 0x0L; // relative offset (n/a)
4774
4775 // now, fill out FCP-RSP header
4776 // (use buffer inside SEST object)
4777
4778 rspHDR = &fcChip->SEST->RspHDR[ *fcExchangeIndex ];
4779 rspHDR->reserved = 0L; // must clear
4780 rspHDR->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; no CLS, noLCr, no TS
4781 rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP
4782 rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4783 // TYPE[31-24] 8 for FCP SCSI
4784 // f_ctl[23:0] responder|last seq| xfer S.I.
4785 rspHDR->f_ctl = 0x08910000L;
4786 rspHDR->seq_cnt = 0x03000000; // sequence ID
4787 rspHDR->ox_rx_id = InFCHS->ox_rx_id; // gives us OX_ID
4788 rspHDR->ro = 0x0L; // relative offset (n/a)
4789
4790
4791 // Now setup the SEST entry
4792
4793 pTWE = &fcChip->SEST->u[ *fcExchangeIndex ].TWE;
4794
4795 // fill out the TWE:
4796
4797 // VALid entry:Dir outbound:enable CM:enal INT:
4798 pTWE->Seq_Accum = 0xC4000000L; // upper word flags
4799 pTWE->reserved = 0L;
4800 pTWE->Remote_Node_ID = 0L; // no more auto RSP frame! (TL/TS change)
4801 pTWE->Remote_Node_ID |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
4802
4803
4804 // Do we need local or extended gather list?
4805 // depends on size - we can handle 3 len/addr pairs
4806 // locally.
4807
4808 fcp_dl = build_SEST_sgList(
4809 &pTWE->SLen1,
4810 Cmnd, // S/G list
4811 &sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
4812 &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
4813
4814
4815 if( !fcp_dl ) // error building S/G list?
4816 {
4817 ulStatus = MEMPOOL_FAIL;
4818 break; // give up
4819 }
4820
4821 // now that we know the S/G length, build CMND payload
4822 build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
4823
4824
4825 if( sgPairs > 3 ) // need extended s/g list
4826 pTWE->Buff_Off = 0x00000000; // extended s/g list, no offset
4827 else
4828 pTWE->Buff_Off = 0x80000000; // local data, no offset
4829
4830 pTWE->Buff_Index = 0; // Buff_Index | Link
4831 pTWE->Exp_RO = 0;
4832 pTWE->Byte_Count = 0; // filled in by TL on err
4833 pTWE->reserved_ = 0;
4834 pTWE->Exp_Byte_Cnt = fcp_dl;// sum of scatter buffers
4835
4836 break;
4837
4838
4839
4840
4841
4842
4843 case SCSI_TRE: // TachLite Target Read Entry
4844
4845 // It doesn't make much sense for us to "time-out" a READ,
4846 // but we'll use it for design consistency and internal error recovery.
4847 Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 10; // per SCSI req.
4848
4849 // I/O request block settings...
4850 *pIRB_flags = 0; // clear IRB flags
4851 // check PRLI (process login) info
4852 // to see if Initiator Requires XFER_RDY
4853 // if not, don't send one!
4854 // { PRLI check...}
4855 IRB_flags.SFA = 0; // don't send XFER_RDY - start data
4856 SfsLen = *pIRB_flags;
4857
4858 SfsLen <<= 24; // shift flags to MSB
4859 SfsLen += (32L + 12L);// add SFS len (header & XFER_RDY payload)
4860
4861
4862
4863 // now, fill out FCP-DATA header
4864 // (use buffer inside SEST object)
4865 dataHDR = &fcChip->SEST->DataHDR[ *fcExchangeIndex ];
4866
4867 dataHDR->reserved = 0L; // must clear
4868 dataHDR->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; no CLS,noLCr,no TS
4869 dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA
4870 dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4871
4872
4873 // TYPE[31-24] 8 for FCP SCSI
4874 // f_ctl[23:0] exchg responder, not 1st seq, xfer S.I.
4875 // valid RO
4876 dataHDR->f_ctl = 0x08810008L;
4877 dataHDR->seq_cnt = 0x01000000; // sequence ID (no XRDY)
4878 dataHDR->ox_rx_id = InFCHS->ox_rx_id & 0xFFFF0000; // we want upper 16 bits
4879 dataHDR->ro = 0x0L; // relative offset (n/a)
4880
4881 // now, fill out FCP-RSP header
4882 // (use buffer inside SEST object)
4883 rspHDR = &fcChip->SEST->RspHDR[ *fcExchangeIndex ];
4884
4885 rspHDR->reserved = 0L; // must clear
4886 rspHDR->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; no CLS, noLCr, no TS
4887 rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP
4888 rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
4889 // TYPE[31-24] 8 for FCP SCSI
4890 // f_ctl[23:0] responder|last seq| xfer S.I.
4891 rspHDR->f_ctl = 0x08910000L;
4892 rspHDR->seq_cnt = 0x02000000; // sequence ID: df_ctl: sequence count
4893
4894 rspHDR->ro = 0x0L; // relative offset (n/a)
4895
4896
4897 // Now setup the SEST entry
4898 pTRE = &fcChip->SEST->u[ *fcExchangeIndex ].TRE;
4899
4900
4901 // VALid entry:Dir outbound:enable CM:enal INT:
4902 pTRE->Hdr_Len = 0x86010020L; // data frame Len always 32 bytes
4903 pTRE->Hdr_Addr = virt_to_bus( dataHDR );
4904 pTRE->RSP_Len = 64L; // hdr+data (TL assisted RSP frame)
4905 pTRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
4906 pTRE->RSP_Addr = virt_to_bus( rspHDR );
4907
4908
4909 // Do we need local or extended gather list?
4910 // depends on size - we can handle 3 len/addr pairs
4911 // locally.
4912
4913 fcp_dl = build_SEST_sgList(
4914 &pTRE->GLen1,
4915 Cmnd, // S/G list
4916 &sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
4917 &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
4918
4919
4920 if( !fcp_dl ) // error building S/G list?
4921 {
4922 ulStatus = MEMPOOL_FAIL;
4923 break; // give up
4924 }
4925
4926 // no payload or command to build -- READ doesn't need XRDY
4927
4928
4929 if( sgPairs > 3 ) // need extended s/g list
4930 pTRE->Buff_Off = 0x78000000L; // extended data | (no offset)
4931 else // local data pointers (in SEST)
4932 pTRE->Buff_Off = 0xf8000000L; // local data | (no offset)
4933
4934 // ULONG 5
4935 pTRE->Buff_Index = 0L; // Buff_Index | reserved
4936 pTRE->reserved = 0x0L; // DWord 6
4937
4938 // DWord 7: NOTE: zero length will
4939 // hang TachLite!
4940 pTRE->Data_Len = fcp_dl; // e.g. sum of scatter buffers
4941
4942 pTRE->reserved_ = 0L; // DWord 8
4943 pTRE->reserved__ = 0L; // DWord 9
4944
4945 break;
4946
4947
4948
4949
4950
4951
4952
4953 case FCP_RESPONSE:
4954 // Target response frame: this sequence uses an OX/RX ID
4955 // pair from a completed SEST exchange. We built most
4956 // of the response frame when we created the TWE/TRE.
4957
4958 *pIRB_flags = 0; // clear IRB flags
4959 IRB_flags.SFA = 1; // send SFS (RSP)
4960 SfsLen = *pIRB_flags;
4961
4962 SfsLen <<= 24; // shift flags to MSB
4963 SfsLen += sizeof(TachFCHDR_RSP);// add SFS len (header & RSP payload)
4964
4965
4966 Exchanges->fcExchange[ *fcExchangeIndex].type =
4967 FCP_RESPONSE; // change Exchange type to "response" phase
4968
4969 // take advantage of prior knowledge of OX/RX_ID pair from
4970 // previous XFER outbound frame (still in fchs of exchange)
4971 fcChip->SEST->RspHDR[ *fcExchangeIndex ].ox_rx_id =
4972 CMDfchs->ox_rx_id;
4973
4974 // Check the status of the DATA phase of the exchange so we can report
4975 // status to the initiator
4976 buildFCPstatus( fcChip, *fcExchangeIndex); // set RSP payload fields
4977
4978 memcpy(
4979 CMDfchs, // re-use same XFER fchs for Response frame
4980 &fcChip->SEST->RspHDR[ *fcExchangeIndex ],
4981 sizeof( TachFCHDR_RSP ));
4982
4983
4984 break;
4985
4986 default:
4987 printk("cpqfcTS: don't know how to build FC type: %Xh(%d)\n", type,type);
4988 break;
4989
4990 }
4991
4992
4993
4994 if( !ulStatus) // no errors above?
4995 {
4996 // FCHS is built; now build IRB
4997
4998 // link the just built FCHS (the "command") to the IRB entry
4999 // for this Exchange.
5000 pIRB = &Exchanges->fcExchange[ *fcExchangeIndex].IRB;
5001
5002 // len & flags according to command type above
5003 pIRB->Req_A_SFS_Len = SfsLen; // includes IRB flags & len
5004 pIRB->Req_A_SFS_Addr = virt_to_bus(CMDfchs); // TL needs physical addr
5005 // of frame to send
5006 pIRB->Req_A_SFS_D_ID = CMDfchs->d_id << 8; // Dest_ID must be consistent!
5007
5008 // Exchange is complete except for "fix-up" fields to be set
5009 // at Tachyon Queuing time:
5010 // IRB->Req_A_Trans_ID (OX_ID/ RX_ID):
5011 // for SEST entry, lower bits correspond to actual FC Exchange ID
5012 // fchs->OX_ID or RX_ID
5013 }
5014 else
5015 {
5016 #ifdef DBG
5017 printk( "FC Error: SEST build Pool Allocation failed\n");
5018 #endif
5019 // return resources...
5020 cpqfcTSCompleteExchange( fcChip, *fcExchangeIndex); // SEST build failed
5021 }
5022 }
5023 else // no Exchanges available
5024 {
5025 ulStatus = SEST_FULL;
5026 printk( "FC Error: no fcExchanges available\n");
5027 }
5028 return ulStatus;
5029 }
5030
5031
5032
5033
5034
5035
5036 // set RSP payload fields
5037 static void buildFCPstatus( PTACHYON fcChip, ULONG ExchangeID)
5038 {
5039 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5040 FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ExchangeID]; // shorthand
5041 PFCP_STATUS_RESPONSE pFcpStatus;
5042
5043 memset( &fcChip->SEST->RspHDR[ ExchangeID ].pl, 0,
5044 sizeof( FCP_STATUS_RESPONSE) );
5045 if( pExchange->status ) // something wrong?
5046 {
5047 pFcpStatus = (PFCP_STATUS_RESPONSE) // cast RSP buffer for this xchng
5048 &fcChip->SEST->RspHDR[ ExchangeID ].pl;
5049 if( pExchange->status & COUNT_ERROR )
5050 {
5051
5052 // set FCP response len valid (so we can report count error)
5053 pFcpStatus->fcp_status |= FCP_RSP_LEN_VALID;
5054 pFcpStatus->fcp_rsp_len = 0x04000000; // 4 byte len (BIG Endian)
5055
5056 pFcpStatus->fcp_rsp_info = FCP_DATA_LEN_NOT_BURST_LEN; // RSP_CODE
5057 }
5058 }
5059 }
5060
5061
5062
5063
5064 // This routine builds scatter/gather lists into SEST entries
5065 // INPUTS:
5066 // SESTalPair - SEST address @DWordA "Local Buffer Length"
5067 // sgList - Scatter/Gather linked list of Len/Address data buffers
5068 // OUTPUT:
5069 // sgPairs - number of valid address/length pairs
5070 // Remarks:
5071 // The SEST data buffer pointers only depend on number of
5072 // length/ address pairs, NOT on the type (IWE, TRE,...)
5073 // Up to 3 pairs can be referenced in the SEST - more than 3
5074 // require this Extended S/G list page. The page holds 4, 8, 16...
5075 // len/addr pairs, per Scatter/Gather List Page Length Reg.
5076 // TachLite allows pages to be linked to any depth.
5077
5078 //#define DBG_SEST_SGLIST 1 // for printing out S/G pairs with Ext. pages
5079
5080 static ULONG build_SEST_sgList(
5081 ULONG *SESTalPairStart, // the 3 len/address buffers in SEST
5082 Scsi_Cmnd *Cmnd,
5083 ULONG *sgPairs,
5084 PSGPAGES sgPages) // link list of TL Ext. S/G pages from O/S Pool
5085
5086 {
5087 ULONG i, AllocatedPages=0; // Tach Ext. S/G page allocations
5088 ULONG* alPair = SESTalPairStart;
5089 ULONG alignedPageAddress; // TL hardware alignment requirement
5090 int PairCount;
5091 unsigned long ulBuff;
5092 ULONG total_data_len=0; // (in bytes)
5093 ULONG bytes_to_go = Cmnd->request_bufflen; // total xfer (S/G sum)
5094 ULONG thisMappingLen;
5095 struct scatterlist *sgl; // S/G list (Linux format)
5096
5097
5098
5099 if( !Cmnd->use_sg ) // no S/G list?
5100 {
5101 *sgPairs = 1; // use "local" S/G pair in SEST entry
5102 // (for now, ignore address bits above #31)
5103 *alPair++ = bytes_to_go & 0x7ffff; // bits 18-0, length
5104 ulBuff = virt_to_bus( Cmnd->request_buffer);
5105 #if BITS_PER_LONG > 32
5106 if( ulBuff >>32 )
5107 {
5108 printk("FATAL! Tachyon DMA address %p exceeds 32 bits\n", (void*)ulBuff );
5109 return 0;
5110 }
5111 #endif
5112 *alPair = (ULONG)ulBuff;
5113 return bytes_to_go;
5114 }
5115
5116
5117 // [TBD - update for Linux to support > 32 bits addressing]
5118 // since the format for local & extended S/G lists is different,
5119 // check if S/G pairs exceeds 3.
5120 *sgPairs = Cmnd->use_sg;
5121 sgl = (struct scatterlist*)Cmnd->request_buffer;
5122
5123 if( *sgPairs <= 3 ) // need "local" SEST list
5124 {
5125 while( bytes_to_go)
5126 {
5127 thisMappingLen = sgl->length; // we want them ALL on every pass
5128 bytes_to_go = bytes_to_go - thisMappingLen;
5129
5130 // we have L/A pair; L = thisMappingLen, A = physicalAddress
5131 // load into SEST...
5132 total_data_len += thisMappingLen & 0x7ffff; // mask in valid bits
5133 // per SEST format
5134 *alPair = thisMappingLen & 0x7ffff; // bits 18-0, length
5135 // physicalAddress.HighPart <= 19; // shift to bit 19
5136
5137 // pick up bits 44-32 of upper 64-bit address
5138 // and load into 31-19 LBAU (upper addr) of SEST entry
5139 // *alPair++ |=(ULONG)((physicalAddress.HighPart & 0xFFF8));
5140 // on Tachlite TS's local S/G, we can handle 13 extra address bits
5141 // i.e., bits 31-19 are actually bits 44-32 of physicalAddress
5142
5143 alPair++;
5144
5145 ulBuff = virt_to_bus( sgl->address);
5146 #if BITS_PER_LONG > 32
5147 if( ulBuff >>32 )
5148 {
5149 printk("cqpfcTS: Tach DMA address %p > 32 bits\n", (void*)ulBuff );
5150 return 0;
5151 }
5152 #endif
5153 *alPair++ = (ULONG)ulBuff; // lower 32 bits (31-0)
5154
5155 ++sgl; // next S/G pair
5156 #ifdef DBG_SEST_SGLIST
5157 printk(" thisLen %d ", thisMappingLen);
5158 printk(" remain %d\n", bytes_to_go);
5159 #endif
5160
5161 }
5162 }
5163
5164
5165
5166
5167 else // more than 3 pairs requires Extended S/G page (Pool Allocation)
5168 {
5169 // clear out SEST DWORDs (local S/G addr) C-F (A-B set in following logic)
5170
5171
5172
5173 for( i=2; i<6; i++)
5174 alPair[i] = 0;
5175
5176 PairCount = TL_EXT_SG_PAGE_COUNT; // forces initial page allocation
5177
5178 while( bytes_to_go )
5179 {
5180
5181
5182 // Per SEST format, we can support 524287 byte lenghts per
5183 // S/G pair. Typical user buffers are 4k, and very rarely
5184 // exceed 12k due to fragmentation of physical memory pages.
5185 // However, on certain O/S system (not "user") buffers (on platforms
5186 // with huge memories like 256Meg), it's possible to exceed this
5187 // length in a single S/G address/len mapping.
5188 //
5189 // Check for Tachyon length boundary
5190 //
5191 if( sgl->length > 0x7ffff )
5192 {
5193 // never ask for more than we can handle
5194 thisMappingLen = sgl->length & 0x7ffff;
5195 }
5196 else
5197 thisMappingLen = sgl->length;
5198
5199
5200
5201 // should we load into "this" extended S/G page, or allocate
5202 // new page?
5203
5204 if( PairCount >= TL_EXT_SG_PAGE_COUNT )
5205 {
5206 // have we exceeded the max possible extended pages?
5207 if( AllocatedPages >= TL_MAX_SGPAGES)
5208 {
5209 printk("Error: aborted loop on %d Ext. S/G page allocations\n",
5210 AllocatedPages);
5211
5212 total_data_len = 0; // failure!! Ext. S/G is All-or-none affair
5213 break; // failed
5214 }
5215
5216 // Allocate the TL Extended S/G list page from O/S pool. We have
5217 // to allocated twice what we want to ensure required TL alignment
5218 // (Tachlite TL/TS User Man. Rev 6.0, p 168)
5219 // We store the original allocated PVOID so we can free later
5220
5221 sgPages->PoolPage[ AllocatedPages] =
5222 kmalloc( TL_EXT_SG_PAGE_BYTELEN*2,GFP_ATOMIC); // double for alignment
5223
5224
5225 if( !sgPages->PoolPage[ AllocatedPages] ) // Allocation failed?
5226 {
5227
5228 printk("Error: Allocation failed @ %d S/G page allocations\n",
5229 AllocatedPages);
5230
5231 total_data_len = 0; // failure!! Ext. S/G is All-or-none affair
5232 break; // give up
5233 }
5234 // clear out memory we just allocated
5235 memset( sgPages->PoolPage[AllocatedPages], 0,
5236 TL_EXT_SG_PAGE_BYTELEN*2);
5237
5238
5239 // align the memory - TL requires sizeof() Ext. S/G page alignment.
5240 // We doubled the actual required size so we could mask off LSBs
5241 // to get desired offset
5242
5243 ulBuff = virt_to_bus( sgPages->PoolPage[AllocatedPages]);
5244
5245 #if BITS_PER_LONG > 32
5246 if( ulBuff >>32 )
5247 {
5248 printk("cqpfcTS: Tach ext. S/G DMA address %p > 32 bits\n",
5249 (void*)ulBuff );
5250 return 0;
5251 }
5252 #endif
5253
5254 ulBuff += TL_EXT_SG_PAGE_BYTELEN; // ensures we pass align. boundary
5255 ulBuff &= (0xFFFFFFFF - (TL_EXT_SG_PAGE_BYTELEN -1) );// mask off LSBs
5256
5257 alignedPageAddress = (ULONG)ulBuff;
5258 #ifdef DBG_SEST_SGLIST
5259 printk("new PoolPage: %p, alignedPageAddress %lXh\n",
5260 sgPages->PoolPage[AllocatedPages], ulBuff);
5261 #endif
5262
5263
5264 // set pointer, in SEST if first Ext. S/G page, or in last pair
5265 // of linked Ext. S/G pages...
5266 // (Only 32-bit PVOIDs, so just load lower 32 bits)
5267 // NOTE: the Len field must be '0' if this is the first Ext. S/G
5268 // pointer in SEST, and not 0 otherwise.
5269 if( alPair == SESTalPairStart) // initial Ext. S/G list?
5270 *alPair = 0;
5271 else // not the SEST entry... Len must be non-0, so
5272 // arbitrarily set it to number bytes remaining
5273 *alPair = ( bytes_to_go & 0x7ffff);
5274
5275 #ifdef DBG_SEST_SGLIST
5276 printk("PairCount %d @%p even %Xh, ",
5277 PairCount, alPair, *alPair);
5278 #endif
5279 alPair++; // next DWORD
5280
5281 *alPair = alignedPageAddress; // TL needs 32-bit physical
5282 #ifdef DBG_SEST_SGLIST
5283 printk("odd %Xh\n", *alPair);
5284 #endif
5285
5286 // now reset the pointer to the ACTUAL (Extended) S/G page
5287 // which will accept the Len/ PhysicalAddress pairs
5288 alPair = bus_to_virt(alignedPageAddress);
5289
5290 AllocatedPages++;
5291 PairCount = 1; // starting new Ext. S/G page
5292 } // end of new TL Ext. S/G page allocation
5293
5294
5295 *alPair = thisMappingLen; // bits 18-0, length (range check above)
5296
5297
5298 // physicalAddress.HighPart <= 19; // shift to bit 19
5299
5300 // pick up bits 44-32 of upper 64-bit address
5301 // and load into 31-19 LBAU (upper addr) of SEST entry
5302 // *alPair |=(ULONG)((physicalAddress.HighPart & 0xFFF8));
5303
5304
5305 #ifdef DBG_SEST_SGLIST
5306 printk("PairCount %d @%p, even %Xh, ",
5307 PairCount, alPair, *alPair);
5308 #endif
5309
5310 alPair++; // next DWORD
5311 // on Tachlite TS's local S/G, we can handle 13 extra address bits
5312 // i.e., bits 31-19 are actually bits 44-32 of physicalAddress
5313
5314
5315 ulBuff = virt_to_bus( sgl->address);
5316 #if BITS_PER_LONG > 32
5317 if( ulBuff >>32 )
5318 {
5319 printk("cqpfcTS: Tach DMA address %p > 32 bits\n", (void*)ulBuff );
5320 return 0;
5321 }
5322 #endif
5323 *alPair = (ULONG)ulBuff; // lower 32 bits (31-0)
5324
5325
5326 #ifdef DBG_SEST_SGLIST
5327 printk("odd %Xh\n", *alPair);
5328 #endif
5329 alPair++; // next DWORD
5330
5331
5332 PairCount++; // next Length/Address pair
5333 bytes_to_go -= thisMappingLen;
5334 total_data_len += thisMappingLen;
5335 sgl++; // next S/G pair
5336 }
5337 }
5338 return total_data_len;
5339 }
5340
5341
5342
5343 // The Tachlite SEST table is referenced to OX_ID (or RX_ID). To optimize
5344 // performance and debuggability, we index the Exchange structure to FC X_ID
5345 // This enables us to build exchanges for later en-queing to Tachyon,
5346 // provided we have an open X_ID slot. At Tachyon queing time, we only
5347 // need an ERQ slot; then "fix-up" references in the
5348 // IRB, FCHS, etc. as needed.
5349 // RETURNS:
5350 // 0 if successful
5351 // non-zero on error
5352 //sstartex
5353 ULONG cpqfcTSStartExchange(
5354 CPQFCHBA *cpqfcHBAdata,
5355 LONG ExchangeID )
5356 {
5357 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
5358 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5359 FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ ExchangeID ]; // shorthand
5360 USHORT producer, consumer;
5361 ULONG ulStatus=0;
5362 short int ErqIndex;
5363 BOOLEAN CompleteExchange = FALSE; // e.g. ACC replies are complete
5364 BOOLEAN SestType=FALSE;
5365 ULONG InboundData=0;
5366
5367 // We will manipulate Tachlite chip registers here to successfully
5368 // start exchanges.
5369
5370 // Check that link is not down -- we can't start an exchange on a
5371 // down link!
5372
5373 if( fcChip->Registers.FMstatus.value & 0x80) // LPSM offline?
5374 {
5375 printk("fcStartExchange: PSM offline (%Xh), x_ID %Xh, type %Xh, port_id %Xh\n",
5376 fcChip->Registers.FMstatus.value & 0xFF,
5377 ExchangeID,
5378 pExchange->type,
5379 pExchange->fchs.d_id);
5380
5381 if( ExchangeID >= TACH_SEST_LEN ) // Link Service Outbound frame?
5382 {
5383 // Our most popular LinkService commands are port discovery types
5384 // (PLOGI/ PDISC...), which are implicitly nullified by Link Down
5385 // events, so it makes no sense to Que them. However, ABTS should
5386 // be queued, since exchange sequences are likely destroyed by
5387 // Link Down events, and we want to notify other ports of broken
5388 // sequences by aborting the corresponding exchanges.
5389 if( pExchange->type != BLS_ABTS )
5390 {
5391 ulStatus = LNKDWN_OSLS;
5392 goto Done;
5393 // don't Que most LinkServ exchanges on LINK DOWN
5394 }
5395 }
5396
5397 printk("fcStartExchange: Que x_ID %Xh, type %Xh\n",
5398 ExchangeID, pExchange->type);
5399 pExchange->status |= EXCHANGE_QUEUED;
5400 ulStatus = EXCHANGE_QUEUED;
5401 goto Done;
5402 }
5403
5404 // Make sure ERQ has available space.
5405
5406 producer = (USHORT)fcChip->ERQ->producerIndex; // copies for logical arith.
5407 consumer = (USHORT)fcChip->ERQ->consumerIndex;
5408 producer++; // We are testing for full que by incrementing
5409
5410 if( producer >= ERQ_LEN ) // rollover condition?
5411 producer = 0;
5412 if( consumer != producer ) // ERQ not full?
5413 {
5414 // ****************** Need Atomic access to chip registers!!********
5415
5416 // remember ERQ PI for copying IRB
5417 ErqIndex = (USHORT)fcChip->ERQ->producerIndex;
5418 fcChip->ERQ->producerIndex = producer; // this is written to Tachyon
5419 // we have an ERQ slot! If SCSI command, need SEST slot
5420 // otherwise we are done.
5421
5422 // Note that Tachyon requires that bit 15 of the OX_ID or RX_ID be
5423 // set according to direction of data to/from Tachyon for SEST assists.
5424 // For consistency, enforce this rule for Link Service (non-SEST)
5425 // exchanges as well.
5426
5427 // fix-up the X_ID field in IRB
5428 pExchange->IRB.Req_A_Trans_ID = ExchangeID & 0x7FFF; // 15-bit field
5429
5430 // fix-up the X_ID field in fchs -- depends on Originator or Responder,
5431 // outgoing or incoming data?
5432 switch( pExchange->type )
5433 {
5434 // ORIGINATOR types... we're setting our OX_ID and
5435 // defaulting the responder's RX_ID to 0xFFFF
5436
5437 case SCSI_IRE:
5438 // Requirement: set MSB of x_ID for Incoming TL data
5439 // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
5440 InboundData = 0x8000;
5441
5442 case SCSI_IWE:
5443 SestType = TRUE;
5444 pExchange->fchs.ox_rx_id = (ExchangeID | InboundData);
5445 pExchange->fchs.ox_rx_id <<= 16; // MSW shift
5446 pExchange->fchs.ox_rx_id |= 0xffff; // add default RX_ID
5447
5448 // now fix-up the Data HDR OX_ID (TL automatically does rx_id)
5449 // (not necessary for IRE -- data buffer unused)
5450 if( pExchange->type == SCSI_IWE)
5451 {
5452 fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id =
5453 pExchange->fchs.ox_rx_id;
5454
5455 }
5456
5457 break;
5458
5459
5460 case FCS_NSR: // ext. link service Name Service Request
5461 case ELS_SCR: // ext. link service State Change Registration
5462 case ELS_FDISC:// ext. link service login
5463 case ELS_FLOGI:// ext. link service login
5464 case ELS_LOGO: // FC-PH extended link service logout
5465 case BLS_NOP: // Basic link service No OPeration
5466 case ELS_PLOGI:// ext. link service login (PLOGI)
5467 case ELS_PDISC:// ext. link service login (PDISC)
5468 case ELS_PRLI: // ext. link service process login
5469
5470 pExchange->fchs.ox_rx_id = ExchangeID;
5471 pExchange->fchs.ox_rx_id <<= 16; // MSW shift
5472 pExchange->fchs.ox_rx_id |= 0xffff; // and RX_ID
5473
5474 break;
5475
5476
5477
5478
5479 // RESPONDER types... we must set our RX_ID while preserving
5480 // sender's OX_ID
5481 // outgoing (or no) data
5482 case ELS_RJT: // extended link service reject
5483 case ELS_LOGO_ACC: // FC-PH extended link service logout accept
5484 case ELS_ACC: // ext. generic link service accept
5485 case ELS_PLOGI_ACC:// ext. link service login accept (PLOGI or PDISC)
5486 case ELS_PRLI_ACC: // ext. link service process login accept
5487
5488 CompleteExchange = TRUE; // Reply (ACC or RJT) is end of exchange
5489 pExchange->fchs.ox_rx_id |= (ExchangeID & 0xFFFF);
5490
5491 break;
5492
5493
5494 // since we are a Responder, OX_ID should already be set by
5495 // cpqfcTSBuildExchange(). We need to -OR- in RX_ID
5496 case SCSI_TWE:
5497 SestType = TRUE;
5498 // Requirement: set MSB of x_ID for Incoming TL data
5499 // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
5500
5501 pExchange->fchs.ox_rx_id &= 0xFFFF0000; // clear RX_ID
5502 // Requirement: set MSB of RX_ID for Incoming TL data
5503 // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
5504 pExchange->fchs.ox_rx_id |= (ExchangeID | 0x8000);
5505 break;
5506
5507
5508 case SCSI_TRE:
5509 SestType = TRUE;
5510
5511 // there is no XRDY for SEST target read; the data
5512 // header needs to be updated. Also update the RSP
5513 // exchange IDs for the status frame, in case it is sent automatically
5514 fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id |= ExchangeID;
5515 fcChip->SEST->RspHDR[ ExchangeID ].ox_rx_id =
5516 fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id;
5517
5518 // for easier FCP response logic (works for TWE and TRE),
5519 // copy exchange IDs. (Not needed if TRE 'RSP' bit set)
5520 pExchange->fchs.ox_rx_id =
5521 fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id;
5522
5523 break;
5524
5525
5526 case FCP_RESPONSE: // using existing OX_ID/ RX_ID pair,
5527 // start SFS FCP-RESPONSE frame
5528 // OX/RX_ID should already be set! (See "fcBuild" above)
5529 CompleteExchange = TRUE; // RSP is end of FCP-SCSI exchange
5530
5531
5532 break;
5533
5534
5535 case BLS_ABTS_RJT: // uses new RX_ID, since SEST x_ID non-existent
5536 case BLS_ABTS_ACC: // using existing OX_ID/ RX_ID pair from SEST entry
5537 CompleteExchange = TRUE; // ACC or RJT marks end of FCP-SCSI exchange
5538 case BLS_ABTS: // using existing OX_ID/ RX_ID pair from SEST entry
5539
5540
5541 break;
5542
5543
5544 default:
5545 printk("Error on fcStartExchange: undefined type %Xh(%d)\n",
5546 pExchange->type, pExchange->type);
5547 return INVALID_ARGS;
5548 }
5549
5550
5551 // X_ID fields are entered -- copy IRB to Tachyon's ERQ
5552
5553
5554 memcpy(
5555 &fcChip->ERQ->QEntry[ ErqIndex ], // dest.
5556 &pExchange->IRB,
5557 32); // fixed (hardware) length!
5558
5559 PCI_TRACEO( ExchangeID, 0xA0)
5560
5561 // ACTION! May generate INT and IMQ entry
5562 writel( fcChip->ERQ->producerIndex,
5563 fcChip->Registers.ERQproducerIndex.address);
5564
5565
5566 if( ExchangeID >= TACH_SEST_LEN ) // Link Service Outbound frame?
5567 {
5568
5569 // wait for completion! (TDB -- timeout and chip reset)
5570
5571
5572 PCI_TRACEO( ExchangeID, 0xA4)
5573
5574 enable_irq( cpqfcHBAdata->HostAdapter->irq); // only way to get Sem.
5575
5576 down_interruptible( cpqfcHBAdata->TYOBcomplete);
5577
5578 disable_irq( cpqfcHBAdata->HostAdapter->irq);
5579 PCI_TRACE( 0xA4)
5580
5581 // On login exchanges, BAD_ALPA (non-existent port_id) results in
5582 // FTO (Frame Time Out) on the Outbound Completion message.
5583 // If we got an FTO status, complete the exchange (free up slot)
5584 if( CompleteExchange || // flag from Reply frames
5585 pExchange->status ) // typically, can get FRAME_TO
5586 {
5587 cpqfcTSCompleteExchange( fcChip, ExchangeID);
5588 }
5589 }
5590
5591 else // SEST Exchange
5592 {
5593 ulStatus = 0; // ship & pray success (e.g. FCP-SCSI)
5594
5595 if( CompleteExchange ) // by Type of exchange (e.g. end-of-xchng)
5596 {
5597 cpqfcTSCompleteExchange( fcChip, ExchangeID);
5598 }
5599
5600 else
5601 pExchange->status &= ~EXCHANGE_QUEUED; // clear ExchangeQueued flag
5602
5603 }
5604 }
5605
5606
5607 else // ERQ 'producer' = 'consumer' and QUE is full
5608 {
5609 ulStatus = OUTQUE_FULL; // Outbound (ERQ) Que full
5610 }
5611
5612 Done:
5613 PCI_TRACE( 0xA0)
5614 return ulStatus;
5615 }
5616
5617
5618
5619
5620
5621 // Scan fcController->fcExchanges array for a usuable index (a "free"
5622 // exchange).
5623 // Inputs:
5624 // fcChip - pointer to TachLite chip structure
5625 // Return:
5626 // index - exchange array element where exchange can be built
5627 // -1 - exchange array is full
5628 // REMARKS:
5629 // Although this is a (yuk!) linear search, we presume
5630 // that the system will complete exchanges about as quickly as
5631 // they are submitted. A full Exchange array (and hence, max linear
5632 // search time for free exchange slot) almost guarantees a Fibre problem
5633 // of some sort.
5634 // In the interest of making exchanges easier to debug, we want a LRU
5635 // (Least Recently Used) scheme.
5636
5637
5638 static LONG FindFreeExchange( PTACHYON fcChip, ULONG type )
5639 {
5640 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5641 ULONG i;
5642 ULONG ulStatus=-1; // assume failure
5643
5644
5645 if( type == SCSI_IRE ||
5646 type == SCSI_TRE ||
5647 type == SCSI_IWE ||
5648 type == SCSI_TWE)
5649 {
5650 // SCSI type - X_IDs should be from 0 to TACH_SEST_LEN-1
5651 if( fcChip->fcSestExchangeLRU >= TACH_SEST_LEN) // rollover?
5652 fcChip->fcSestExchangeLRU = 0;
5653 i = fcChip->fcSestExchangeLRU; // typically it's already free!
5654
5655 if( Exchanges->fcExchange[i].type == 0 ) // check for "free" element
5656 {
5657 ulStatus = 0; // success!
5658 }
5659
5660 else
5661 { // YUK! we need to do a linear search for free element.
5662 // Fragmentation of the fcExchange array is due to excessively
5663 // long completions or timeouts.
5664
5665 while( TRUE )
5666 {
5667 if( ++i >= TACH_SEST_LEN ) // rollover check
5668 i = 0; // beginning of SEST X_IDs
5669
5670 // printk( "looping for SCSI xchng ID: i=%d, type=%Xh\n",
5671 // i, Exchanges->fcExchange[i].type);
5672
5673 if( Exchanges->fcExchange[i].type == 0 ) // "free"?
5674 {
5675 ulStatus = 0; // success!
5676 break;
5677 }
5678 if( i == fcChip->fcSestExchangeLRU ) // wrapped-around array?
5679 {
5680 printk( "SEST X_ID space full\n");
5681 break; // failed - prevent inf. loop
5682 }
5683 }
5684 }
5685 fcChip->fcSestExchangeLRU = i + 1; // next! (rollover check next pass)
5686 }
5687
5688
5689
5690 else // Link Service type - X_IDs should be from TACH_SEST_LEN
5691 // to TACH_MAX_XID
5692 {
5693 if( fcChip->fcLsExchangeLRU >= TACH_MAX_XID || // range check
5694 fcChip->fcLsExchangeLRU < TACH_SEST_LEN ) // (e.g. startup)
5695 fcChip->fcLsExchangeLRU = TACH_SEST_LEN;
5696
5697 i = fcChip->fcLsExchangeLRU; // typically it's already free!
5698 if( Exchanges->fcExchange[i].type == 0 ) // check for "free" element
5699 {
5700 ulStatus = 0; // success!
5701 }
5702
5703 else
5704 { // YUK! we need to do a linear search for free element
5705 // Fragmentation of the fcExchange array is due to excessively
5706 // long completions or timeouts.
5707
5708 while( TRUE )
5709 {
5710 if( ++i >= TACH_MAX_XID ) // rollover check
5711 i = TACH_SEST_LEN;// beginning of Link Service X_IDs
5712
5713 // printk( "looping for xchng ID: i=%d, type=%Xh\n",
5714 // i, Exchanges->fcExchange[i].type);
5715
5716 if( Exchanges->fcExchange[i].type == 0 ) // "free"?
5717 {
5718 ulStatus = 0; // success!
5719 break;
5720 }
5721 if( i == fcChip->fcLsExchangeLRU ) // wrapped-around array?
5722 {
5723 printk( "LinkService X_ID space full\n");
5724 break; // failed - prevent inf. loop
5725 }
5726 }
5727 }
5728 fcChip->fcLsExchangeLRU = i + 1; // next! (rollover check next pass)
5729
5730 }
5731
5732 if( !ulStatus ) // success?
5733 Exchanges->fcExchange[i].type = type; // allocate it.
5734
5735 else
5736 i = -1; // error - all exchanges "open"
5737
5738 return i;
5739 }
5740
5741
5742
5743
5744
5745 // We call this routine to free an Exchange for any reason:
5746 // completed successfully, completed with error, aborted, etc.
5747
5748 // returns FALSE if Exchange failed and "retry" is acceptable
5749 // returns TRUE if Exchange was successful, or retry is impossible
5750 // (e.g. port/device gone).
5751 //scompleteexchange
5752
5753 void cpqfcTSCompleteExchange(
5754 PTACHYON fcChip,
5755 ULONG x_ID)
5756 {
5757 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5758
5759 if( x_ID < TACH_SEST_LEN ) // SEST-based (or LinkServ for FCP exchange)
5760 {
5761 if( Exchanges->fcExchange[ x_ID ].Cmnd == NULL ) // what#@!
5762 {
5763 // TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
5764 printk(" x_ID %Xh, type %Xh, NULL ptr!\n", x_ID,
5765 Exchanges->fcExchange[ x_ID ].type);
5766
5767 goto CleanUpSestResources; // this path should be very rare.
5768 }
5769
5770 // we have Linux Scsi Cmnd ptr..., now check our Exchange status
5771 // to decide how to complete this SEST FCP exchange
5772
5773 if( Exchanges->fcExchange[ x_ID ].status ) // perhaps a Tach indicated problem,
5774 // or abnormal exchange completion
5775 {
5776 // set FCP Link statistics
5777
5778 if( Exchanges->fcExchange[ x_ID ].status & FC2_TIMEOUT)
5779 fcChip->fcStats.timeouts++;
5780 if( Exchanges->fcExchange[ x_ID ].status & INITIATOR_ABORT)
5781 fcChip->fcStats.FC4aborted++;
5782 if( Exchanges->fcExchange[ x_ID ].status & COUNT_ERROR)
5783 fcChip->fcStats.CntErrors++;
5784 if( Exchanges->fcExchange[ x_ID ].status & LINKFAIL_TX)
5785 fcChip->fcStats.linkFailTX++;
5786 if( Exchanges->fcExchange[ x_ID ].status & LINKFAIL_RX)
5787 fcChip->fcStats.linkFailRX++;
5788 if( Exchanges->fcExchange[ x_ID ].status & OVERFLOW)
5789 fcChip->fcStats.CntErrors++;
5790
5791 // First, see if the Scsi upper level initiated an ABORT on this
5792 // exchange...
5793 if( Exchanges->fcExchange[ x_ID ].status == INITIATOR_ABORT )
5794 {
5795 printk(" DID_ABORT, x_ID %Xh, Cmnd %p ",
5796 x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
5797 goto CleanUpSestResources; // (we don't expect Linux _aborts)
5798 }
5799
5800 // Did our driver timeout the Exchange, or did Tachyon indicate
5801 // a failure during transmission? Ask for retry with "SOFT_ERROR"
5802 else if( Exchanges->fcExchange[ x_ID ].status & FC2_TIMEOUT)
5803 {
5804 // printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n",
5805 // x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
5806 Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
5807 }
5808
5809 // Did frame(s) for an open exchange arrive in the SFQ,
5810 // meaning the SEST was unable to process them?
5811 else if( Exchanges->fcExchange[ x_ID ].status & SFQ_FRAME)
5812 {
5813 // printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n",
5814 // x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
5815 Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
5816 }
5817
5818 // Did our driver timeout the Exchange, or did Tachyon indicate
5819 // a failure during transmission? Ask for retry with "SOFT_ERROR"
5820 else if(
5821 (Exchanges->fcExchange[ x_ID ].status & LINKFAIL_TX) ||
5822 (Exchanges->fcExchange[ x_ID ].status & PORTID_CHANGED) ||
5823 (Exchanges->fcExchange[ x_ID ].status & FRAME_TO) ||
5824 (Exchanges->fcExchange[ x_ID ].status & INV_ENTRY) ||
5825 (Exchanges->fcExchange[ x_ID ].status & ABORTSEQ_NOTIFY) )
5826
5827
5828 {
5829 // printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n",
5830 // x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
5831 Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
5832
5833
5834 }
5835
5836 // e.g., a LOGOut happened, or device never logged back in.
5837 else if( Exchanges->fcExchange[ x_ID ].status & DEVICE_REMOVED)
5838 {
5839 // printk(" *LOGOut or timeout on login!* ");
5840 // trigger?
5841 // TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
5842
5843 Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_BAD_TARGET <<16);
5844 }
5845
5846
5847 // Did Tachyon indicate a CNT error? We need further analysis
5848 // to determine if the exchange is acceptable
5849 else if( Exchanges->fcExchange[ x_ID ].status == COUNT_ERROR)
5850 {
5851 UCHAR ScsiStatus;
5852 FCP_STATUS_RESPONSE *pFcpStatus =
5853 (PFCP_STATUS_RESPONSE)&fcChip->SEST->RspHDR[ x_ID ].pl;
5854
5855 ScsiStatus = pFcpStatus->fcp_status >>24;
5856
5857 // If the command is a SCSI Read/Write type, we don't tolerate
5858 // count errors of any kind; assume the count error is due to
5859 // a dropped frame and ask for retry...
5860
5861 if(( (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x8) ||
5862 (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x28) ||
5863 (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0xA) ||
5864 (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x2A) )
5865 &&
5866 ScsiStatus == 0 )
5867 {
5868 // ask for retry
5869 /* printk("COUNT_ERROR retry, x_ID %Xh, status %Xh, Cmnd %p\n",
5870 x_ID, Exchanges->fcExchange[ x_ID ].status,
5871 Exchanges->fcExchange[ x_ID ].Cmnd);*/
5872 Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
5873 }
5874
5875 else // need more analysis
5876 {
5877 cpqfcTSCheckandSnoopFCP(fcChip, x_ID); // (will set ->result)
5878 }
5879 }
5880
5881 // default: NOTE! We don't ever want to get here. Getting here
5882 // implies something new is happening that we've never had a test
5883 // case for. Need code maintenance! Return "ERROR"
5884 else
5885 {
5886 printk("DEFAULT result %Xh, x_ID %Xh, Cmnd %p\n",
5887 Exchanges->fcExchange[ x_ID ].status, x_ID,
5888 Exchanges->fcExchange[ x_ID ].Cmnd);
5889 Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_ERROR <<16);
5890 }
5891 }
5892 else // definitely no Tach problem, but perhaps an FCP problem
5893 {
5894 // set FCP Link statistic
5895 fcChip->fcStats.ok++;
5896 cpqfcTSCheckandSnoopFCP( fcChip, x_ID); // (will set ->result)
5897 }
5898
5899 // OK, we've set the Scsi "->result" field, so proceed with calling
5900 // Linux Scsi "done" (if not NULL), and free any kernel memory we
5901 // may have allocated for the exchange.
5902
5903 PCI_TRACEO( (ULONG)Exchanges->fcExchange[x_ID].Cmnd, 0xAC);
5904 // complete the command back to upper Scsi drivers
5905 if( Exchanges->fcExchange[ x_ID ].Cmnd->scsi_done != NULL)
5906 {
5907 // Calling "done" on an Linux _abort() aborted
5908 // Cmnd causes a kernel panic trying to re-free mem.
5909 // Actually, we shouldn't do anything with an _abort CMND
5910 if( Exchanges->fcExchange[ x_ID ].Cmnd->result != (DID_ABORT<<16) )
5911 {
5912 PCI_TRACE(0xAC)
5913 (*Exchanges->fcExchange[ x_ID ].Cmnd->scsi_done)
5914 (Exchanges->fcExchange[ x_ID ].Cmnd);
5915 }
5916 else
5917 {
5918
5919 // printk(" not calling scsi_done on x_ID %Xh, Cmnd %p\n",
5920 // x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
5921 }
5922 }
5923 else{
5924 printk(" x_ID %Xh, type %Xh, Cdb0 %Xh\n", x_ID,
5925 Exchanges->fcExchange[ x_ID ].type,
5926 Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0]);
5927 printk(" cpqfcTS: Null scsi_done function pointer!\n");
5928 }
5929
5930
5931 // Now, clean up non-Scsi_Cmnd items...
5932 CleanUpSestResources:
5933
5934 // Was an Extended Scatter/Gather page allocated? We know
5935 // this by checking DWORD 4, bit 31 ("LOC") of SEST entry
5936 if( !(fcChip->SEST->u[ x_ID ].IWE.Buff_Off & 0x80000000))
5937 {
5938 int i = 0;
5939
5940 // extended S/G list was used -- Free the allocated ext. S/G pages
5941
5942 while( fcChip->SEST->sgPages[x_ID].PoolPage[i] &&
5943 (i < TL_MAX_SGPAGES) )
5944 {
5945 kfree( fcChip->SEST->sgPages[x_ID].PoolPage[i]);
5946 fcChip->SEST->sgPages[x_ID].PoolPage[i] = NULL;
5947 i++;
5948 }
5949 }
5950
5951 Exchanges->fcExchange[ x_ID ].Cmnd = NULL;
5952 } // Done with FCP (SEST) exchanges
5953
5954
5955 // the remaining logic is common to ALL Exchanges:
5956 // FCP(SEST) and LinkServ.
5957
5958 Exchanges->fcExchange[ x_ID ].type = 0; // there -- FREE!
5959 Exchanges->fcExchange[ x_ID ].status = 0;
5960
5961 PCI_TRACEO( x_ID, 0xAC)
5962
5963
5964 return;
5965 } // (END of CompleteExchange function)
5966
5967
5968
5969
5970 // Unfortunately, we must snoop all command completions in
5971 // order to manipulate certain return fields, and take note of
5972 // device types, etc., to facilitate the Fibre-Channel to SCSI
5973 // "mapping".
5974 // (Watch for BIG Endian confusion on some payload fields)
5975 void cpqfcTSCheckandSnoopFCP( PTACHYON fcChip, ULONG x_ID)
5976 {
5977 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
5978 Scsi_Cmnd *Cmnd = Exchanges->fcExchange[ x_ID].Cmnd;
5979 FCP_STATUS_RESPONSE *pFcpStatus =
5980 (PFCP_STATUS_RESPONSE)&fcChip->SEST->RspHDR[ x_ID ].pl;
5981 UCHAR ScsiStatus;
5982
5983 ScsiStatus = pFcpStatus->fcp_status >>24;
5984
5985 #ifdef FCP_COMPLETION_DBG
5986 printk("ScsiStatus = 0x%X\n", ScsiStatus);
5987 #endif
5988
5989 // First, check FCP status
5990 if( pFcpStatus->fcp_status & FCP_RSP_LEN_VALID )
5991 {
5992 // check response code (RSP_CODE) -- most popular is bad len
5993 // 1st 4 bytes of rsp info -- only byte 3 interesting
5994 if( pFcpStatus->fcp_rsp_info & FCP_DATA_LEN_NOT_BURST_LEN )
5995 {
5996
5997 // do we EVER get here?
5998 printk("cpqfcTS: FCP data len not burst len, x_ID %Xh\n", x_ID);
5999 }
6000 }
6001
6002 // for now, go by the ScsiStatus, and manipulate certain
6003 // commands when necessary...
6004 if( ScsiStatus == 0) // SCSI status byte "good"?
6005 {
6006 Cmnd->result = 0; // everything's OK
6007
6008 if( (Cmnd->cmnd[0] == INQUIRY))
6009 {
6010 UCHAR *InquiryData = Cmnd->request_buffer;
6011 PFC_LOGGEDIN_PORT pLoggedInPort;
6012
6013 // We need to manipulate INQUIRY
6014 // strings for COMPAQ RAID controllers to force
6015 // Linux to scan additional LUNs. Namely, set
6016 // the Inquiry string byte 2 (ANSI-approved version)
6017 // to 2.
6018
6019 if( !memcmp( &InquiryData[8], "COMPAQ", 6 ))
6020 {
6021 InquiryData[2] = 0x2; // claim SCSI-2 compliance,
6022 // so multiple LUNs may be scanned.
6023 // (no SCSI-2 problems known in CPQ)
6024 }
6025
6026 // snoop the Inquiry to detect Disk, Tape, etc. type
6027 // (search linked list for the port_id we sent INQUIRY to)
6028 pLoggedInPort = fcFindLoggedInPort( fcChip,
6029 NULL, // DON'T search Scsi Nexus (we will set it)
6030 Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF,
6031 NULL, // DON'T search linked list for FC WWN
6032 NULL); // DON'T care about end of list
6033
6034 if( pLoggedInPort )
6035 {
6036 pLoggedInPort->ScsiNexus.InqDeviceType = InquiryData[0];
6037 }
6038 else
6039 {
6040 printk("cpqfcTS: can't find LoggedIn FC port %06X for INQUIRY\n",
6041 Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF);
6042 }
6043 }
6044 }
6045
6046
6047 // Scsi Status not good -- pass it back to caller
6048
6049 else
6050 {
6051 Cmnd->result = ScsiStatus; // SCSI status byte is 1st
6052
6053 // check for valid "sense" data
6054
6055 if( pFcpStatus->fcp_status & FCP_SNS_LEN_VALID )
6056 { // limit Scsi Sense field length!
6057 int SenseLen = pFcpStatus->fcp_sns_len >>24; // (BigEndian) lower byte
6058
6059 SenseLen = SenseLen > sizeof( Cmnd->sense_buffer) ?
6060 sizeof( Cmnd->sense_buffer) : SenseLen;
6061
6062
6063 #ifdef FCP_COMPLETION_DBG
6064 printk("copy sense_buffer %p, len %d, result %Xh\n",
6065 Cmnd->sense_buffer, SenseLen, Cmnd->result);
6066 #endif
6067
6068 // NOTE: There is some dispute over the FCP response
6069 // format. Most FC devices assume that FCP_RSP_INFO
6070 // is 8 bytes long, in spite of the fact that FCP_RSP_LEN
6071 // is (virtually) always 0 and the field is "invalid".
6072 // Some other devices assume that
6073 // the FCP_SNS_INFO begins after FCP_RSP_LEN bytes (i.e. 0)
6074 // when the FCP_RSP is invalid (this almost appears to be
6075 // one of those "religious" issues).
6076 // Consequently, we test the usual position of FCP_SNS_INFO
6077 // for 7Xh, since the SCSI sense format says the first
6078 // byte ("error code") should be 0x70 or 0x71. In practice,
6079 // we find that every device does in fact have 0x70 or 0x71
6080 // in the first byte position, so this test works for all
6081 // FC devices.
6082 // (This logic is especially effective for the CPQ/DEC HSG80
6083 // & HSG60 controllers).
6084
6085 if( (pFcpStatus->fcp_sns_info[0] & 0x70) == 0x70 )
6086 memcpy( Cmnd->sense_buffer,
6087 &pFcpStatus->fcp_sns_info[0], SenseLen);
6088 else
6089 {
6090 unsigned char *sbPtr =
6091 (unsigned char *)&pFcpStatus->fcp_sns_info[0];
6092 sbPtr -= 8; // back up 8 bytes hoping to find the
6093 // start of the sense buffer
6094 memcpy( Cmnd->sense_buffer, sbPtr, SenseLen);
6095 }
6096
6097 // in the special case of Device Reset, tell upper layer
6098 // to immediately retry (with SOFT_ERROR status)
6099 // look for Sense Key Unit Attention (0x6) with ASC Device
6100 // Reset (0x29)
6101 // printk("SenseLen %d, Key = 0x%X, ASC = 0x%X\n",
6102 // SenseLen, Cmnd->sense_buffer[2],
6103 // Cmnd->sense_buffer[12]);
6104 if( ((Cmnd->sense_buffer[2] & 0xF) == 0x6) &&
6105 (Cmnd->sense_buffer[12] == 0x29) ) // Sense Code "reset"
6106 {
6107 Cmnd->result |= (DID_SOFT_ERROR << 16); // "Host" status byte 3rd
6108 }
6109
6110 // check for SenseKey "HARDWARE ERROR", ASC InternalTargetFailure
6111 else if( ((Cmnd->sense_buffer[2] & 0xF) == 0x4) && // "hardware error"
6112 (Cmnd->sense_buffer[12] == 0x44) ) // Addtl. Sense Code
6113 {
6114 // printk("HARDWARE_ERROR, Channel/Target/Lun %d/%d/%d\n",
6115 // Cmnd->channel, Cmnd->target, Cmnd->lun);
6116 Cmnd->result |= (DID_ERROR << 16); // "Host" status byte 3rd
6117 }
6118
6119 } // (end of sense len valid)
6120
6121 // there is no sense data to help out Linux's Scsi layers...
6122 // We'll just return the Scsi status and hope he will "do the
6123 // right thing"
6124 else
6125 {
6126 // as far as we know, the Scsi status is sufficient
6127 Cmnd->result |= (DID_OK << 16); // "Host" status byte 3rd
6128 }
6129 }
6130 }
6131
6132
6133
6134 //PPPPPPPPPPPPPPPPPPPPPPPPP PAYLOAD PPPPPPPPP
6135 // build data PAYLOAD; SCSI FCP_CMND I.U.
6136 // remember BIG ENDIAN payload - DWord values must be byte-reversed
6137 // (hence the affinity for byte pointer building).
6138
6139 static int build_FCP_payload( Scsi_Cmnd *Cmnd,
6140 UCHAR* payload, ULONG type, ULONG fcp_dl )
6141 {
6142 int i;
6143
6144
6145 switch( type)
6146 {
6147
6148 case SCSI_IWE:
6149 case SCSI_IRE:
6150 // 8 bytes FCP_LUN
6151 // Peripheral Device or Volume Set addressing, and LUN mapping
6152 // When the FC port was looked up, we copied address mode
6153 // and any LUN mask to the scratch pad SCp.phase & .mode
6154
6155 *payload++ = (UCHAR)Cmnd->SCp.phase;
6156
6157 // Now, because of "lun masking"
6158 // (aka selective storage presentation),
6159 // the contiguous Linux Scsi lun number may not match the
6160 // device's lun number, so we may have to "map".
6161
6162 *payload++ = (UCHAR)Cmnd->SCp.have_data_in;
6163
6164 // We don't know of anyone in the FC business using these
6165 // extra "levels" of addressing. In fact, confusion still exists
6166 // just using the FIRST level... ;-)
6167
6168 *payload++ = 0; // 2nd level addressing
6169 *payload++ = 0;
6170 *payload++ = 0; // 3rd level addressing
6171 *payload++ = 0;
6172 *payload++ = 0; // 4th level addressing
6173 *payload++ = 0;
6174
6175 // 4 bytes Control Field FCP_CNTL
6176 *payload++ = 0; // byte 0: (MSB) reserved
6177 *payload++ = 0; // byte 1: task codes
6178
6179 // byte 2: task management flags
6180 // another "use" of the spare field to accomplish TDR
6181 // note combination needed
6182 if( (Cmnd->cmnd[0] == RELEASE) &&
6183 (Cmnd->SCp.buffers_residual == FCP_TARGET_RESET) )
6184 {
6185 Cmnd->cmnd[0] = 0; // issue "Test Unit Ready" for TDR
6186 *payload++ = 0x20; // target device reset bit
6187 }
6188 else
6189 *payload++ = 0; // no TDR
6190 // byte 3: (LSB) execution management codes
6191 // bit 0 write, bit 1 read (don't set together)
6192
6193 if( fcp_dl != 0 )
6194 {
6195 if( type == SCSI_IWE ) // WRITE
6196 *payload++ = 1;
6197 else // READ
6198 *payload++ = 2;
6199 }
6200 else
6201 {
6202 // On some devices, if RD or WR bits are set,
6203 // and fcp_dl is 0, they will generate an error on the command.
6204 // (i.e., if direction is specified, they insist on a length).
6205 *payload++ = 0; // no data (necessary for CPQ)
6206 }
6207
6208
6209 // NOTE: clean this up if/when MAX_COMMAND_SIZE is increased to 16
6210 // FCP_CDB allows 16 byte SCSI command descriptor blk;
6211 // Linux SCSI CDB array is MAX_COMMAND_SIZE (12 at this time...)
6212 for( i=0; (i < Cmnd->cmd_len) && i < MAX_COMMAND_SIZE; i++)
6213 *payload++ = Cmnd->cmnd[i];
6214
6215 if( Cmnd->cmd_len == 16 )
6216 {
6217 memcpy( payload, &Cmnd->SCp.buffers_residual, 4);
6218 }
6219 payload+= (16 - i);
6220
6221 // FCP_DL is largest number of expected data bytes
6222 // per CDB (i.e. read/write command)
6223 *payload++ = (UCHAR)(fcp_dl >>24); // (MSB) 8 bytes data len FCP_DL
6224 *payload++ = (UCHAR)(fcp_dl >>16);
6225 *payload++ = (UCHAR)(fcp_dl >>8);
6226 *payload++ = (UCHAR)fcp_dl; // (LSB)
6227 break;
6228
6229 case SCSI_TWE: // need FCP_XFER_RDY
6230 *payload++ = 0; // (4 bytes) DATA_RO (MSB byte 0)
6231 *payload++ = 0;
6232 *payload++ = 0;
6233 *payload++ = 0; // LSB (byte 3)
6234 // (4 bytes) BURST_LEN
6235 // size of following FCP_DATA payload
6236 *payload++ = (UCHAR)(fcp_dl >>24); // (MSB) 8 bytes data len FCP_DL
6237 *payload++ = (UCHAR)(fcp_dl >>16);
6238 *payload++ = (UCHAR)(fcp_dl >>8);
6239 *payload++ = (UCHAR)fcp_dl; // (LSB)
6240 // 4 bytes RESERVED
6241 *payload++ = 0;
6242 *payload++ = 0;
6243 *payload++ = 0;
6244 *payload++ = 0;
6245 break;
6246
6247 default:
6248 break;
6249 }
6250
6251 return 0;
6252 }
6253
6254