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

Subversion Repositories or1k

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

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
 * IOCTL and procfs added by Jouke Numan
21
 * SMP testing by Chel Van Gennip
22
 *
23
 * portions copied from:
24
 * QLogic CPQFCTS SCSI-FCP
25
 * Written by Erik H. Moe, ehm@cris.com
26
 * Copyright 1995, Erik H. Moe
27
 * Renamed and updated to 1.3.x by Michael Griffith <grif@cs.ucr.edu>
28
 * Chris Loveland <cwl@iol.unh.edu> to support the isp2100 and isp2200
29
*/
30
 
31
 
32
#include <linux/blk.h>
33
#include <linux/kernel.h>
34
#include <linux/string.h>
35
#include <linux/sched.h>
36
#include <linux/types.h>
37
#include <linux/pci.h>
38
#include <linux/delay.h>
39
#include <linux/timer.h>
40
#include <linux/ioport.h>       // request_region() prototype
41
#include <linux/slab.h>
42
#include <linux/vmalloc.h>      // ioremap()
43
#include <linux/completion.h>
44
#include <linux/init.h>
45
#ifdef __alpha__
46
#define __KERNEL_SYSCALLS__
47
#endif
48
#include <asm/unistd.h>
49
#include <asm/io.h>
50
#include <asm/uaccess.h>        // ioctl related
51
#include <asm/irq.h>
52
#include <linux/spinlock.h>
53
#include "sd.h"
54
#include <scsi/scsi_ioctl.h>
55
#include "hosts.h"
56
#include "cpqfcTSchip.h"
57
#include "cpqfcTSstructs.h"
58
#include "cpqfcTStrigger.h"
59
 
60
#include "cpqfcTS.h"
61
 
62
#include <linux/config.h>
63
#include <linux/module.h>
64
#include <linux/version.h>
65
 
66
/* Embedded module documentation macros - see module.h */
67
MODULE_AUTHOR("Compaq Computer Corporation");
68
MODULE_DESCRIPTION("Driver for Compaq 64-bit/66Mhz PCI Fibre Channel HBA v. 2.1.2");
69
MODULE_LICENSE("GPL");
70
 
71
int cpqfcTS_TargetDeviceReset(Scsi_Device * ScsiDev, unsigned int reset_flags);
72
 
73
#define CPQFC_DECLARE_COMPLETION(x) DECLARE_COMPLETION(x)
74
#define CPQFC_WAITING waiting
75
#define CPQFC_COMPLETE(x) complete(x)
76
#define CPQFC_WAIT_FOR_COMPLETION(x) wait_for_completion(x);
77
 
