OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [scsi/] [cpqfcTSworker.c] - Blame information for rev 1780

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.