78
/* local function to load our per-HBA (local) data for chip
79
   registers, FC link state, all FC exchanges, etc.
80
 
81
   We allocate space and compute address offsets for the
82
   most frequently accessed addresses; others (like World Wide
83
   Name) are not necessary.
84
 
85
*/
86
static void Cpqfc_initHBAdata(CPQFCHBA * cpqfcHBAdata, struct pci_dev *PciDev)
87
{
88
 
89
        cpqfcHBAdata->PciDev = PciDev;  // copy PCI info ptr
90
 
91
        // since x86 port space is 64k, we only need the lower 16 bits
92
        cpqfcHBAdata->fcChip.Registers.IOBaseL = PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
93
        cpqfcHBAdata->fcChip.Registers.IOBaseU = PciDev->resource[2].start & PCI_BASE_ADDRESS_IO_MASK;
94
 
95
        // 32-bit memory addresses
96
        cpqfcHBAdata->fcChip.Registers.MemBase = PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK;
97
        cpqfcHBAdata->fcChip.Registers.ReMapMemBase = ioremap(PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK, 0x200);
98
        cpqfcHBAdata->fcChip.Registers.RAMBase = PciDev->resource[4].start;
99
        cpqfcHBAdata->fcChip.Registers.SROMBase = PciDev->resource[5].start; // NULL for HP TS adapter
100
 
101
        // now the Tachlite chip registers
102
        // the REGISTER struct holds both the physical address & last
103
        // written value (some TL registers are WRITE ONLY)
104
 
105
        cpqfcHBAdata->fcChip.Registers.SFQconsumerIndex.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_SFQ_CONSUMER_INDEX;
106
 
107
        cpqfcHBAdata->fcChip.Registers.ERQproducerIndex.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_ERQ_PRODUCER_INDEX;
108
 
109
        // TL Frame Manager
110
        cpqfcHBAdata->fcChip.Registers.FMconfig.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_CONFIG;
111
        cpqfcHBAdata->fcChip.Registers.FMcontrol.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_CONTROL;
112
        cpqfcHBAdata->fcChip.Registers.FMstatus.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_STATUS;
113
        cpqfcHBAdata->fcChip.Registers.FMLinkStatus1.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_LINK_STAT1;
114
        cpqfcHBAdata->fcChip.Registers.FMLinkStatus2.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_LINK_STAT2;
115
        cpqfcHBAdata->fcChip.Registers.FMBB_CreditZero.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_BB_CREDIT0;
116
 
117
        // TL Control Regs
118
        cpqfcHBAdata->fcChip.Registers.TYconfig.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_CONFIG;
119
        cpqfcHBAdata->fcChip.Registers.TYcontrol.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_CONTROL;
120
        cpqfcHBAdata->fcChip.Registers.TYstatus.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_STATUS;
121
        cpqfcHBAdata->fcChip.Registers.rcv_al_pa.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_RCV_AL_PA;
122
        cpqfcHBAdata->fcChip.Registers.ed_tov.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_ED_TOV;
123
 
124
 
125
        cpqfcHBAdata->fcChip.Registers.INTEN.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTEN;
126
        cpqfcHBAdata->fcChip.Registers.INTPEND.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTPEND;
127
        cpqfcHBAdata->fcChip.Registers.INTSTAT.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTSTAT;
128
 
129
        DEBUG_PCI(printk("  cpqfcHBAdata->fcChip.Registers. :\n"));
130
        DEBUG_PCI(printk("    IOBaseL = %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseL));
131
        DEBUG_PCI(printk("    IOBaseU = %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseU));
132
 
133
        printk(" ioremap'd Membase: %p\n", cpqfcHBAdata->fcChip.Registers.ReMapMemBase);
134
 
135
        DEBUG_PCI(printk("    SFQconsumerIndex.address = %p\n", cpqfcHBAdata->fcChip.Registers.SFQconsumerIndex.address));
136
        DEBUG_PCI(printk("    ERQproducerIndex.address = %p\n", cpqfcHBAdata->fcChip.Registers.ERQproducerIndex.address));
137
        DEBUG_PCI(printk("    TYconfig.address = %p\n", cpqfcHBAdata->fcChip.Registers.TYconfig.address));
138
        DEBUG_PCI(printk("    FMconfig.address = %p\n", cpqfcHBAdata->fcChip.Registers.FMconfig.address));
139
        DEBUG_PCI(printk("    FMcontrol.address = %p\n", cpqfcHBAdata->fcChip.Registers.FMcontrol.address));
140
 
141
        // set default options for FC controller (chip)
142
        cpqfcHBAdata->fcChip.Options.initiator = 1;     // default: SCSI initiator
143
        cpqfcHBAdata->fcChip.Options.target = 0; // default: SCSI target
144
        cpqfcHBAdata->fcChip.Options.extLoopback = 0;    // default: no loopback @GBIC
145
        cpqfcHBAdata->fcChip.Options.intLoopback = 0;    // default: no loopback inside chip
146
 
147
        // set highest and lowest FC-PH version the adapter/driver supports
148
        // (NOT strict compliance)
149
        cpqfcHBAdata->fcChip.highest_FCPH_ver = FC_PH3;
150
        cpqfcHBAdata->fcChip.lowest_FCPH_ver = FC_PH43;
151
 
152
        // set function points for this controller / adapter
153
        cpqfcHBAdata->fcChip.ResetTachyon = CpqTsResetTachLite;
154
        cpqfcHBAdata->fcChip.FreezeTachyon = CpqTsFreezeTachlite;
155
        cpqfcHBAdata->fcChip.UnFreezeTachyon = CpqTsUnFreezeTachlite;
156
        cpqfcHBAdata->fcChip.CreateTachyonQues = CpqTsCreateTachLiteQues;
157
        cpqfcHBAdata->fcChip.DestroyTachyonQues = CpqTsDestroyTachLiteQues;
158
        cpqfcHBAdata->fcChip.InitializeTachyon = CpqTsInitializeTachLite;
159
        cpqfcHBAdata->fcChip.LaserControl = CpqTsLaserControl;
160
        cpqfcHBAdata->fcChip.ProcessIMQEntry = CpqTsProcessIMQEntry;
161
        cpqfcHBAdata->fcChip.InitializeFrameManager = CpqTsInitializeFrameManager;;
162
        cpqfcHBAdata->fcChip.ReadWriteWWN = CpqTsReadWriteWWN;
163
        cpqfcHBAdata->fcChip.ReadWriteNVRAM = CpqTsReadWriteNVRAM;
164
 
165
 
166
 
167
}
168
 
169
 
170
/* (borrowed from linux/drivers/scsi/hosts.c) */
171
static void launch_FCworker_thread(struct Scsi_Host *HostAdapter)
172
{
173
        DECLARE_MUTEX_LOCKED(sem);
174
 
175
        CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) HostAdapter->hostdata;
176
 
177
        ENTER("launch_FC_worker_thread");
178
 
179
        cpqfcHBAdata->notify_wt = &sem;
180
 
181
        /* must unlock before kernel_thread(), for it may cause a reschedule. */
182
        spin_unlock_irq(&io_request_lock);
183
        kernel_thread((int (*)(void *)) cpqfcTSWorkerThread, (void *) HostAdapter, 0);
184
        /*
185
         * Now wait for the kernel error thread to initialize itself
186
 
187
         */
188
        down(&sem);
189
        spin_lock_irq(&io_request_lock);
190
        cpqfcHBAdata->notify_wt = NULL;
191
 
192
        LEAVE("launch_FC_worker_thread");
193
 
194
}
195
 
196
 
197
/* "Entry" point to discover if any supported PCI
198
   bus adapter can be found
199
*/
200
/* We're supporting:
201
 * Compaq 64-bit, 66MHz HBA with Tachyon TS
202
 * Agilent XL2
203
 * HP Tachyon
204
 */
205
#define HBA_TYPES 3
206
 
207
#ifndef PCI_DEVICE_ID_COMPAQ_
208
#define PCI_DEVICE_ID_COMPAQ_TACHYON    0xa0fc
209
#endif
210
 
211
static struct SupportedPCIcards cpqfc_boards[] __initdata = {
212
        {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TACHYON},
213
        {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_TACHLITE},
214
        {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_TACHYON},
215
};
216
 
217
 
218
int cpqfcTS_detect(Scsi_Host_Template * ScsiHostTemplate)
219
{
220
        int NumberOfAdapters = 0;        // how many of our PCI adapters are found?
221
        struct pci_dev *PciDev = NULL;
222
        struct Scsi_Host *HostAdapter = NULL;
223
        CPQFCHBA *cpqfcHBAdata = NULL;
224
        struct timer_list *cpqfcTStimer = NULL;
225
        int i;
226
 
227
        ENTER("cpqfcTS_detect");
228
 
229
#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
230
        ScsiHostTemplate->proc_dir = &proc_scsi_cpqfcTS;
231
#else
232
        ScsiHostTemplate->proc_name = "cpqfcTS";
233
#endif
234
 
235
        if (pci_present() == 0)  // no PCI busses?
236
        {
237
                printk("  no PCI bus?@#!\n");
238
                return NumberOfAdapters;
239
        }
240
 
241
        for (i = 0; i < HBA_TYPES; i++) {
242
                // look for all HBAs of each type
243
 
244
                while ((PciDev = pci_find_device(cpqfc_boards[i].vendor_id, cpqfc_boards[i].device_id, PciDev))) {
245
 
246
                        if (pci_enable_device(PciDev) != 0) {
247
                                printk(KERN_WARNING "cpqfc: pci_enable_devive failed, skipping.\n");
248
                                continue;
249
                        }
250
                        if (pci_set_dma_mask(PciDev, CPQFCTS_DMA_MASK) != 0) {
251
                                printk(KERN_WARNING "cpqfc: HBA cannot support required DMA mask, skipping.\n");
252
                                continue;
253
                        }
254
                        // NOTE: (kernel 2.2.12-32) limits allocation to 128k bytes...
255
                        printk(" scsi_register allocating %d bytes for FC HBA\n", (u32) sizeof(CPQFCHBA));
256
 
257
                        HostAdapter = scsi_register(ScsiHostTemplate, sizeof(CPQFCHBA));
258
 
259
                        if (HostAdapter == NULL)
260
                                continue;
261
                        DEBUG_PCI(printk("  HBA found!\n"));
262
                        DEBUG_PCI(printk("  HostAdapter->PciDev->irq = %u\n", PciDev->irq));
263
                        DEBUG_PCI(printk("  PciDev->baseaddress[0]= %lx\n", PciDev->resource[0].start));
264
                        DEBUG_PCI(printk("  PciDev->baseaddress[1]= %lx\n", PciDev->resource[1].start));
265
                        DEBUG_PCI(printk("  PciDev->baseaddress[2]= %lx\n", PciDev->resource[2].start));
266
                        DEBUG_PCI(printk("  PciDev->baseaddress[3]= %lx\n", PciDev->resource[3].start));
267
 
268
                        scsi_set_pci_device(HostAdapter, PciDev);
269
                        HostAdapter->irq = PciDev->irq; // copy for Scsi layers
270
 
271
                        // HP Tachlite uses two (255-byte) ranges of Port I/O (lower & upper),
272
                        // for a total I/O port address space of 512 bytes.
273
                        // mask out the I/O port address (lower) & record
274
                        HostAdapter->io_port = (unsigned int)
275
                            PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
276
                        HostAdapter->n_io_port = 0xff;
277
 
278
                        // i.e., expect 128 targets (arbitrary number), while the
279
                        //  RA-4000 supports 32 LUNs
280
                        HostAdapter->max_id = 0; // incremented as devices log in    
281
                        HostAdapter->max_lun = CPQFCTS_MAX_LUN; // LUNs per FC device
282
                        HostAdapter->max_channel = CPQFCTS_MAX_CHANNEL; // multiple busses?
283
 
284
                        // get the pointer to our HBA specific data... (one for
285
                        // each HBA on the PCI bus(ses)).
286
                        cpqfcHBAdata = (CPQFCHBA *) HostAdapter->hostdata;
287
 
288
                        // make certain our data struct is clear
289
                        memset(cpqfcHBAdata, 0, sizeof(CPQFCHBA));
290
 
291
 
292
                        // initialize our HBA info
293
                        cpqfcHBAdata->HBAnum = NumberOfAdapters;
294
 
295
                        cpqfcHBAdata->HostAdapter = HostAdapter;        // back ptr
296
                        Cpqfc_initHBAdata(cpqfcHBAdata, PciDev);        // fill MOST fields
297
 
298
                        cpqfcHBAdata->HBAnum = NumberOfAdapters;
299
                        cpqfcHBAdata->hba_spinlock = SPIN_LOCK_UNLOCKED;
300
 
301
                        // request necessary resources and check for conflicts
302
                        if (request_irq(HostAdapter->irq, cpqfcTS_intr_handler, SA_INTERRUPT | SA_SHIRQ, DEV_NAME, HostAdapter)) {
303
                                printk(" IRQ %u already used\n", HostAdapter->irq);
304
                                scsi_unregister(HostAdapter);
305
                                continue;
306
                        }
307
                        // Since we have two 256-byte I/O port ranges (upper
308
                        // and lower), check them both
309
                        if (check_region(cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff)) {
310
                                printk("  cpqfcTS address in use: %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseU);
311
                                free_irq(HostAdapter->irq, HostAdapter);
312
                                scsi_unregister(HostAdapter);
313
                                continue;
314
                        }
315
 
316
                        if (check_region(cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff)) {
317
                                printk("  cpqfcTS address in use: %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseL);
318
                                free_irq(HostAdapter->irq, HostAdapter);
319
                                scsi_unregister(HostAdapter);
320
                                continue;
321
                        }
322
                        // OK, we should be able to grab everything we need now.
323
                        request_region(cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff, DEV_NAME);
324
                        request_region(cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff, DEV_NAME);
325
                        DEBUG_PCI(printk("  Requesting 255 I/O addresses @ %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseL));
326
                        DEBUG_PCI(printk("  Requesting 255 I/O addresses @ %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseU));
327
 
328
 
329
                        // start our kernel worker thread
330
 
331
                        launch_FCworker_thread(HostAdapter);
332
 
333
 
334
                        // start our TimerTask...
335
 
336
                        cpqfcTStimer = &cpqfcHBAdata->cpqfcTStimer;
337
 
338
                        init_timer(cpqfcTStimer);       // Linux clears next/prev values
339
                        cpqfcTStimer->expires = jiffies + HZ;   // one second
340
                        cpqfcTStimer->data = (unsigned long) cpqfcHBAdata;      // this adapter
341
                        cpqfcTStimer->function = cpqfcTSheartbeat;      // handles timeouts, housekeeping
342
 
343
                        add_timer(cpqfcTStimer);        // give it to Linux
344
 
345
 
346
                        // now initialize our hardware...
347
                        if (cpqfcHBAdata->fcChip.InitializeTachyon(cpqfcHBAdata, 1, 1)) {
348
                                printk(KERN_WARNING "cpqfc: initialization of HBA hardware failed.\n");
349
                                // FIXME: might want to do something better than nothing here.
350
                        }
351
 
352
                        cpqfcHBAdata->fcStatsTime = jiffies;    // (for FC Statistics delta)
353
 
354
                        // give our HBA time to initialize and login current devices...
355
                        {
356
                                // The Brocade switch (e.g. 2400, 2010, etc.) as of March 2000,
357
                                // has the following algorithm for FL_Port startup:
358
                                // Time(sec) Action
359
                                // 0:        Device Plugin and LIP(F7,F7) transmission
360
                                // 1.0       LIP incoming
361
                                // 1.027     LISA incoming, no CLS! (link not up)
362
                                // 1.028     NOS incoming (switch test for N_Port)
363
                                // 1.577     ED_TOV expired, transmit LIPs again        
364
                                // 3.0       LIP(F8,F7) incoming (switch passes Tach Prim.Sig)
365
                                // 3.028     LILP received, link up, FLOGI starts
366
                                // slowest(worst) case, measured on 1Gb Finisar GT analyzer
367
 
368
                                unsigned long stop_time;
369
 
370
                                spin_unlock_irq(&io_request_lock);
371
                                stop_time = jiffies + 4 * HZ;
372
                                while (time_before(jiffies, stop_time))
373
                                        schedule();     // (our worker task needs to run)
374
 
375
                                spin_lock_irq(&io_request_lock);
376
                        }
377
 
378
                        NumberOfAdapters++;
379
                }               // end of while()
380
        }
381
 
382
        LEAVE("cpqfcTS_detect");
383
 
384
        return NumberOfAdapters;
385
}
386
 
387
static void my_ioctl_done(Scsi_Cmnd * SCpnt)
388
{
389
        struct request *req;
390
 
391
        req = &SCpnt->request;
392
        req->rq_status = RQ_SCSI_DONE;  /* Busy, but indicate request done */
393
 
394
        if (req->CPQFC_WAITING != NULL)
395
                CPQFC_COMPLETE(req->CPQFC_WAITING);
396
}
397
 
398
 
399
 
400
int cpqfcTS_ioctl(Scsi_Device * ScsiDev, int Cmnd, void *arg)
401
{
402
        int result = 0;
403
        struct Scsi_Host *HostAdapter = ScsiDev->host;
404
        CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) HostAdapter->hostdata;
405
        PTACHYON fcChip = &cpqfcHBAdata->fcChip;
406
        PFC_LOGGEDIN_PORT pLoggedInPort;
407
        Scsi_Cmnd DumCmnd;
408
        int i, j;
409
        VENDOR_IOCTL_REQ ioc;
410
        cpqfc_passthru_t *vendor_cmd;
411
        Scsi_Device *SDpnt;
412
        Scsi_Cmnd *ScsiPassThruCmnd;
413
 
414
        ENTER("cpqfcTS_ioctl ");
415
 
416
        // can we find an FC device mapping to this SCSI target?
417
        DumCmnd.channel = ScsiDev->channel;     // For searching
418
        DumCmnd.target = ScsiDev->id;
419
        DumCmnd.lun = ScsiDev->lun;
420
        pLoggedInPort = fcFindLoggedInPort(fcChip, &DumCmnd,    // search Scsi Nexus
421
                                           0,    // DON'T search linked list for FC port id
422
                                           NULL,        // DON'T search linked list for FC WWN
423
                                           NULL);       // DON'T care about end of list
424
 
425
        if (pLoggedInPort == NULL)      // not found!
426
        {
427
                result = -ENXIO;
428
        }
429
 
430
        else                    // we know what FC device to operate on...
431
        {
432
                // printk("ioctl CMND %d", Cmnd);
433
                switch (Cmnd) {
434
                        // Passthrough provides a mechanism to bypass the RAID
435
                        // or other controller and talk directly to the devices
436
                        // (e.g. physical disk drive)
437
                        // Passthrough commands, unfortunately, tend to be vendor
438
                        // specific; this is tailored to COMPAQ's RAID (RA4x00)
439
                case CPQFCTS_SCSI_PASSTHRU:
440
                        {
441
                                void *buf = NULL;       // for kernel space buffer for user data
442
 
443
                                if (!arg)
444
                                        return -EINVAL;
445
 
446
                                // must be super user to send stuff directly to the
447
                                // controller and/or physical drives...
448
                                if (!suser())
449
                                        return -EPERM;
450
 
451
                                // copy the caller's struct to our space.
452
                                if (copy_from_user(&ioc, arg, sizeof(VENDOR_IOCTL_REQ)))
453
                                        return (-EFAULT);
454
 
455
                                vendor_cmd = ioc.argp;  // i.e., CPQ specific command struct
456
 
457
                                // If necessary, grab a kernel/DMA buffer
458
                                if (vendor_cmd->len) {
459
                                        buf = kmalloc(vendor_cmd->len, GFP_KERNEL);
460
                                        if (!buf)
461
                                                return -ENOMEM;
462
                                }
463
                                // Now build a SCSI_CMND to pass down...
464
                                // This function allocates and sets Scsi_Cmnd ptrs such as
465
                                //  ->channel, ->target, ->host
466
                                ScsiPassThruCmnd = scsi_allocate_device(ScsiDev, 1, 1);
467
 
468
                                // Need data from user?
469
                                // make sure caller's buffer is in kernel space.
470
                                if ((vendor_cmd->rw_flag == VENDOR_WRITE_OPCODE) && vendor_cmd->len)
471
                                        if (copy_from_user(buf, vendor_cmd->bufp, vendor_cmd->len)) {
472
                                                kfree(buf);
473
                                                return (-EFAULT);
474
                                        }
475
 
476
                                // copy the CDB (if/when MAX_COMMAND_SIZE is 16, remove copy below)
477
                                memcpy(&ScsiPassThruCmnd->cmnd[0], &vendor_cmd->cdb[0], MAX_COMMAND_SIZE);
478
                                // we want to copy all 16 bytes into the FCP-SCSI CDB,
479
                                // although the actual passthru only uses up to the
480
                                // first 12.
481
 
482
                                ScsiPassThruCmnd->cmd_len = 16; // sizeof FCP-SCSI CDB
483
 
484
                                // Unfortunately, the SCSI command cmnd[] field has only
485
                                // 12 bytes.  Ideally the MAX_COMMAND_SIZE should be increased
486
                                // to 16 for newer Fibre Channel and SCSI-3 larger CDBs.
487
                                // However, to avoid a mandatory kernel rebuild, we use the SCp
488
                                // spare field to store the extra 4 bytes ( ugly :-(
489
 
490
                                if (MAX_COMMAND_SIZE < 16) {
491
                                        memcpy(&ScsiPassThruCmnd->SCp.buffers_residual, &vendor_cmd->cdb[12], 4);
492
                                }
493
 
494
 
495
                                ScsiPassThruCmnd->SCp.sent_command = 1; // PASSTHRU!
496
                                // suppress LUN masking
497
                                // and VSA logic
498
 
499
                                // Use spare fields to copy FCP-SCSI LUN address info...
500
                                ScsiPassThruCmnd->SCp.phase = vendor_cmd->bus;
501
                                ScsiPassThruCmnd->SCp.have_data_in = vendor_cmd->pdrive;
502
 
503
                                // We copy the scheme used by scsi.c to submit commands
504
                                // to our own HBA.  We do this in order to stall the
505
                                // thread calling the IOCTL until it completes, and use
506
                                // the same "_quecommand" function for synchronizing
507
                                // FC Link events with our "worker thread".
508
 
509
                                {
510
                                        CPQFC_DECLARE_COMPLETION(wait);
511
                                        ScsiPassThruCmnd->request.CPQFC_WAITING = &wait;
512
                                        // eventually gets us to our own _quecommand routine
513
                                        scsi_do_cmd(ScsiPassThruCmnd, &vendor_cmd->cdb[0], buf, vendor_cmd->len, my_ioctl_done, 10 * HZ, 1);     // timeout,retries
514
                                        // Other I/Os can now resume; we wait for our ioctl
515
                                        // command to complete
516
                                        CPQFC_WAIT_FOR_COMPLETION(&wait);
517
                                        ScsiPassThruCmnd->request.CPQFC_WAITING = NULL;
518
                                }
519
 
520
                                result = ScsiPassThruCmnd->result;
521
 
522
                                // copy any sense data back to caller
523
                                if (result != 0) {
524
                                        memcpy(vendor_cmd->sense_data,  // see struct def - size=40
525
                                               ScsiPassThruCmnd->sense_buffer, sizeof(ScsiPassThruCmnd->sense_buffer));
526
                                }
527
                                SDpnt = ScsiPassThruCmnd->device;
528
                                scsi_release_command(ScsiPassThruCmnd); // "de-allocate"
529
                                ScsiPassThruCmnd = NULL;
530
 
531
                                // if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
532
                                //  (*SDpnt->scsi_request_fn)();
533
 
534
                                wake_up(&SDpnt->scpnt_wait);
535
 
536
                                // need to pass data back to user (space)?
537
                                if ((vendor_cmd->rw_flag == VENDOR_READ_OPCODE) && vendor_cmd->len)
538
                                        if (copy_to_user(vendor_cmd->bufp, buf, vendor_cmd->len))
539
                                                result = -EFAULT;
540
 
541
                                if (buf)
542
                                        kfree(buf);
543
 
544
                                return result;
545
                        }
546
 
547
                case CPQFCTS_GETPCIINFO:
548
                        {
549
                                cpqfc_pci_info_struct pciinfo;
550
 
551
                                if (!arg)
552
                                        return -EINVAL;
553
 
554
 
555
 
556
                                pciinfo.bus = cpqfcHBAdata->PciDev->bus->number;
557
                                pciinfo.dev_fn = cpqfcHBAdata->PciDev->devfn;
558
                                pciinfo.board_id = cpqfcHBAdata->PciDev->device | (cpqfcHBAdata->PciDev->vendor << 16);
559
 
560
                                if (copy_to_user(arg, &pciinfo, sizeof(cpqfc_pci_info_struct)))
561
                                        return (-EFAULT);
562
                                return 0;
563
                        }
564
 
565
                case CPQFCTS_GETDRIVVER:
566
                        {
567
                                DriverVer_type DriverVer = CPQFCTS_DRIVER_VER(VER_MAJOR, VER_MINOR, VER_SUBMINOR);
568
 
569
                                if (!arg)
570
                                        return -EINVAL;
571
 
572
                                if (copy_to_user(arg, &DriverVer, sizeof(DriverVer)))
573
                                        return (-EFAULT);
574
                                return 0;
575
                        }
576
 
577
 
578
 
579
                case CPQFC_IOCTL_FC_TARGET_ADDRESS:
580
                        result = verify_area(VERIFY_WRITE, arg, sizeof(Scsi_FCTargAddress));
581
                        if (result)
582
                                break;
583
 
584
                        put_user(pLoggedInPort->port_id, &((Scsi_FCTargAddress *) arg)->host_port_id);
585
 
586
                        for (i = 3, j = 0; i >= 0; i--)   // copy the LOGIN port's WWN
587
                                put_user(pLoggedInPort->u.ucWWN[i], &((Scsi_FCTargAddress *) arg)->host_wwn[j++]);
588
                        for (i = 7; i > 3; i--) // copy the LOGIN port's WWN
589
                                put_user(pLoggedInPort->u.ucWWN[i], &((Scsi_FCTargAddress *) arg)->host_wwn[j++]);
590
                        break;
591
 
592
 
593
                case CPQFC_IOCTL_FC_TDR:
594
 
595
                        result = cpqfcTS_TargetDeviceReset(ScsiDev, 0);
596
 
597
                        break;
598
 
599
 
600
 
601
 
602
                default:
603
                        result = -EINVAL;
604
                        break;
605
                }
606
        }
607
 
608
        LEAVE("cpqfcTS_ioctl");
609
        return result;
610
}
611
 
612
 
613
/* "Release" the Host Bus Adapter...
614
   disable interrupts, stop the HBA, release the interrupt,
615
   and free all resources */
616
 
617
int cpqfcTS_release(struct Scsi_Host *HostAdapter)
618
{
619
        CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) HostAdapter->hostdata;
620
 
621
 
622
        ENTER("cpqfcTS_release");
623
 
624
        DEBUG_PCI(printk(" cpqfcTS: delete timer...\n"));
625
        del_timer(&cpqfcHBAdata->cpqfcTStimer);
626
 
627
        // disable the hardware...
628
        DEBUG_PCI(printk(" disable hardware, destroy queues, free mem\n"));
629
        cpqfcHBAdata->fcChip.ResetTachyon(cpqfcHBAdata, CLEAR_FCPORTS);
630
 
631
        // kill kernel thread
632
        if (cpqfcHBAdata->worker_thread)        // (only if exists)
633
        {
634
                DECLARE_MUTEX_LOCKED(sem);      // synchronize thread kill
635
 
636
                cpqfcHBAdata->notify_wt = &sem;
637
                DEBUG_PCI(printk(" killing kernel thread\n"));
638
                send_sig(SIGKILL, cpqfcHBAdata->worker_thread, 1);
639
                down(&sem);
640
                cpqfcHBAdata->notify_wt = NULL;
641
 
642
        }
643
        // free Linux resources
644
        DEBUG_PCI(printk(" cpqfcTS: freeing resources...\n"));
645
        free_irq(HostAdapter->irq, HostAdapter);
646
        scsi_unregister(HostAdapter);
647
        release_region(cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff);
648
        release_region(cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff);
649
        /* we get "vfree: bad address" executing this - need to investigate...
650
           if( (void*)((unsigned long)cpqfcHBAdata->fcChip.Registers.MemBase) !=
651
           cpqfcHBAdata->fcChip.Registers.ReMapMemBase)
652
           vfree( cpqfcHBAdata->fcChip.Registers.ReMapMemBase);
653
         */
654
 
655
        LEAVE("cpqfcTS_release");
656
        return 0;
657
}
658
 
659
 
660
const char *cpqfcTS_info(struct Scsi_Host *HostAdapter)
661
{
662
        static char buf[300];
663
        CPQFCHBA *cpqfcHBA;
664
        int BusSpeed, BusWidth;
665
 
666
        // get the pointer to our Scsi layer HBA buffer  
667
        cpqfcHBA = (CPQFCHBA *) HostAdapter->hostdata;
668
 
669
        BusWidth = (cpqfcHBA->fcChip.Registers.PCIMCTR & 0x4) > 0 ? 64 : 32;
670
 
671
        if (cpqfcHBA->fcChip.Registers.TYconfig.value & 0x80000000)
672
                BusSpeed = 66;
673
        else
674
                BusSpeed = 33;
675
 
676
        sprintf(buf,
677
                "%s: WWN %08X%08X\n on PCI bus %d device 0x%02x irq %d IObaseL 0x%x, MEMBASE 0x%x\nPCI bus width %d bits, bus speed %d MHz\nFCP-SCSI Driver v%d.%d.%d",
678
                cpqfcHBA->fcChip.Name,
679
                cpqfcHBA->fcChip.Registers.wwn_hi,
680
                cpqfcHBA->fcChip.Registers.wwn_lo, cpqfcHBA->PciDev->bus->number, cpqfcHBA->PciDev->device, HostAdapter->irq, cpqfcHBA->fcChip.Registers.IOBaseL, cpqfcHBA->fcChip.Registers.MemBase, BusWidth, BusSpeed, VER_MAJOR, VER_MINOR, VER_SUBMINOR);
681
 
682
 
683
        cpqfcTSDecodeGBICtype(&cpqfcHBA->fcChip, &buf[strlen(buf)]);
684
        cpqfcTSGetLPSM(&cpqfcHBA->fcChip, &buf[strlen(buf)]);
685
        return buf;
686
}
687
 
688
//
689
// /proc/scsi support. The following routines allow us to do 'normal'
690
// sprintf like calls to return the currently requested piece (buflenght
691
// chars, starting at bufoffset) of the file. Although procfs allows for
692
// a 1 Kb bytes overflow after te supplied buffer, I consider it bad 
693
// programming to use it to make programming a little simpler. This piece
694
// of coding is borrowed from ncr53c8xx.c with some modifications 
695
//
696
struct info_str {
697
        char *buffer;           // Pointer to output buffer
698
        int buflength;          // It's length
699
        int bufoffset;          // File offset corresponding with buf[0]
700
        int buffillen;          // Current filled length 
701
        int filpos;             // Current file offset
702
};
703
 
704
static void copy_mem_info(struct info_str *info, char *data, int datalen)
705
{
706
 
707
        if (info->filpos < info->bufoffset) {   // Current offset before buffer offset
708
                if (info->filpos + datalen <= info->bufoffset) {
709
                        info->filpos += datalen;        // Discard if completely before buffer
710
                        return;
711
                } else {        // Partial copy, set to begin
712
                        data += (info->bufoffset - info->filpos);
713
                        datalen -= (info->bufoffset - info->filpos);
714
                        info->filpos = info->bufoffset;
715
                }
716
        }
717
 
718
        info->filpos += datalen;        // Update current offset
719
 
720
        if (info->buffillen == info->buflength) // Buffer full, discard
721
                return;
722
 
723
        if (info->buflength - info->buffillen < datalen)        // Overflows buffer ?
724
                datalen = info->buflength - info->buffillen;
725
 
726
        memcpy(info->buffer + info->buffillen, data, datalen);
727
        info->buffillen += datalen;
728
}
729
 
730
static int copy_info(struct info_str *info, char *fmt, ...)
731
{
732
        va_list args;
733
        char buf[400];
734
        int len;
735
 
736
        va_start(args, fmt);
737
        len = vsprintf(buf, fmt, args);
738
        va_end(args);
739
 
740
        copy_mem_info(info, buf, len);
741
        return len;
742
}
743
 
744
 
745
// Routine to get data for /proc RAM filesystem
746
//
747
int cpqfcTS_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout)
748
{
749
        struct Scsi_Host *host;
750
        Scsi_Cmnd DumCmnd;
751
        int Chan, Targ, i;
752
        struct info_str info;
753
        CPQFCHBA *cpqfcHBA;
754
        PTACHYON fcChip;
755
        PFC_LOGGEDIN_PORT pLoggedInPort;
756
        char buf[81];
757
 
758
        // Search the Scsi host list for our controller
759
        for (host = scsi_hostlist; host; host = host->next)
760
                if (host->host_no == hostno)
761
                        break;
762
 
763
        if (!host)
764
                return -ESRCH;
765
 
766
        if (inout)
767
                return -EINVAL;
768
 
769
        // get the pointer to our Scsi layer HBA buffer  
770
        cpqfcHBA = (CPQFCHBA *) host->hostdata;
771
        fcChip = &cpqfcHBA->fcChip;
772
 
773
        *start = buffer;
774
 
775
        info.buffer = buffer;
776
        info.buflength = length;
777
        info.bufoffset = offset;
778
        info.filpos = 0;
779
        info.buffillen = 0;
780
        copy_info(&info, "Driver version = %d.%d.%d", VER_MAJOR, VER_MINOR, VER_SUBMINOR);
781
        cpqfcTSDecodeGBICtype(&cpqfcHBA->fcChip, &buf[0]);
782
        cpqfcTSGetLPSM(&cpqfcHBA->fcChip, &buf[strlen(buf)]);
783
        copy_info(&info, "%s\n", buf);
784
 
785
#define DISPLAY_WWN_INFO
786
#ifdef DISPLAY_WWN_INFO
787
        copy_info(&info, "WWN database: (\"port_id: 000000\" means disconnected)\n");
788
        for (Chan = 0; Chan <= host->max_channel; Chan++) {
789
                DumCmnd.channel = Chan;
790
                for (Targ = 0; Targ <= host->max_id; Targ++) {
791
                        DumCmnd.target = Targ;
792
                        if ((pLoggedInPort = fcFindLoggedInPort(fcChip, &DumCmnd,       // search Scsi Nexus
793
                                                                0,       // DON'T search list for FC port id
794
                                                                NULL,   // DON'T search list for FC WWN
795
                                                                NULL))) {       // DON'T care about end of list
796
                                copy_info(&info, "Host: scsi%d Channel: %02d TargetId: %02d -> WWN: ", hostno, Chan, Targ);
797
                                for (i = 3; i >= 0; i--) // copy the LOGIN port's WWN
798
                                        copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]);
799
                                for (i = 7; i > 3; i--) // copy the LOGIN port's WWN
800
                                        copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]);
801
                                copy_info(&info, " port_id: %06X\n", pLoggedInPort->port_id);
802
                        }
803
                }
804
        }
805
#endif
806
 
807
 
808
 
809
 
810
 
811
// Unfortunately, the proc_info buffer isn't big enough
812
// for everything we would like...
813
// For FC stats, compile this and turn off WWN stuff above  
814
//#define DISPLAY_FC_STATS
815
#ifdef DISPLAY_FC_STATS
816
// get the Fibre Channel statistics
817
        {
818
                int DeltaSecs = (jiffies - cpqfcHBA->fcStatsTime) / HZ;
819
                int days, hours, minutes, secs;
820
 
821
                days = DeltaSecs / (3600 * 24); // days
822
                hours = (DeltaSecs % (3600 * 24)) / 3600;       // hours
823
                minutes = (DeltaSecs % 3600 / 60);      // minutes
824
                secs = DeltaSecs % 60;  // secs
825
                copy_info(&info, "Fibre Channel Stats (time dd:hh:mm:ss %02u:%02u:%02u:%02u\n", days, hours, minutes, secs);
826
        }
827
 
828
        cpqfcHBA->fcStatsTime = jiffies;        // (for next delta)
829
 
830
        copy_info(&info, "  LinkUp           %9u     LinkDown      %u\n", fcChip->fcStats.linkUp, fcChip->fcStats.linkDown);
831
 
832
        copy_info(&info, "  Loss of Signal   %9u     Loss of Sync  %u\n", fcChip->fcStats.LossofSignal, fcChip->fcStats.LossofSync);
833
 
834
        copy_info(&info, "  Discarded Frames %9u     Bad CRC Frame %u\n", fcChip->fcStats.Dis_Frm, fcChip->fcStats.Bad_CRC);
835
 
836
        copy_info(&info, "  TACH LinkFailTX  %9u     TACH LinkFailRX     %u\n", fcChip->fcStats.linkFailTX, fcChip->fcStats.linkFailRX);
837
 
838
        copy_info(&info, "  TACH RxEOFa      %9u     TACH Elastic Store  %u\n", fcChip->fcStats.Rx_EOFa, fcChip->fcStats.e_stores);
839
 
840
        copy_info(&info, "  BufferCreditWait %9uus   TACH FM Inits %u\n", fcChip->fcStats.BB0_Timer * 10, fcChip->fcStats.FMinits);
841
 
842
        copy_info(&info, "  FC-2 Timeouts    %9u     FC-2 Logouts  %u\n", fcChip->fcStats.timeouts, fcChip->fcStats.logouts);
843
 
844
        copy_info(&info, "  FC-2 Aborts      %9u     FC-4 Aborts   %u\n", fcChip->fcStats.FC2aborted, fcChip->fcStats.FC4aborted);
845
 
846
        // clear the counters
847
        cpqfcTSClearLinkStatusCounters(fcChip);
848
#endif
849
 
850
        return info.buffillen;
851
}
852
 
853
 
854
#if DEBUG_CMND
855
 
856
u8 *ScsiToAscii(u8 ScsiCommand)
857
{
858
 
859
/*++
860
 
861
Routine Description:
862
 
863
   Converts a SCSI command to a text string for debugging purposes.
864
 
865
 
866
Arguments:
867
 
868
   ScsiCommand -- hex value SCSI Command
869
 
870
 
871
Return Value:
872
 
873
   An ASCII, null-terminated string if found, else returns NULL.
874
 
875
Original code from M. McGowen, Compaq
876
--*/
877
 
878
 
879
        switch (ScsiCommand) {
880
        case 0x00:
881
                return ("Test Unit Ready");
882
 
883
        case 0x01:
884
                return ("Rezero Unit or Rewind");
885
 
886
        case 0x02:
887
                return ("Request Block Address");
888
 
889
        case 0x03:
890
                return ("Requese Sense");
891
 
892
        case 0x04:
893
                return ("Format Unit");
894
 
895
        case 0x05:
896
                return ("Read Block Limits");
897
 
898
        case 0x07:
899
                return ("Reassign Blocks");
900
 
901
        case 0x08:
902
                return ("Read (6)");
903
 
904
        case 0x0a:
905
                return ("Write (6)");
906
 
907
        case 0x0b:
908
                return ("Seek (6)");
909
 
910
        case 0x12:
911
                return ("Inquiry");
912
 
913
        case 0x15:
914
                return ("Mode Select (6)");
915
 
916
        case 0x16:
917
                return ("Reserve");
918
 
919
        case 0x17:
920
                return ("Release");
921
 
922
        case 0x1a:
923
                return ("ModeSen(6)");
924
 
925
        case 0x1b:
926
                return ("Start/Stop Unit");
927
 
928
        case 0x1c:
929
                return ("Receive Diagnostic Results");
930
 
931
        case 0x1d:
932
                return ("Send Diagnostic");
933
 
934
        case 0x25:
935
                return ("Read Capacity");
936
 
937
        case 0x28:
938
                return ("Read (10)");
939
 
940
        case 0x2a:
941
                return ("Write (10)");
942
 
943
        case 0x2b:
944
                return ("Seek (10)");
945
 
946
        case 0x2e:
947
                return ("Write and Verify");
948
 
949
        case 0x2f:
950
                return ("Verify");
951
 
952
        case 0x34:
953
                return ("Pre-Fetch");
954
 
955
        case 0x35:
956
                return ("Synchronize Cache");
957
 
958
        case 0x37:
959
                return ("Read Defect Data (10)");
960
 
961
        case 0x3b:
962
                return ("Write Buffer");
963
 
964
        case 0x3c:
965
                return ("Read Buffer");
966
 
967
        case 0x3e:
968
                return ("Read Long");
969
 
970
        case 0x3f:
971
                return ("Write Long");
972
 
973
        case 0x41:
974
                return ("Write Same");
975
 
976
        case 0x4c:
977
                return ("Log Select");
978
 
979
        case 0x4d:
980
                return ("Log Sense");
981
 
982
        case 0x56:
983
                return ("Reserve (10)");
984
 
985
        case 0x57:
986
                return ("Release (10)");
987
 
988
        case 0xa0:
989
                return ("ReportLuns");
990
 
991
        case 0xb7:
992
                return ("Read Defect Data (12)");
993
 
994
        case 0xca:
995
                return ("Peripheral Device Addressing SCSI Passthrough");
996
 
997
        case 0xcb:
998
                return ("Compaq Array Firmware Passthrough");
999
 
1000
        default:
1001
                return (NULL);
1002
        }
1003
 
1004
}                               // end ScsiToAscii()
1005
 
1006
void cpqfcTS_print_scsi_cmd(Scsi_Cmnd * cmd)
1007
{
1008
 
1009
        printk("cpqfcTS: (%s) chnl 0x%02x, trgt = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n", ScsiToAscii(cmd->cmnd[0]), cmd->channel, cmd->target, cmd->lun, cmd->cmd_len);
1010
 
1011
        if (cmd->cmnd[0] == 0)    // Test Unit Ready?
1012
        {
1013
                int i;
1014
 
1015
                printk("Cmnd->request_bufflen = 0x%X, ->use_sg = %d, ->bufflen = %d\n", cmd->request_bufflen, cmd->use_sg, cmd->bufflen);
1016
                printk("Cmnd->request_buffer = %p, ->sglist_len = %d, ->buffer = %p\n", cmd->request_buffer, cmd->sglist_len, cmd->buffer);
1017
                for (i = 0; i < cmd->cmd_len; i++)
1018
                        printk("0x%02x ", cmd->cmnd[i]);
1019
                printk("\n");
1020
        }
1021
 
1022
}
1023
 
1024
#endif                          /* DEBUG_CMND */
1025
 
1026
 
1027
 
1028
 
1029
static void QueCmndOnBoardLock(CPQFCHBA * cpqfcHBAdata, Scsi_Cmnd * Cmnd)
1030
{
1031
        int i;
1032
 
1033
        for (i = 0; i < CPQFCTS_REQ_QUEUE_LEN; i++) {    // find spare slot
1034
                if (cpqfcHBAdata->BoardLockCmnd[i] == NULL) {
1035
                        cpqfcHBAdata->BoardLockCmnd[i] = Cmnd;
1036
//      printk(" BoardLockCmnd[%d] %p Queued, chnl/target/lun %d/%d/%d\n",
1037
//        i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
1038
                        break;
1039
                }
1040
        }
1041
        if (i >= CPQFCTS_REQ_QUEUE_LEN) {
1042
                printk(" cpqfcTS WARNING: Lost Cmnd %p on BoardLock Q full!", Cmnd);
1043
        }
1044
 
1045
}
1046
 
1047
 
1048
static void QueLinkDownCmnd(CPQFCHBA * cpqfcHBAdata, Scsi_Cmnd * Cmnd)
1049
{
1050
        int indx;
1051
 
1052
        // Remember the command ptr so we can return; we'll complete when
1053
        // the device comes back, causing immediate retry
1054
        for (indx = 0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++)     //, SCptr++)
1055
        {
1056
                if (cpqfcHBAdata->LinkDnCmnd[indx] == NULL)     // available?
1057
                {
1058
#ifdef DUMMYCMND_DBG
1059
                        printk(" @add Cmnd %p to LnkDnCmnd[%d]@ ", Cmnd, indx);
1060
#endif
1061
                        cpqfcHBAdata->LinkDnCmnd[indx] = Cmnd;
1062
                        break;
1063
                }
1064
        }
1065
 
1066
        if (indx >= CPQFCTS_REQ_QUEUE_LEN)      // no space for Cmnd??
1067
        {
1068
                // this will result in an _abort call later (with possible trouble)
1069
                printk("no buffer for LinkDnCmnd!! %p\n", Cmnd);
1070
        }
1071
}
1072
 
1073
 
1074
 
1075
 
1076
 
1077
// The file "hosts.h" says not to call scsi_done from
1078
// inside _queuecommand, so we'll do it from the heartbeat timer
1079
// (clarification: Turns out it's ok to call scsi_done from queuecommand 
1080
// for cases that don't go to the hardware like scsi cmds destined
1081
// for LUNs we know don't exist, so this code might be simplified...)
1082
 
1083
static void QueBadTargetCmnd(CPQFCHBA * cpqfcHBAdata, Scsi_Cmnd * Cmnd)
1084
{
1085
        int i;
1086
        //    printk(" can't find target %d\n", Cmnd->target);
1087
 
1088
        for (i = 0; i < CPQFCTS_MAX_TARGET_ID; i++) {    // find spare slot
1089
                if (cpqfcHBAdata->BadTargetCmnd[i] == NULL) {
1090
                        cpqfcHBAdata->BadTargetCmnd[i] = Cmnd;
1091
//      printk(" BadTargetCmnd[%d] %p Queued, chnl/target/lun %d/%d/%d\n",
1092
//          i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
1093
                        break;
1094
                }
1095
        }
1096
}
1097
 
1098
 
1099
// This is the "main" entry point for Linux Scsi commands --
1100
// it all starts here.
1101
 
1102
int cpqfcTS_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *))
1103
{
1104
        struct Scsi_Host *HostAdapter = Cmnd->host;
1105
        CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) HostAdapter->hostdata;
1106
        PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1107
        TachFCHDR_GCMND fchs;   // only use for FC destination id field  
1108
        PFC_LOGGEDIN_PORT pLoggedInPort;
1109
        u32 ulStatus, SESTtype;
1110
        s32 ExchangeID;
1111
 
1112
 
1113
 
1114
 
1115
        ENTER("cpqfcTS_queuecommand");
1116
 
1117
        PCI_TRACEO((u32) Cmnd, 0x98)
1118
 
1119
 
1120
            Cmnd->scsi_done = done;
1121
#ifdef DEBUG_CMND
1122
        cpqfcTS_print_scsi_cmd(Cmnd);
1123
#endif
1124
 
1125
        // prevent board contention with kernel thread...  
1126
 
1127
        if (cpqfcHBAdata->BoardLock) {
1128
//    printk(" @BrdLck Hld@ ");
1129
                QueCmndOnBoardLock(cpqfcHBAdata, Cmnd);
1130
        }
1131
 
1132
        else {
1133
 
1134
                // in the current system (2.2.12), this routine is called
1135
                // after spin_lock_irqsave(), so INTs are disabled. However,
1136
                // we might have something pending in the LinkQ, which
1137
                // might cause the WorkerTask to run.  In case that
1138
                // happens, make sure we lock it out.
1139
 
1140
 
1141
 
1142
                PCI_TRACE(0x98)
1143
                    CPQ_SPINLOCK_HBA(cpqfcHBAdata)
1144
                    PCI_TRACE(0x98)
1145
                    // can we find an FC device mapping to this SCSI target?
1146
                    pLoggedInPort = fcFindLoggedInPort(fcChip, Cmnd,    // search Scsi Nexus
1147
                                                       0,        // DON'T search linked list for FC port id
1148
                                                       NULL,    // DON'T search linked list for FC WWN
1149
                                                       NULL);   // DON'T care about end of list
1150
 
1151
                if (pLoggedInPort == NULL)      // not found!
1152
                {
1153
//    printk(" @Q bad targ cmnd %p@ ", Cmnd);
1154
                        QueBadTargetCmnd(cpqfcHBAdata, Cmnd);
1155
                } else if (Cmnd->lun >= CPQFCTS_MAX_LUN) {
1156
                        printk(KERN_WARNING "cpqfc: Invalid LUN: %d\n", Cmnd->lun);
1157
                        QueBadTargetCmnd(cpqfcHBAdata, Cmnd);
1158
                }
1159
 
1160
                else            // we know what FC device to send to...
1161
                {
1162
 
1163
                        // does this device support FCP target functions?
1164
                        // (determined by PRLI field)
1165
 
1166
                        if (!(pLoggedInPort->fcp_info & TARGET_FUNCTION)) {
1167
                                printk(" Doesn't support TARGET functions port_id %Xh\n", pLoggedInPort->port_id);
1168
                                QueBadTargetCmnd(cpqfcHBAdata, Cmnd);
1169
                        }
1170
                        // In this case (previous login OK), the device is temporarily
1171
                        // unavailable waiting for re-login, in which case we expect it
1172
                        // to be back in between 25 - 500ms.  
1173
                        // If the FC port doesn't log back in within several seconds
1174
                        // (i.e. implicit "logout"), or we get an explicit logout,
1175
                        // we set "device_blocked" in Scsi_Device struct; in this
1176
                        // case 30 seconds will elapse before Linux/Scsi sends another
1177
                        // command to the device.
1178
                        else if (pLoggedInPort->prli != TRUE) {
1179
//      printk("Device (Chnl/Target %d/%d) invalid PRLI, port_id %06lXh\n",
1180
//        Cmnd->channel, Cmnd->target, pLoggedInPort->port_id);
1181
                                QueLinkDownCmnd(cpqfcHBAdata, Cmnd);
1182
//    Need to use "blocked" flag??      
1183
//      Cmnd->device->device_blocked = TRUE; // just let it timeout
1184
                        } else  // device supports TARGET functions, and is logged in...
1185
                        {
1186
                                // (context of fchs is to "reply" to...)
1187
                                fchs.s_id = pLoggedInPort->port_id;     // destination FC address
1188
 
1189
                                // what is the data direction?  For data TO the device,
1190
                                // we need IWE (Intiator Write Entry).  Otherwise, IRE.
1191
 
1192
                                if (Cmnd->cmnd[0] == WRITE_10 || Cmnd->cmnd[0] == WRITE_6 || Cmnd->cmnd[0] == WRITE_BUFFER || Cmnd->cmnd[0] == VENDOR_WRITE_OPCODE ||       // CPQ specific 
1193
                                    Cmnd->cmnd[0] == MODE_SELECT) {
1194
                                        SESTtype = SCSI_IWE;    // data from HBA to Device
1195
                                } else
1196
                                        SESTtype = SCSI_IRE;    // data from Device to HBA
1197
 
1198
                                ulStatus = cpqfcTSBuildExchange(cpqfcHBAdata, SESTtype, // e.g. Initiator Read Entry (IRE)
1199
                                                                &fchs,  // we are originator; only use d_id
1200
                                                                Cmnd,   // Linux SCSI command (with scatter/gather list)
1201
                                                                &ExchangeID);   // fcController->fcExchanges index, -1 if failed
1202
 
1203
                                if (!ulStatus)  // Exchange setup?
1204
 
1205
                                {
1206
                                        if (cpqfcHBAdata->BoardLock) {
1207
                                                TriggerHBA(fcChip->Registers.ReMapMemBase, 0);
1208
                                                printk(" @bl! %d, xID %Xh@ ", current->pid, ExchangeID);
1209
                                        }
1210
 
1211
                                        ulStatus = cpqfcTSStartExchange(cpqfcHBAdata, ExchangeID);
1212
                                        if (!ulStatus) {
1213
                                                PCI_TRACEO(ExchangeID, 0xB8)
1214
                                                    // submitted to Tach's Outbound Que (ERQ PI incremented)
1215
                                                    // waited for completion for ELS type (Login frames issued
1216
                                                    // synchronously)
1217
                                        } else
1218
                                                // check reason for Exchange not being started - we might
1219
                                                // want to Queue and start later, or fail with error
1220
                                        {
1221
                                                printk("quecommand: cpqfcTSStartExchange failed: %Xh\n", ulStatus);
1222
                                        }
1223
                                }       // end good BuildExchange status
1224
 
1225
                                else    // SEST table probably full  -- why? hardware hang?
1226
                                {
1227
                                        printk("quecommand: cpqfcTSBuildExchange faild: %Xh\n", ulStatus);
1228
                                }
1229
                        }       // end can't do FCP-SCSI target functions
1230
                }               // end can't find target (FC device)
1231
 
1232
                CPQ_SPINUNLOCK_HBA(cpqfcHBAdata)
1233
        }
1234
 
1235
        PCI_TRACEO((u32) Cmnd, 0x9C)
1236
            LEAVE("cpqfcTS_queuecommand");
1237
        return 0;
1238
}
1239
 
1240
 
1241
// Entry point for upper Scsi layer intiated abort.  Typically
1242
// this is called if the command (for hard disk) fails to complete
1243
// in 30 seconds.  This driver intends to complete all disk commands
1244
// within Exchange ".timeOut" seconds (now 7) with target status, or
1245
// in case of ".timeOut" expiration, a DID_SOFT_ERROR which causes
1246
// immediate retry.
1247
// If any disk commands get the _abort call, except for the case that
1248
// the physical device was removed or unavailable due to hardware
1249
// errors, it should be considered a driver error and reported to
1250
// the author.
1251
 
1252
int cpqfcTS_abort(Scsi_Cmnd * Cmnd)
1253
{
1254
//      printk(" cpqfcTS_abort called?? \n");
1255
        return 0;
1256
}
1257
 
1258
int cpqfcTS_eh_abort(Scsi_Cmnd * Cmnd)
1259
{
1260
 
1261
        struct Scsi_Host *HostAdapter = Cmnd->host;
1262
        // get the pointer to our Scsi layer HBA buffer  
1263
        CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) HostAdapter->hostdata;
1264
        PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1265
        FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1266
        int i;
1267
        ENTER("cpqfcTS_eh_abort");
1268
 
1269
        Cmnd->result = DID_ABORT << 16; // assume we'll find it
1270
 
1271
        printk(" @Linux _abort Scsi_Cmnd %p ", Cmnd);
1272
        // See if we can find a Cmnd pointer that matches...
1273
        // The most likely case is we accepted the command
1274
        // from Linux Scsi (e.g. ceated a SEST entry) and it
1275
        // got lost somehow.  If we can't find any reference
1276
        // to the passed pointer, we can only presume it
1277
        // got completed as far as our driver is concerned.
1278
        // If we found it, we will try to abort it through
1279
        // common mechanism.  If FC ABTS is successful (ACC)
1280
        // or is rejected (RJT) by target, we will call
1281
        // Scsi "done" quickly.  Otherwise, the ABTS will timeout
1282
        // and we'll call "done" later.
1283
 
1284
        // Search the SEST exchanges for a matching Cmnd ptr.
1285
        for (i = 0; i < TACH_SEST_LEN; i++) {
1286
                if (Exchanges->fcExchange[i].Cmnd == Cmnd) {
1287
 
1288
                        // found it!
1289
                        printk(" x_ID %Xh, type %Xh\n", i, Exchanges->fcExchange[i].type);
1290
 
1291
                        Exchanges->fcExchange[i].status = INITIATOR_ABORT;      // seconds default
1292
                        Exchanges->fcExchange[i].timeOut = 10;  // seconds default (changed later)
1293
 
1294
                        // Since we need to immediately return the aborted Cmnd to Scsi 
1295
                        // upper layers, we can't make future reference to any of it's 
1296
                        // fields (e.g the Nexus).
1297
 
1298
                        cpqfcTSPutLinkQue(cpqfcHBAdata, BLS_ABTS, &i);
1299
 
1300
                        break;
1301
                }
1302
        }
1303
 
1304
        if (i >= TACH_SEST_LEN) // didn't find Cmnd ptr in chip's SEST?
1305
        {
1306
                // now search our non-SEST buffers (i.e. Cmnd waiting to
1307
                // start on the HBA or waiting to complete with error for retry).
1308
 
1309
                // first check BadTargetCmnd
1310
                for (i = 0; i < CPQFCTS_MAX_TARGET_ID; i++) {
1311
                        if (cpqfcHBAdata->BadTargetCmnd[i] == Cmnd) {
1312
                                cpqfcHBAdata->BadTargetCmnd[i] = NULL;
1313
                                printk("in BadTargetCmnd Q\n");
1314
                                goto Done;      // exit
1315
                        }
1316
                }
1317
 
1318
                // if not found above...
1319
 
1320
                for (i = 0; i < CPQFCTS_REQ_QUEUE_LEN; i++) {
1321
                        if (cpqfcHBAdata->LinkDnCmnd[i] == Cmnd) {
1322
                                cpqfcHBAdata->LinkDnCmnd[i] = NULL;
1323
                                printk("in LinkDnCmnd Q\n");
1324
                                goto Done;
1325
                        }
1326
                }
1327
 
1328
 
1329
                for (i = 0; i < CPQFCTS_REQ_QUEUE_LEN; i++) {    // find spare slot
1330
                        if (cpqfcHBAdata->BoardLockCmnd[i] == Cmnd) {
1331
                                cpqfcHBAdata->BoardLockCmnd[i] = NULL;
1332
                                printk("in BoardLockCmnd Q\n");
1333
                                goto Done;
1334
                        }
1335
                }
1336
 
1337
                Cmnd->result = DID_ERROR << 16; // Hmmm...
1338
                printk("Not found! ");
1339
//    panic("_abort");
1340
        }
1341
 
1342
      Done:
1343
 
1344
//    panic("_abort");
1345
        LEAVE("cpqfcTS_eh_abort");
1346
        return 0;                // (see scsi.h)
1347
}
1348
 
1349
 
1350
// FCP-SCSI Target Device Reset
1351
// See dpANS Fibre Channel Protocol for SCSI
1352
// X3.269-199X revision 12, pg 25
1353
 
1354
int cpqfcTS_TargetDeviceReset(Scsi_Device * ScsiDev, unsigned int reset_flags)
1355
{
1356
        int timeout = 10 * HZ;
1357
        int retries = 1;
1358
        char scsi_cdb[12];
1359
        int result;
1360
        Scsi_Cmnd *SCpnt;
1361
        Scsi_Device *SDpnt;
1362
 
1363
 
1364
        // printk("   ENTERING cpqfcTS_TargetDeviceReset() - flag=%d \n",reset_flags);
1365
 
1366
        if (ScsiDev->host->eh_active)
1367
                return FAILED;
1368
 
1369
        memset(scsi_cdb, 0, sizeof(scsi_cdb));
1370
 
1371
        scsi_cdb[0] = RELEASE;
1372
 
1373
        // allocate with wait = true, interruptible = false 
1374
        SCpnt = scsi_allocate_device(ScsiDev, 1, 0);
1375
        {
1376
                CPQFC_DECLARE_COMPLETION(wait);
1377
 
1378
                SCpnt->SCp.buffers_residual = FCP_TARGET_RESET;
1379
 
1380
                SCpnt->request.CPQFC_WAITING = &wait;
1381
                scsi_do_cmd(SCpnt, scsi_cdb, NULL, 0, my_ioctl_done, timeout, retries);
1382
                CPQFC_WAIT_FOR_COMPLETION(&wait);
1383
                SCpnt->request.CPQFC_WAITING = NULL;
1384
        }
1385
 
1386
/*
1387
      if(driver_byte(SCpnt->result) != 0)
1388
          switch(SCpnt->sense_buffer[2] & 0xf) {
1389
        case ILLEGAL_REQUEST:
1390
            if(cmd[0] == ALLOW_MEDIUM_REMOVAL) dev->lockable = 0;
1391
            else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n");
1392
            break;
1393
        case NOT_READY: // This happens if there is no disc in drive
1394
            if(dev->removable && (cmd[0] != TEST_UNIT_READY)){
1395
                printk(KERN_INFO "Device not ready.  Make sure there is a disc in the drive.\n");
1396
                break;
1397
            }
1398
        case UNIT_ATTENTION:
1399
            if (dev->removable){
1400
                dev->changed = 1;
1401
                SCpnt->result = 0; // This is no longer considered an error
1402
                // gag this error, VFS will log it anyway /axboe
1403
                // printk(KERN_INFO "Disc change detected.\n");
1404
                break;
1405
            };
1406
        default: // Fall through for non-removable media
1407
            printk("SCSI error: host %d id %d lun %d return code = %x\n",
1408
                   dev->host->host_no,
1409
                   dev->id,
1410
                   dev->lun,
1411
                   SCpnt->result);
1412
            printk("\tSense class %x, sense error %x, extended sense %x\n",
1413
                   sense_class(SCpnt->sense_buffer[0]),
1414
                   sense_error(SCpnt->sense_buffer[0]),
1415
                   SCpnt->sense_buffer[2] & 0xf);
1416
 
1417
      };
1418
*/
1419
        result = SCpnt->result;
1420
 
1421
        SDpnt = SCpnt->device;
1422
        scsi_release_command(SCpnt);
1423
        SCpnt = NULL;
1424
 
1425
        // if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
1426
        //    (*SDpnt->scsi_request_fn)();
1427
 
1428
        wake_up(&SDpnt->scpnt_wait);
1429
        // printk("   LEAVING cpqfcTS_TargetDeviceReset() - return SUCCESS \n");
1430
        return SUCCESS;
1431
}
1432
 
1433
 
1434
int cpqfcTS_eh_device_reset(Scsi_Cmnd * Cmnd)
1435
{
1436
        int retval;
1437
        Scsi_Device *SDpnt = Cmnd->device;
1438
        // printk("   ENTERING cpqfcTS_eh_device_reset() \n");
1439
        spin_unlock_irq(&io_request_lock);
1440
        retval = cpqfcTS_TargetDeviceReset(SDpnt, 0);
1441
        spin_lock_irq(&io_request_lock);
1442
        return retval;
1443
}
1444
 
1445
 
1446
int cpqfcTS_reset(Scsi_Cmnd * Cmnd, unsigned int reset_flags)
1447
{
1448
 
1449
        ENTER("cpqfcTS_reset");
1450
 
1451
        LEAVE("cpqfcTS_reset");
1452
        return SCSI_RESET_ERROR;        /* Bus Reset Not supported */
1453
}
1454
 
1455
/* This function determines the bios parameters for a given
1456
   harddisk. These tend to be numbers that are made up by the
1457
   host adapter.  Parameters:
1458
   size, device number, list (heads, sectors,cylinders).
1459
   (from hosts.h)
1460
*/
1461
 
1462
int cpqfcTS_biosparam(Disk * disk, kdev_t n, int ip[])
1463
{
1464
        int size = disk->capacity;
1465
 
1466
        ENTER("cpqfcTS_biosparam");
1467
        ip[0] = 64;
1468
        ip[1] = 32;
1469
        ip[2] = size >> 11;
1470
 
1471
        if (ip[2] > 1024) {
1472
                ip[0] = 255;
1473
                ip[1] = 63;
1474
                ip[2] = size / (ip[0] * ip[1]);
1475
        }
1476
 
1477
        LEAVE("cpqfcTS_biosparam");
1478
        return 0;
1479
}
1480
 
1481
 
1482
 
1483
void cpqfcTS_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
1484
{
1485
 
1486
        unsigned long flags, InfLoopBrk = 0;
1487
        struct Scsi_Host *HostAdapter = dev_id;
1488
        CPQFCHBA *cpqfcHBA = (CPQFCHBA *) HostAdapter->hostdata;
1489
        int MoreMessages = 1;   // assume we have something to do
1490
        u8 IntPending;
1491
 
1492
        ENTER("intr_handler");
1493
 
1494
        spin_lock_irqsave(&io_request_lock, flags);
1495
        // is this our INT?
1496
        IntPending = readb(cpqfcHBA->fcChip.Registers.INTPEND.address);
1497
 
1498
        // broken boards can generate messages forever, so
1499
        // prevent the infinite loop
1500
#define INFINITE_IMQ_BREAK 10000
1501
        if (IntPending) {
1502
 
1503
                // mask our HBA interrupts until we handle it...
1504
                writeb(0, cpqfcHBA->fcChip.Registers.INTEN.address);
1505
 
1506
                if (IntPending & 0x4)   // "INT" - Tach wrote to IMQ
1507
                {
1508
                        while ((++InfLoopBrk < INFINITE_IMQ_BREAK) && (MoreMessages == 1)) {
1509
                                MoreMessages = CpqTsProcessIMQEntry(HostAdapter);       // ret 0 when done
1510
                        }
1511
                        if (InfLoopBrk >= INFINITE_IMQ_BREAK) {
1512
                                printk("WARNING: Compaq FC adapter generating excessive INTs -REPLACE\n");
1513
                                printk("or investigate alternate causes (e.g. physical FC layer)\n");
1514
                        }
1515
 
1516
                        else    // working normally - re-enable INTs and continue
1517
                                writeb(0x1F, cpqfcHBA->fcChip.Registers.INTEN.address);
1518
 
1519
                }               // (...ProcessIMQEntry() clears INT by writing IMQ consumer)
1520
                else            // indications of errors or problems...
1521
                        // these usually indicate critical system hardware problems.
1522
                {
1523
                        if (IntPending & 0x10)
1524
                                printk(" cpqfcTS adapter external memory parity error detected\n");
1525
                        if (IntPending & 0x8)
1526
                                printk(" cpqfcTS adapter PCI master address crossed 45-bit boundary\n");
1527
                        if (IntPending & 0x2)
1528
                                printk(" cpqfcTS adapter DMA error detected\n");
1529
                        if (IntPending & 0x1) {
1530
                                u8 IntStat;
1531
                                printk(" cpqfcTS adapter PCI error detected\n");
1532
                                IntStat = readb(cpqfcHBA->fcChip.Registers.INTSTAT.address);
1533
                                if (IntStat & 0x4)
1534
                                        printk("(INT)\n");
1535
                                if (IntStat & 0x8)
1536
                                        printk("CRS: PCI master address crossed 46 bit bouandary\n");
1537
                                if (IntStat & 0x10)
1538
                                        printk("MRE: external memory parity error.\n");
1539
                        }
1540
                }
1541
        }
1542
        spin_unlock_irqrestore(&io_request_lock, flags);
1543
        LEAVE("intr_handler");
1544
}
1545
 
1546
 
1547
 
1548
 
1549
int cpqfcTSDecodeGBICtype(PTACHYON fcChip, char cErrorString[])
1550
{
1551
        // Verify GBIC type (if any) and correct Tachyon Port State Machine
1552
        // (GBIC) module definition is:
1553
        // GPIO1, GPIO0, GPIO4 for MD2, MD1, MD0.  The input states appear
1554
        // to be inverted -- i.e., a setting of 111 is read when there is NO
1555
        // GBIC present.  The Module Def (MD) spec says 000 is "no GBIC"
1556
        // Hard code the bit states to detect Copper, 
1557
        // Long wave (single mode), Short wave (multi-mode), and absent GBIC
1558
 
1559
        u32 ulBuff;
1560
 
1561
        sprintf(cErrorString, "\nGBIC detected: ");
1562
 
1563
        ulBuff = fcChip->Registers.TYstatus.value & 0x13;
1564
        switch (ulBuff) {
1565
        case 0x13:              // GPIO4, GPIO1, GPIO0 = 111; no GBIC!
1566
                sprintf(&cErrorString[strlen(cErrorString)], "NONE! ");
1567
                return FALSE;
1568
 
1569
 
1570
        case 0x11:              // Copper GBIC detected
1571
                sprintf(&cErrorString[strlen(cErrorString)], "Copper. ");
1572
                break;
1573
 
1574
        case 0x10:              // Long-wave (single mode) GBIC detected
1575
                sprintf(&cErrorString[strlen(cErrorString)], "Long-wave. ");
1576
                break;
1577
        case 0x1:               // Short-wave (multi mode) GBIC detected
1578
                sprintf(&cErrorString[strlen(cErrorString)], "Short-wave. ");
1579
                break;
1580
        default:                // unknown GBIC - presumably it will work (?)
1581
                sprintf(&cErrorString[strlen(cErrorString)], "Unknown. ");
1582
 
1583
                break;
1584
        }                       // end switch GBIC detection
1585
 
1586
        return TRUE;
1587
}
1588
 
1589
 
1590
 
1591
 
1592
 
1593
 
1594
int cpqfcTSGetLPSM(PTACHYON fcChip, char cErrorString[])
1595
{
1596
        // Tachyon's Frame Manager LPSM in LinkDown state?
1597
        // (For non-loop port, check PSM instead.)
1598
        // return string with state and FALSE is Link Down
1599
 
1600
        int LinkUp;
1601
 
1602
        if (fcChip->Registers.FMstatus.value & 0x80)
1603
                LinkUp = FALSE;
1604
        else
1605
                LinkUp = TRUE;
1606
 
1607
        sprintf(&cErrorString[strlen(cErrorString)], " LPSM %Xh ", (fcChip->Registers.FMstatus.value >> 4) & 0xf);
1608
 
1609
 
1610
        switch (fcChip->Registers.FMstatus.value & 0xF0) {
1611
                // bits set in LPSM
1612
        case 0x10:
1613
                sprintf(&cErrorString[strlen(cErrorString)], "ARB");
1614
                break;
1615
        case 0x20:
1616
                sprintf(&cErrorString[strlen(cErrorString)], "ARBwon");
1617
                break;
1618
        case 0x30:
1619
                sprintf(&cErrorString[strlen(cErrorString)], "OPEN");
1620
                break;
1621
        case 0x40:
1622
                sprintf(&cErrorString[strlen(cErrorString)], "OPENed");
1623
                break;
1624
        case 0x50:
1625
                sprintf(&cErrorString[strlen(cErrorString)], "XmitCLS");
1626
                break;
1627
        case 0x60:
1628
                sprintf(&cErrorString[strlen(cErrorString)], "RxCLS");
1629
                break;
1630
        case 0x70:
1631
                sprintf(&cErrorString[strlen(cErrorString)], "Xfer");
1632
                break;
1633
        case 0x80:
1634
                sprintf(&cErrorString[strlen(cErrorString)], "Init");
1635
                break;
1636
        case 0x90:
1637
                sprintf(&cErrorString[strlen(cErrorString)], "O-IInitFin");
1638
                break;
1639
        case 0xa0:
1640
                sprintf(&cErrorString[strlen(cErrorString)], "O-IProtocol");
1641
                break;
1642
        case 0xb0:
1643
                sprintf(&cErrorString[strlen(cErrorString)], "O-ILipRcvd");
1644
                break;
1645
        case 0xc0:
1646
                sprintf(&cErrorString[strlen(cErrorString)], "HostControl");
1647
                break;
1648
        case 0xd0:
1649
                sprintf(&cErrorString[strlen(cErrorString)], "LoopFail");
1650
                break;
1651
        case 0xe0:
1652
                sprintf(&cErrorString[strlen(cErrorString)], "Offline");
1653
                break;
1654
        case 0xf0:
1655
                sprintf(&cErrorString[strlen(cErrorString)], "OldPort");
1656
                break;
1657
        case 0:
1658
        default:
1659
                sprintf(&cErrorString[strlen(cErrorString)], "Monitor");
1660
                break;
1661
 
1662
        }
1663
 
1664
        return LinkUp;
1665
}
1666
 
1667
// Dynamic memory allocation alignment routines
1668
// HP's Tachyon Fibre Channel Controller chips require
1669
// certain memory queues and register pointers to be aligned
1670
// on various boundaries, usually the size of the Queue in question.
1671
// Alignment might be on 2, 4, 8, ... or even 512 byte boundaries.
1672
// Since most O/Ss don't allow this (usually only Cache aligned -
1673
// 32-byte boundary), these routines provide generic alignment (after
1674
// O/S allocation) at any boundary, and store the original allocated
1675
// pointer for deletion (O/S free function).  Typically, we expect
1676
// these functions to only be called at HBA initialization and
1677
// removal time (load and unload times)
1678
// ALGORITHM notes:
1679
// Memory allocation varies by compiler and platform.  In the worst case,
1680
// we are only assured BYTE alignment, but in the best case, we can
1681
// request allocation on any desired boundary.  Our strategy: pad the
1682
// allocation request size (i.e. waste memory) so that we are assured
1683
// of passing desired boundary near beginning of contiguous space, then
1684
// mask out lower address bits.
1685
// We define the following algorithm:
1686
//   allocBoundary - compiler/platform specific address alignment
1687
//                   in number of bytes (default is single byte; i.e. 1)
1688
//   n_alloc       - number of bytes application wants @ aligned address
1689
//   ab            - alignment boundary, in bytes (e.g. 4, 32, ...)
1690
//   t_alloc       - total allocation needed to ensure desired boundary
1691
//   mask          - to clear least significant address bits for boundary
1692
//   Compute:
1693
//   t_alloc = n_alloc + (ab - allocBoundary)
1694
//   allocate t_alloc bytes @ alloc_address
1695
//   mask =  NOT (ab - 1)
1696
//       (e.g. if ab=32  _0001 1111  -> _1110 0000
1697
//   aligned_address = alloc_address & mask
1698
//   set n_alloc bytes to 0
1699
//   return aligned_address (NULL if failed)
1700
//
1701
// If u32_AlignedAddress is non-zero, then search for BaseAddress (stored
1702
// from previous allocation).  If found, invoke call to FREE the memory.
1703
// Return NULL if BaseAddress not found
1704
 
1705
// we need about 8 allocations per HBA.  Figuring at most 10 HBAs per server
1706
// size the dynamic_mem array at 80.
1707
 
1708
void *fcMemManager(struct pci_dev *pdev, ALIGNED_MEM * dynamic_mem, u32 n_alloc, u32 ab, u32 u32_AlignedAddress, dma_addr_t * dma_handle)
1709
{
1710
        u16 allocBoundary = 1;  // compiler specific - worst case 1
1711
        // best case - replace malloc() call
1712
        // with function that allocates exactly
1713
        // at desired boundary
1714
 
1715
        unsigned long ulAddress;
1716
        u32 t_alloc, i;
1717
        void *alloc_address = 0; // def. error code / address not found
1718
        s32 mask;               // must be 32-bits wide!
1719
 
1720
        ENTER("fcMemManager");
1721
        if (u32_AlignedAddress) // are we freeing existing memory?
1722
        {
1723
//    printk(" freeing AlignedAddress %Xh\n", u32_AlignedAddress);
1724
                for (i = 0; i < DYNAMIC_ALLOCATIONS; i++)        // look for the base address
1725
                {
1726
//    printk("dynamic_mem[%u].AlignedAddress %lX\n", i, dynamic_mem[i].AlignedAddress);
1727
                        if (dynamic_mem[i].AlignedAddress == u32_AlignedAddress) {
1728
                                alloc_address = dynamic_mem[i].BaseAllocated;   // 'success' status
1729
                                pci_free_consistent(pdev, dynamic_mem[i].size, alloc_address, dynamic_mem[i].dma_handle);
1730
                                dynamic_mem[i].BaseAllocated = 0;        // clear for next use
1731
                                dynamic_mem[i].AlignedAddress = 0;
1732
                                dynamic_mem[i].size = 0;
1733
                                break;  // quit for loop; done
1734
                        }
1735
                }
1736
        } else if (n_alloc)     // want new memory?
1737
        {
1738
                dma_addr_t handle;
1739
                t_alloc = n_alloc + (ab - allocBoundary);       // pad bytes for alignment
1740
//    printk("pci_alloc_consistent() for Tach alignment: %ld bytes\n", t_alloc);
1741
 
1742
// (would like to) allow thread block to free pages 
1743
                alloc_address = // total bytes (NumberOfBytes)
1744
                    pci_alloc_consistent(pdev, t_alloc, &handle);
1745
 
1746
                // now mask off least sig. bits of address
1747
                if (alloc_address)      // (only if non-NULL)
1748
                {
1749
                        // find place to store ptr, so we
1750
                        // can free it later...
1751
 
1752
                        mask = (s32) (ab - 1);  // mask all low-order bits
1753
                        mask = ~mask;   // invert bits
1754
                        for (i = 0; i < DYNAMIC_ALLOCATIONS; i++)        // look for free slot
1755
                        {
1756
                                if (dynamic_mem[i].BaseAllocated == 0)   // take 1st available
1757
                                {
1758
                                        dynamic_mem[i].BaseAllocated = alloc_address;   // address from O/S
1759
                                        dynamic_mem[i].dma_handle = handle;
1760
                                        if (dma_handle != NULL) {
1761
//             printk("handle = %p, ab=%d, boundary = %d, mask=0x%08x\n", 
1762
//                      handle, ab, allocBoundary, mask);
1763
                                                *dma_handle = (dma_addr_t)
1764
                                                    ((((u32) handle) + (ab - allocBoundary)) & mask);
1765
                                        }
1766
                                        dynamic_mem[i].size = t_alloc;
1767
                                        break;
1768
                                }
1769
                        }
1770
                        ulAddress = (unsigned long) alloc_address;
1771
 
1772
                        ulAddress += (ab - allocBoundary);      // add the alignment bytes-
1773
                        // then truncate address...
1774
                        alloc_address = (void *) (ulAddress & mask);
1775
 
1776
                        dynamic_mem[i].AlignedAddress = (u32) (ulAddress & mask);       // 32bit Tach address
1777
                        memset(alloc_address, 0, n_alloc);       // clear new memory
1778
                } else          // O/S dynamic mem alloc failed!
1779
                        alloc_address = 0;       // (for debugging breakpt)
1780
 
1781
        }
1782
 
1783
        LEAVE("fcMemManager");
1784
        return alloc_address;   // good (or NULL) address
1785
}
1786
 
1787
 
1788
static Scsi_Host_Template driver_template = CPQFCTS;
1789
 
1790
#include "scsi_module.c"

powered by: WebSVN 2.1.0

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