1 /* Copyright(c) 2000, Compaq Computer Corporation
2 * Fibre Channel Host Bus Adapter
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
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
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
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
32 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
34 #include <linux/config.h>
35 #include <linux/interrupt.h>
36 #include <linux/module.h>
37 #include <linux/version.h>
38 #include <linux/blkdev.h>
39 #include <linux/kernel.h>
40 #include <linux/string.h>
41 #include <linux/types.h>
42 #include <linux/pci.h>
43 #include <linux/delay.h>
44 #include <linux/timer.h>
45 #include <linux/init.h>
46 #include <linux/ioport.h> // request_region() prototype
47 #include <linux/completion.h>
50 #include <asm/uaccess.h> // ioctl related
52 #include <linux/spinlock.h>
55 #include <scsi/scsi_ioctl.h>
56 #include "cpqfcTSchip.h"
57 #include "cpqfcTSstructs.h"
58 #include "cpqfcTStrigger.h"
62 /* Embedded module documentation macros - see module.h */
63 MODULE_AUTHOR("Compaq Computer Corporation");
64 MODULE_DESCRIPTION("Driver for Compaq 64-bit/66Mhz PCI Fibre Channel HBA v. 2.5.4");
65 MODULE_LICENSE("GPL");
67 int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, unsigned int reset_flags);
69 // This struct was originally defined in
70 // /usr/src/linux/include/linux/proc_fs.h
71 // since it's only partially implemented, we only use first
73 // NOTE: proc_fs changes in 2.4 kernel
75 #if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
76 static struct proc_dir_entry proc_scsi_cpqfcTS =
78 PROC_SCSI_CPQFCTS, // ushort low_ino (enumerated list)
80 DEV_NAME, // const char* name
81 S_IFDIR | S_IRUGO | S_IXUGO, // mode_t mode
89 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,7)
90 # define CPQFC_DECLARE_COMPLETION(x) DECLARE_COMPLETION(x)
91 # define CPQFC_WAITING waiting
92 # define CPQFC_COMPLETE(x) complete(x)
93 # define CPQFC_WAIT_FOR_COMPLETION(x) wait_for_completion(x);
95 # define CPQFC_DECLARE_COMPLETION(x) DECLARE_MUTEX_LOCKED(x)
96 # define CPQFC_WAITING sem
97 # define CPQFC_COMPLETE(x) up(x)
98 # define CPQFC_WAIT_FOR_COMPLETION(x) down(x)
101 static int cpqfc_alloc_private_data_pool(CPQFCHBA *hba);
103 /* local function to load our per-HBA (local) data for chip
104 registers, FC link state, all FC exchanges, etc.
106 We allocate space and compute address offsets for the
107 most frequently accessed addresses; others (like World Wide
108 Name) are not necessary.
110 static void Cpqfc_initHBAdata(CPQFCHBA *cpqfcHBAdata, struct pci_dev *PciDev )
113 cpqfcHBAdata->PciDev = PciDev; // copy PCI info ptr
115 // since x86 port space is 64k, we only need the lower 16 bits
116 cpqfcHBAdata->fcChip.Registers.IOBaseL =
117 PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
119 cpqfcHBAdata->fcChip.Registers.IOBaseU =
120 PciDev->resource[2].start & PCI_BASE_ADDRESS_IO_MASK;
122 // 32-bit memory addresses
123 cpqfcHBAdata->fcChip.Registers.MemBase =
124 PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK;
126 cpqfcHBAdata->fcChip.Registers.ReMapMemBase =
127 ioremap( PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK,
130 cpqfcHBAdata->fcChip.Registers.RAMBase =
131 PciDev->resource[4].start;
133 cpqfcHBAdata->fcChip.Registers.SROMBase = // NULL for HP TS adapter
134 PciDev->resource[5].start;
136 // now the Tachlite chip registers
137 // the REGISTER struct holds both the physical address & last
138 // written value (some TL registers are WRITE ONLY)
140 cpqfcHBAdata->fcChip.Registers.SFQconsumerIndex.address =
141 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_SFQ_CONSUMER_INDEX;
143 cpqfcHBAdata->fcChip.Registers.ERQproducerIndex.address =
144 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_ERQ_PRODUCER_INDEX;
147 cpqfcHBAdata->fcChip.Registers.FMconfig.address =
148 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_CONFIG;
149 cpqfcHBAdata->fcChip.Registers.FMcontrol.address =
150 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_CONTROL;
151 cpqfcHBAdata->fcChip.Registers.FMstatus.address =
152 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_STATUS;
153 cpqfcHBAdata->fcChip.Registers.FMLinkStatus1.address =
154 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_LINK_STAT1;
155 cpqfcHBAdata->fcChip.Registers.FMLinkStatus2.address =
156 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_LINK_STAT2;
157 cpqfcHBAdata->fcChip.Registers.FMBB_CreditZero.address =
158 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_BB_CREDIT0;
161 cpqfcHBAdata->fcChip.Registers.TYconfig.address =
162 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_CONFIG;
163 cpqfcHBAdata->fcChip.Registers.TYcontrol.address =
164 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_CONTROL;
165 cpqfcHBAdata->fcChip.Registers.TYstatus.address =
166 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_STATUS;
167 cpqfcHBAdata->fcChip.Registers.rcv_al_pa.address =
168 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_RCV_AL_PA;
169 cpqfcHBAdata->fcChip.Registers.ed_tov.address =
170 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_ED_TOV;
173 cpqfcHBAdata->fcChip.Registers.INTEN.address =
174 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTEN;
175 cpqfcHBAdata->fcChip.Registers.INTPEND.address =
176 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTPEND;
177 cpqfcHBAdata->fcChip.Registers.INTSTAT.address =
178 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTSTAT;
180 DEBUG_PCI(printk(" cpqfcHBAdata->fcChip.Registers. :\n"));
181 DEBUG_PCI(printk(" IOBaseL = %x\n",
182 cpqfcHBAdata->fcChip.Registers.IOBaseL));
183 DEBUG_PCI(printk(" IOBaseU = %x\n",
184 cpqfcHBAdata->fcChip.Registers.IOBaseU));
186 /* printk(" ioremap'd Membase: %p\n", cpqfcHBAdata->fcChip.Registers.ReMapMemBase); */
188 DEBUG_PCI(printk(" SFQconsumerIndex.address = %p\n",
189 cpqfcHBAdata->fcChip.Registers.SFQconsumerIndex.address));
190 DEBUG_PCI(printk(" ERQproducerIndex.address = %p\n",
191 cpqfcHBAdata->fcChip.Registers.ERQproducerIndex.address));
192 DEBUG_PCI(printk(" TYconfig.address = %p\n",
193 cpqfcHBAdata->fcChip.Registers.TYconfig.address));
194 DEBUG_PCI(printk(" FMconfig.address = %p\n",
195 cpqfcHBAdata->fcChip.Registers.FMconfig.address));
196 DEBUG_PCI(printk(" FMcontrol.address = %p\n",
197 cpqfcHBAdata->fcChip.Registers.FMcontrol.address));
199 // set default options for FC controller (chip)
200 cpqfcHBAdata->fcChip.Options.initiator = 1; // default: SCSI initiator
201 cpqfcHBAdata->fcChip.Options.target = 0; // default: SCSI target
202 cpqfcHBAdata->fcChip.Options.extLoopback = 0;// default: no loopback @GBIC
203 cpqfcHBAdata->fcChip.Options.intLoopback = 0;// default: no loopback inside chip
205 // set highest and lowest FC-PH version the adapter/driver supports
206 // (NOT strict compliance)
207 cpqfcHBAdata->fcChip.highest_FCPH_ver = FC_PH3;
208 cpqfcHBAdata->fcChip.lowest_FCPH_ver = FC_PH43;
210 // set function points for this controller / adapter
211 cpqfcHBAdata->fcChip.ResetTachyon = CpqTsResetTachLite;
212 cpqfcHBAdata->fcChip.FreezeTachyon = CpqTsFreezeTachlite;
213 cpqfcHBAdata->fcChip.UnFreezeTachyon = CpqTsUnFreezeTachlite;
214 cpqfcHBAdata->fcChip.CreateTachyonQues = CpqTsCreateTachLiteQues;
215 cpqfcHBAdata->fcChip.DestroyTachyonQues = CpqTsDestroyTachLiteQues;
216 cpqfcHBAdata->fcChip.InitializeTachyon = CpqTsInitializeTachLite;
217 cpqfcHBAdata->fcChip.LaserControl = CpqTsLaserControl;
218 cpqfcHBAdata->fcChip.ProcessIMQEntry = CpqTsProcessIMQEntry;
219 cpqfcHBAdata->fcChip.InitializeFrameManager = CpqTsInitializeFrameManager;
220 cpqfcHBAdata->fcChip.ReadWriteWWN = CpqTsReadWriteWWN;
221 cpqfcHBAdata->fcChip.ReadWriteNVRAM = CpqTsReadWriteNVRAM;
223 if (cpqfc_alloc_private_data_pool(cpqfcHBAdata) != 0) {
225 "cpqfc: unable to allocate pool for passthru ioctls. "
226 "Passthru ioctls disabled.\n");
231 /* (borrowed from linux/drivers/scsi/hosts.c) */
232 static void launch_FCworker_thread(struct Scsi_Host *HostAdapter)
234 DECLARE_MUTEX_LOCKED(sem);
236 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
238 ENTER("launch_FC_worker_thread");
240 cpqfcHBAdata->notify_wt = &sem;
242 /* must unlock before kernel_thread(), for it may cause a reschedule. */
243 spin_unlock_irq(HostAdapter->host_lock);
244 kernel_thread((int (*)(void *))cpqfcTSWorkerThread,
245 (void *) HostAdapter, 0);
247 * Now wait for the kernel error thread to initialize itself
251 spin_lock_irq(HostAdapter->host_lock);
252 cpqfcHBAdata->notify_wt = NULL;
254 LEAVE("launch_FC_worker_thread");
259 /* "Entry" point to discover if any supported PCI
260 bus adapter can be found
263 * Compaq 64-bit, 66MHz HBA with Tachyon TS
269 #ifndef PCI_DEVICE_ID_COMPAQ_
270 #define PCI_DEVICE_ID_COMPAQ_TACHYON 0xa0fc
273 static struct SupportedPCIcards cpqfc_boards[] __initdata = {
274 {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TACHYON},
275 {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_TACHLITE},
276 {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_TACHYON},
280 int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate)
282 int NumberOfAdapters=0; // how many of our PCI adapters are found?
283 struct pci_dev *PciDev = NULL;
284 struct Scsi_Host *HostAdapter = NULL;
285 CPQFCHBA *cpqfcHBAdata = NULL;
286 struct timer_list *cpqfcTStimer = NULL;
289 ENTER("cpqfcTS_detect");
291 #if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
292 ScsiHostTemplate->proc_dir = &proc_scsi_cpqfcTS;
294 ScsiHostTemplate->proc_name = "cpqfcTS";
297 for( i=0; i < HBA_TYPES; i++)
299 // look for all HBAs of each type
301 while((PciDev = pci_find_device(cpqfc_boards[i].vendor_id,
302 cpqfc_boards[i].device_id, PciDev)))
305 if (pci_set_dma_mask(PciDev, CPQFCTS_DMA_MASK) != 0) {
307 "cpqfc: HBA cannot support required DMA mask, skipping.\n");
311 // NOTE: (kernel 2.2.12-32) limits allocation to 128k bytes...
312 /* printk(" scsi_register allocating %d bytes for FC HBA\n",
313 (ULONG)sizeof(CPQFCHBA)); */
315 HostAdapter = scsi_register( ScsiHostTemplate, sizeof( CPQFCHBA ) );
317 if(HostAdapter == NULL)
319 DEBUG_PCI( printk(" HBA found!\n"));
320 DEBUG_PCI( printk(" HostAdapter->PciDev->irq = %u\n", PciDev->irq) );
321 DEBUG_PCI(printk(" PciDev->baseaddress[0]= %lx\n",
322 PciDev->resource[0].start));
323 DEBUG_PCI(printk(" PciDev->baseaddress[1]= %lx\n",
324 PciDev->resource[1].start));
325 DEBUG_PCI(printk(" PciDev->baseaddress[2]= %lx\n",
326 PciDev->resource[2].start));
327 DEBUG_PCI(printk(" PciDev->baseaddress[3]= %lx\n",
328 PciDev->resource[3].start));
330 scsi_set_device(HostAdapter, &PciDev->dev);
331 HostAdapter->irq = PciDev->irq; // copy for Scsi layers
333 // HP Tachlite uses two (255-byte) ranges of Port I/O (lower & upper),
334 // for a total I/O port address space of 512 bytes.
335 // mask out the I/O port address (lower) & record
336 HostAdapter->io_port = (unsigned int)
337 PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
338 HostAdapter->n_io_port = 0xff;
340 // i.e., expect 128 targets (arbitrary number), while the
341 // RA-4000 supports 32 LUNs
342 HostAdapter->max_id = 0; // incremented as devices log in
343 HostAdapter->max_lun = CPQFCTS_MAX_LUN; // LUNs per FC device
344 HostAdapter->max_channel = CPQFCTS_MAX_CHANNEL; // multiple busses?
346 // get the pointer to our HBA specific data... (one for
347 // each HBA on the PCI bus(ses)).
348 cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
350 // make certain our data struct is clear
351 memset( cpqfcHBAdata, 0, sizeof( CPQFCHBA ) );
354 // initialize our HBA info
355 cpqfcHBAdata->HBAnum = NumberOfAdapters;
357 cpqfcHBAdata->HostAdapter = HostAdapter; // back ptr
358 Cpqfc_initHBAdata( cpqfcHBAdata, PciDev ); // fill MOST fields
360 cpqfcHBAdata->HBAnum = NumberOfAdapters;
361 cpqfcHBAdata->hba_spinlock = SPIN_LOCK_UNLOCKED;
363 // request necessary resources and check for conflicts
364 if( request_irq( HostAdapter->irq,
365 cpqfcTS_intr_handler,
366 SA_INTERRUPT | SA_SHIRQ,
370 printk(" IRQ %u already used\n", HostAdapter->irq);
371 scsi_unregister( HostAdapter);
375 // Since we have two 256-byte I/O port ranges (upper
376 // and lower), check them both
377 if( !request_region( cpqfcHBAdata->fcChip.Registers.IOBaseU,
380 printk(" cpqfcTS address in use: %x\n",
381 cpqfcHBAdata->fcChip.Registers.IOBaseU);
382 free_irq( HostAdapter->irq, HostAdapter);
383 scsi_unregister( HostAdapter);
387 if( !request_region( cpqfcHBAdata->fcChip.Registers.IOBaseL,
390 printk(" cpqfcTS address in use: %x\n",
391 cpqfcHBAdata->fcChip.Registers.IOBaseL);
392 release_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff );
393 free_irq( HostAdapter->irq, HostAdapter);
394 scsi_unregister( HostAdapter);
398 // OK, we have grabbed everything we need now.
399 DEBUG_PCI(printk(" Reserved 255 I/O addresses @ %x\n",
400 cpqfcHBAdata->fcChip.Registers.IOBaseL ));
401 DEBUG_PCI(printk(" Reserved 255 I/O addresses @ %x\n",
402 cpqfcHBAdata->fcChip.Registers.IOBaseU ));
406 // start our kernel worker thread
408 spin_lock_irq(HostAdapter->host_lock);
409 launch_FCworker_thread(HostAdapter);
412 // start our TimerTask...
414 cpqfcTStimer = &cpqfcHBAdata->cpqfcTStimer;
416 init_timer( cpqfcTStimer); // Linux clears next/prev values
417 cpqfcTStimer->expires = jiffies + HZ; // one second
418 cpqfcTStimer->data = (unsigned long)cpqfcHBAdata; // this adapter
419 cpqfcTStimer->function = cpqfcTSheartbeat; // handles timeouts, housekeeping
421 add_timer( cpqfcTStimer); // give it to Linux
424 // now initialize our hardware...
425 if (cpqfcHBAdata->fcChip.InitializeTachyon( cpqfcHBAdata, 1,1)) {
426 printk(KERN_WARNING "cpqfc: initialization of HBA hardware failed.\n");
427 // FIXME: might want to do something better than nothing here.
430 cpqfcHBAdata->fcStatsTime = jiffies; // (for FC Statistics delta)
432 // give our HBA time to initialize and login current devices...
434 // The Brocade switch (e.g. 2400, 2010, etc.) as of March 2000,
435 // has the following algorithm for FL_Port startup:
437 // 0: Device Plugin and LIP(F7,F7) transmission
439 // 1.027 LISA incoming, no CLS! (link not up)
440 // 1.028 NOS incoming (switch test for N_Port)
441 // 1.577 ED_TOV expired, transmit LIPs again
442 // 3.0 LIP(F8,F7) incoming (switch passes Tach Prim.Sig)
443 // 3.028 LILP received, link up, FLOGI starts
444 // slowest(worst) case, measured on 1Gb Finisar GT analyzer
446 unsigned long stop_time;
448 spin_unlock_irq(HostAdapter->host_lock);
449 stop_time = jiffies + 4*HZ;
450 while ( time_before(jiffies, stop_time) )
451 schedule(); // (our worker task needs to run)
455 spin_lock_irq(HostAdapter->host_lock);
457 spin_unlock_irq(HostAdapter->host_lock);
461 LEAVE("cpqfcTS_detect");
463 return NumberOfAdapters;
467 static void my_ioctl_done (Scsi_Cmnd * SCpnt)
469 struct request * req;
471 req = SCpnt->request;
472 req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */
474 if (req->CPQFC_WAITING != NULL)
475 CPQFC_COMPLETE(req->CPQFC_WAITING);
479 static int cpqfc_alloc_private_data_pool(CPQFCHBA *hba)
481 hba->private_data_bits = NULL;
482 hba->private_data_pool = NULL;
483 hba->private_data_bits =
484 kmalloc(((CPQFC_MAX_PASSTHRU_CMDS+BITS_PER_LONG-1) /
485 BITS_PER_LONG)*sizeof(unsigned long),
487 if (hba->private_data_bits == NULL)
489 memset(hba->private_data_bits, 0,
490 ((CPQFC_MAX_PASSTHRU_CMDS+BITS_PER_LONG-1) /
491 BITS_PER_LONG)*sizeof(unsigned long));
492 hba->private_data_pool = kmalloc(sizeof(cpqfc_passthru_private_t) *
493 CPQFC_MAX_PASSTHRU_CMDS, GFP_KERNEL);
494 if (hba->private_data_pool == NULL) {
495 kfree(hba->private_data_bits);
496 hba->private_data_bits = NULL;
502 static void cpqfc_free_private_data_pool(CPQFCHBA *hba)
504 kfree(hba->private_data_bits);
505 kfree(hba->private_data_pool);
508 int is_private_data_of_cpqfc(CPQFCHBA *hba, void *pointer)
510 /* Is pointer within our private data pool?
511 We use Scsi_Request->upper_private_data (normally
512 reserved for upper layer drivers, e.g. the sg driver)
513 We check to see if the pointer is ours by looking at
514 its address. Is this ok? Hmm, it occurs to me that
515 a user app might do something bad by using sg to send
516 a cpqfc passthrough ioctl with upper_data_private
517 forged to be somewhere in our pool..., though they'd
518 normally have to be root already to do this. */
520 return (pointer != NULL &&
521 pointer >= (void *) hba->private_data_pool &&
522 pointer < (void *) hba->private_data_pool +
523 sizeof(*hba->private_data_pool) *
524 CPQFC_MAX_PASSTHRU_CMDS);
527 cpqfc_passthru_private_t *cpqfc_alloc_private_data(CPQFCHBA *hba)
532 i = find_first_zero_bit(hba->private_data_bits,
533 CPQFC_MAX_PASSTHRU_CMDS);
534 if (i == CPQFC_MAX_PASSTHRU_CMDS)
536 } while ( test_and_set_bit(i & (BITS_PER_LONG - 1),
537 hba->private_data_bits+(i/BITS_PER_LONG)) != 0);
538 return &hba->private_data_pool[i];
541 void cpqfc_free_private_data(CPQFCHBA *hba, cpqfc_passthru_private_t *data)
544 i = data - hba->private_data_pool;
545 clear_bit(i&(BITS_PER_LONG-1),
546 hba->private_data_bits+(i/BITS_PER_LONG));
549 int cpqfcTS_ioctl( struct scsi_device *ScsiDev, int Cmnd, void *arg)
552 struct Scsi_Host *HostAdapter = ScsiDev->host;
553 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
554 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
555 PFC_LOGGEDIN_PORT pLoggedInPort = NULL;
556 struct scsi_cmnd *DumCmnd;
558 VENDOR_IOCTL_REQ ioc;
559 cpqfc_passthru_t *vendor_cmd;
561 Scsi_Request *ScsiPassThruReq;
562 cpqfc_passthru_private_t *privatedata;
564 ENTER("cpqfcTS_ioctl ");
566 // printk("ioctl CMND %d", Cmnd);
568 // Passthrough provides a mechanism to bypass the RAID
569 // or other controller and talk directly to the devices
570 // (e.g. physical disk drive)
571 // Passthrough commands, unfortunately, tend to be vendor
572 // specific; this is tailored to COMPAQ's RAID (RA4x00)
573 case CPQFCTS_SCSI_PASSTHRU:
575 void *buf = NULL; // for kernel space buffer for user data
577 /* Check that our pool got allocated ok. */
578 if (cpqfcHBAdata->private_data_pool == NULL)
584 // must be super user to send stuff directly to the
585 // controller and/or physical drives...
586 if( !capable(CAP_SYS_RAWIO) )
589 // copy the caller's struct to our space.
590 if( copy_from_user( &ioc, arg, sizeof( VENDOR_IOCTL_REQ)))
593 vendor_cmd = ioc.argp; // i.e., CPQ specific command struct
595 // If necessary, grab a kernel/DMA buffer
598 buf = kmalloc( vendor_cmd->len, GFP_KERNEL);
602 // Now build a Scsi_Request to pass down...
603 ScsiPassThruReq = scsi_allocate_request(ScsiDev, GFP_KERNEL);
604 if (ScsiPassThruReq == NULL) {
608 ScsiPassThruReq->upper_private_data =
609 cpqfc_alloc_private_data(cpqfcHBAdata);
610 if (ScsiPassThruReq->upper_private_data == NULL) {
612 scsi_release_request(ScsiPassThruReq); // "de-allocate"
616 if (vendor_cmd->rw_flag == VENDOR_WRITE_OPCODE) {
617 if (vendor_cmd->len) { // Need data from user?
618 if (copy_from_user(buf, vendor_cmd->bufp,
621 cpqfc_free_private_data(cpqfcHBAdata,
622 ScsiPassThruReq->upper_private_data);
623 scsi_release_request(ScsiPassThruReq);
627 ScsiPassThruReq->sr_data_direction = SCSI_DATA_WRITE;
628 } else if (vendor_cmd->rw_flag == VENDOR_READ_OPCODE) {
629 ScsiPassThruReq->sr_data_direction = SCSI_DATA_READ;
631 // maybe this means a bug in the user app
632 ScsiPassThruReq->sr_data_direction = SCSI_DATA_NONE;
634 ScsiPassThruReq->sr_cmd_len = 0; // set correctly by scsi_do_req()
635 ScsiPassThruReq->sr_sense_buffer[0] = 0;
636 ScsiPassThruReq->sr_sense_buffer[2] = 0;
638 // We copy the scheme used by sd.c:spinup_disk() to submit commands
639 // to our own HBA. We do this in order to stall the
640 // thread calling the IOCTL until it completes, and use
641 // the same "_quecommand" function for synchronizing
642 // FC Link events with our "worker thread".
644 privatedata = ScsiPassThruReq->upper_private_data;
645 privatedata->bus = vendor_cmd->bus;
646 privatedata->pdrive = vendor_cmd->pdrive;
648 // eventually gets us to our own _quecommand routine
649 scsi_wait_req(ScsiPassThruReq,
650 &vendor_cmd->cdb[0], buf, vendor_cmd->len,
653 result = ScsiPassThruReq->sr_result;
655 // copy any sense data back to caller
658 memcpy( vendor_cmd->sense_data, // see struct def - size=40
659 ScsiPassThruReq->sr_sense_buffer,
660 sizeof(ScsiPassThruReq->sr_sense_buffer) <
661 sizeof(vendor_cmd->sense_data) ?
662 sizeof(ScsiPassThruReq->sr_sense_buffer) :
663 sizeof(vendor_cmd->sense_data)
666 SDpnt = ScsiPassThruReq->sr_device;
667 /* upper_private_data is already freed in call_scsi_done() */
668 scsi_release_request(ScsiPassThruReq); // "de-allocate"
669 ScsiPassThruReq = NULL;
671 // need to pass data back to user (space)?
672 if( (vendor_cmd->rw_flag == VENDOR_READ_OPCODE) &&
674 if( copy_to_user( vendor_cmd->bufp, buf, vendor_cmd->len))
683 case CPQFCTS_GETPCIINFO:
685 cpqfc_pci_info_struct pciinfo;
692 pciinfo.bus = cpqfcHBAdata->PciDev->bus->number;
693 pciinfo.dev_fn = cpqfcHBAdata->PciDev->devfn;
694 pciinfo.board_id = cpqfcHBAdata->PciDev->device |
695 (cpqfcHBAdata->PciDev->vendor <<16);
697 if(copy_to_user( arg, &pciinfo, sizeof(cpqfc_pci_info_struct)))
702 case CPQFCTS_GETDRIVVER:
704 DriverVer_type DriverVer =
705 CPQFCTS_DRIVER_VER( VER_MAJOR,VER_MINOR,VER_SUBMINOR);
710 if(copy_to_user( arg, &DriverVer, sizeof(DriverVer)))
717 case CPQFC_IOCTL_FC_TARGET_ADDRESS:
718 // can we find an FC device mapping to this SCSI target?
719 /* DumCmnd.channel = ScsiDev->channel; */ // For searching
720 /* DumCmnd.target = ScsiDev->id; */
721 /* DumCmnd.lun = ScsiDev->lun; */
723 DumCmnd = scsi_get_command (ScsiDev, GFP_KERNEL);
727 pLoggedInPort = fcFindLoggedInPort( fcChip,
728 DumCmnd, // search Scsi Nexus
729 0, // DON'T search linked list for FC port id
730 NULL, // DON'T search linked list for FC WWN
731 NULL); // DON'T care about end of list
732 scsi_put_command (DumCmnd);
733 if (pLoggedInPort == NULL) {
737 result = verify_area(VERIFY_WRITE, arg, sizeof(Scsi_FCTargAddress));
740 put_user(pLoggedInPort->port_id,
741 &((Scsi_FCTargAddress *) arg)->host_port_id);
743 for( i=3,j=0; i>=0; i--) // copy the LOGIN port's WWN
744 put_user(pLoggedInPort->u.ucWWN[i],
745 &((Scsi_FCTargAddress *) arg)->host_wwn[j++]);
746 for( i=7; i>3; i--) // copy the LOGIN port's WWN
747 put_user(pLoggedInPort->u.ucWWN[i],
748 &((Scsi_FCTargAddress *) arg)->host_wwn[j++]);
752 case CPQFC_IOCTL_FC_TDR:
754 result = cpqfcTS_TargetDeviceReset( ScsiDev, 0);
766 LEAVE("cpqfcTS_ioctl");
771 /* "Release" the Host Bus Adapter...
772 disable interrupts, stop the HBA, release the interrupt,
773 and free all resources */
775 int cpqfcTS_release(struct Scsi_Host *HostAdapter)
777 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
780 ENTER("cpqfcTS_release");
782 DEBUG_PCI( printk(" cpqfcTS: delete timer...\n"));
783 del_timer( &cpqfcHBAdata->cpqfcTStimer);
785 // disable the hardware...
786 DEBUG_PCI( printk(" disable hardware, destroy queues, free mem\n"));
787 cpqfcHBAdata->fcChip.ResetTachyon( cpqfcHBAdata, CLEAR_FCPORTS);
789 // kill kernel thread
790 if( cpqfcHBAdata->worker_thread ) // (only if exists)
792 DECLARE_MUTEX_LOCKED(sem); // synchronize thread kill
794 cpqfcHBAdata->notify_wt = &sem;
795 DEBUG_PCI( printk(" killing kernel thread\n"));
796 send_sig( SIGKILL, cpqfcHBAdata->worker_thread, 1);
798 cpqfcHBAdata->notify_wt = NULL;
802 cpqfc_free_private_data_pool(cpqfcHBAdata);
803 // free Linux resources
804 DEBUG_PCI( printk(" cpqfcTS: freeing resources...\n"));
805 free_irq( HostAdapter->irq, HostAdapter);
806 scsi_unregister( HostAdapter);
807 release_region( cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff);
808 release_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff);
809 /* we get "vfree: bad address" executing this - need to investigate...
810 if( (void*)((unsigned long)cpqfcHBAdata->fcChip.Registers.MemBase) !=
811 cpqfcHBAdata->fcChip.Registers.ReMapMemBase)
812 vfree( cpqfcHBAdata->fcChip.Registers.ReMapMemBase);
815 LEAVE("cpqfcTS_release");
820 const char * cpqfcTS_info(struct Scsi_Host *HostAdapter)
822 static char buf[300];
824 int BusSpeed, BusWidth;
826 // get the pointer to our Scsi layer HBA buffer
827 cpqfcHBA = (CPQFCHBA *)HostAdapter->hostdata;
829 BusWidth = (cpqfcHBA->fcChip.Registers.PCIMCTR &0x4) > 0 ?
832 if( cpqfcHBA->fcChip.Registers.TYconfig.value & 0x80000000)
838 "%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",
839 cpqfcHBA->fcChip.Name,
840 cpqfcHBA->fcChip.Registers.wwn_hi,
841 cpqfcHBA->fcChip.Registers.wwn_lo,
842 cpqfcHBA->PciDev->bus->number,
843 cpqfcHBA->PciDev->device,
845 cpqfcHBA->fcChip.Registers.IOBaseL,
846 cpqfcHBA->fcChip.Registers.MemBase,
849 VER_MAJOR, VER_MINOR, VER_SUBMINOR
853 cpqfcTSDecodeGBICtype( &cpqfcHBA->fcChip, &buf[ strlen(buf)]);
854 cpqfcTSGetLPSM( &cpqfcHBA->fcChip, &buf[ strlen(buf)]);
859 // /proc/scsi support. The following routines allow us to do 'normal'
860 // sprintf like calls to return the currently requested piece (buflenght
861 // chars, starting at bufoffset) of the file. Although procfs allows for
862 // a 1 Kb bytes overflow after te supplied buffer, I consider it bad
863 // programming to use it to make programming a little simpler. This piece
864 // of coding is borrowed from ncr53c8xx.c with some modifications
868 char *buffer; // Pointer to output buffer
869 int buflength; // It's length
870 int bufoffset; // File offset corresponding with buf[0]
871 int buffillen; // Current filled length
872 int filpos; // Current file offset
875 static void copy_mem_info(struct info_str *info, char *data, int datalen)
878 if (info->filpos < info->bufoffset) { // Current offset before buffer offset
879 if (info->filpos + datalen <= info->bufoffset) {
880 info->filpos += datalen; // Discard if completely before buffer
882 } else { // Partial copy, set to begin
883 data += (info->bufoffset - info->filpos);
884 datalen -= (info->bufoffset - info->filpos);
885 info->filpos = info->bufoffset;
889 info->filpos += datalen; // Update current offset
891 if (info->buffillen == info->buflength) // Buffer full, discard
894 if (info->buflength - info->buffillen < datalen) // Overflows buffer ?
895 datalen = info->buflength - info->buffillen;
897 memcpy(info->buffer + info->buffillen, data, datalen);
898 info->buffillen += datalen;
901 static int copy_info(struct info_str *info, char *fmt, ...)
908 len = vsprintf(buf, fmt, args);
911 copy_mem_info(info, buf, len);
916 // Routine to get data for /proc RAM filesystem
918 int cpqfcTS_proc_info (struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length,
921 struct scsi_cmnd *DumCmnd;
922 struct scsi_device *ScsiDev;
924 struct info_str info;
927 PFC_LOGGEDIN_PORT pLoggedInPort;
930 if (inout) return -EINVAL;
932 // get the pointer to our Scsi layer HBA buffer
933 cpqfcHBA = (CPQFCHBA *)host->hostdata;
934 fcChip = &cpqfcHBA->fcChip;
938 info.buffer = buffer;
939 info.buflength = length;
940 info.bufoffset = offset;
943 copy_info(&info, "Driver version = %d.%d.%d", VER_MAJOR, VER_MINOR, VER_SUBMINOR);
944 cpqfcTSDecodeGBICtype( &cpqfcHBA->fcChip, &buf[0]);
945 cpqfcTSGetLPSM( &cpqfcHBA->fcChip, &buf[ strlen(buf)]);
946 copy_info(&info, "%s\n", buf);
948 #define DISPLAY_WWN_INFO
949 #ifdef DISPLAY_WWN_INFO
950 ScsiDev = scsi_get_host_dev (host);
953 DumCmnd = scsi_get_command (ScsiDev, GFP_KERNEL);
955 scsi_free_host_dev (ScsiDev);
958 copy_info(&info, "WWN database: (\"port_id: 000000\" means disconnected)\n");
959 for ( Chan=0; Chan <= host->max_channel; Chan++) {
960 DumCmnd->device->channel = Chan;
961 for (Targ=0; Targ <= host->max_id; Targ++) {
962 DumCmnd->device->id = Targ;
963 if ((pLoggedInPort = fcFindLoggedInPort( fcChip,
964 DumCmnd, // search Scsi Nexus
965 0, // DON'T search list for FC port id
966 NULL, // DON'T search list for FC WWN
967 NULL))){ // DON'T care about end of list
968 copy_info(&info, "Host: scsi%d Channel: %02d TargetId: %02d -> WWN: ",
969 host->host_no, Chan, Targ);
970 for( i=3; i>=0; i--) // copy the LOGIN port's WWN
971 copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]);
972 for( i=7; i>3; i--) // copy the LOGIN port's WWN
973 copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]);
974 copy_info(&info, " port_id: %06X\n", pLoggedInPort->port_id);
979 scsi_put_command (DumCmnd);
980 scsi_free_host_dev (ScsiDev);
987 // Unfortunately, the proc_info buffer isn't big enough
988 // for everything we would like...
989 // For FC stats, compile this and turn off WWN stuff above
990 //#define DISPLAY_FC_STATS
991 #ifdef DISPLAY_FC_STATS
992 // get the Fibre Channel statistics
994 int DeltaSecs = (jiffies - cpqfcHBA->fcStatsTime) / HZ;
995 int days,hours,minutes,secs;
997 days = DeltaSecs / (3600*24); // days
998 hours = (DeltaSecs% (3600*24)) / 3600; // hours
999 minutes = (DeltaSecs%3600 /60); // minutes
1000 secs = DeltaSecs%60; // secs
1001 copy_info( &info, "Fibre Channel Stats (time dd:hh:mm:ss %02u:%02u:%02u:%02u\n",
1002 days, hours, minutes, secs);
1005 cpqfcHBA->fcStatsTime = jiffies; // (for next delta)
1007 copy_info( &info, " LinkUp %9u LinkDown %u\n",
1008 fcChip->fcStats.linkUp, fcChip->fcStats.linkDown);
1010 copy_info( &info, " Loss of Signal %9u Loss of Sync %u\n",
1011 fcChip->fcStats.LossofSignal, fcChip->fcStats.LossofSync);
1013 copy_info( &info, " Discarded Frames %9u Bad CRC Frame %u\n",
1014 fcChip->fcStats.Dis_Frm, fcChip->fcStats.Bad_CRC);
1016 copy_info( &info, " TACH LinkFailTX %9u TACH LinkFailRX %u\n",
1017 fcChip->fcStats.linkFailTX, fcChip->fcStats.linkFailRX);
1019 copy_info( &info, " TACH RxEOFa %9u TACH Elastic Store %u\n",
1020 fcChip->fcStats.Rx_EOFa, fcChip->fcStats.e_stores);
1022 copy_info( &info, " BufferCreditWait %9uus TACH FM Inits %u\n",
1023 fcChip->fcStats.BB0_Timer*10, fcChip->fcStats.FMinits );
1025 copy_info( &info, " FC-2 Timeouts %9u FC-2 Logouts %u\n",
1026 fcChip->fcStats.timeouts, fcChip->fcStats.logouts);
1028 copy_info( &info, " FC-2 Aborts %9u FC-4 Aborts %u\n",
1029 fcChip->fcStats.FC2aborted, fcChip->fcStats.FC4aborted);
1031 // clear the counters
1032 cpqfcTSClearLinkStatusCounters( fcChip);
1035 return info.buffillen;
1041 UCHAR *ScsiToAscii( UCHAR ScsiCommand)
1046 Routine Description:
1048 Converts a SCSI command to a text string for debugging purposes.
1053 ScsiCommand -- hex value SCSI Command
1058 An ASCII, null-terminated string if found, else returns NULL.
1060 Original code from M. McGowen, Compaq
1064 switch (ScsiCommand)
1067 return( "Test Unit Ready" );
1070 return( "Rezero Unit or Rewind" );
1073 return( "Request Block Address" );
1076 return( "Requese Sense" );
1079 return( "Format Unit" );
1082 return( "Read Block Limits" );
1085 return( "Reassign Blocks" );
1088 return( "Read (6)" );
1091 return( "Write (6)" );
1094 return( "Seek (6)" );
1097 return( "Inquiry" );
1100 return( "Mode Select (6)" );
1103 return( "Reserve" );
1106 return( "Release" );
1109 return( "ModeSen(6)" );
1112 return( "Start/Stop Unit" );
1115 return( "Receive Diagnostic Results" );
1118 return( "Send Diagnostic" );
1121 return( "Read Capacity" );
1124 return( "Read (10)" );
1127 return( "Write (10)" );
1130 return( "Seek (10)" );
1133 return( "Write and Verify" );
1139 return( "Pre-Fetch" );
1142 return( "Synchronize Cache" );
1145 return( "Read Defect Data (10)" );
1148 return( "Write Buffer" );
1151 return( "Read Buffer" );
1154 return( "Read Long" );
1157 return( "Write Long" );
1160 return( "Write Same" );
1163 return( "Log Select" );
1166 return( "Log Sense" );
1169 return( "Reserve (10)" );
1172 return( "Release (10)" );
1175 return( "ReportLuns" );
1178 return( "Read Defect Data (12)" );
1181 return( "Peripheral Device Addressing SCSI Passthrough" );
1184 return( "Compaq Array Firmware Passthrough" );
1190 } // end ScsiToAscii()
1192 void cpqfcTS_print_scsi_cmd(Scsi_Cmnd * cmd)
1195 printk("cpqfcTS: (%s) chnl 0x%02x, trgt = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n",
1196 ScsiToAscii( cmd->cmnd[0]), cmd->channel, cmd->target, cmd->lun, cmd->cmd_len);
1198 if( cmd->cmnd[0] == 0) // Test Unit Ready?
1202 printk("Cmnd->request_bufflen = 0x%X, ->use_sg = %d, ->bufflen = %d\n",
1203 cmd->request_bufflen, cmd->use_sg, cmd->bufflen);
1204 printk("Cmnd->request_buffer = %p, ->sglist_len = %d, ->buffer = %p\n",
1205 cmd->request_buffer, cmd->sglist_len, cmd->buffer);
1206 for (i = 0; i < cmd->cmd_len; i++)
1207 printk("0x%02x ", cmd->cmnd[i]);
1213 #endif /* DEBUG_CMND */
1218 static void QueCmndOnBoardLock( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd)
1222 for( i=0; i< CPQFCTS_REQ_QUEUE_LEN; i++)
1223 { // find spare slot
1224 if( cpqfcHBAdata->BoardLockCmnd[i] == NULL )
1226 cpqfcHBAdata->BoardLockCmnd[i] = Cmnd;
1227 // printk(" BoardLockCmnd[%d] %p Queued, chnl/target/lun %d/%d/%d\n",
1228 // i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
1232 if( i >= CPQFCTS_REQ_QUEUE_LEN)
1234 printk(" cpqfcTS WARNING: Lost Cmnd %p on BoardLock Q full!", Cmnd);
1240 static void QueLinkDownCmnd( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd)
1244 // Remember the command ptr so we can return; we'll complete when
1245 // the device comes back, causing immediate retry
1246 for( indx=0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++)//, SCptr++)
1248 if( cpqfcHBAdata->LinkDnCmnd[indx] == NULL ) // available?
1250 #ifdef DUMMYCMND_DBG
1251 printk(" @add Cmnd %p to LnkDnCmnd[%d]@ ", Cmnd,indx);
1253 cpqfcHBAdata->LinkDnCmnd[indx] = Cmnd;
1258 if( indx >= CPQFCTS_REQ_QUEUE_LEN ) // no space for Cmnd??
1260 // this will result in an _abort call later (with possible trouble)
1261 printk("no buffer for LinkDnCmnd!! %p\n", Cmnd);
1269 // The file "hosts.h" says not to call scsi_done from
1270 // inside _queuecommand, so we'll do it from the heartbeat timer
1271 // (clarification: Turns out it's ok to call scsi_done from queuecommand
1272 // for cases that don't go to the hardware like scsi cmds destined
1273 // for LUNs we know don't exist, so this code might be simplified...)
1275 static void QueBadTargetCmnd( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd)
1278 // printk(" can't find target %d\n", Cmnd->target);
1280 for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++)
1281 { // find spare slot
1282 if( cpqfcHBAdata->BadTargetCmnd[i] == NULL )
1284 cpqfcHBAdata->BadTargetCmnd[i] = Cmnd;
1285 // printk(" BadTargetCmnd[%d] %p Queued, chnl/target/lun %d/%d/%d\n",
1286 // i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
1293 // This is the "main" entry point for Linux Scsi commands --
1294 // it all starts here.
1296 int cpqfcTS_queuecommand(Scsi_Cmnd *Cmnd, void (* done)(Scsi_Cmnd *))
1298 struct Scsi_Host *HostAdapter = Cmnd->device->host;
1299 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
1300 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1301 TachFCHDR_GCMND fchs; // only use for FC destination id field
1302 PFC_LOGGEDIN_PORT pLoggedInPort;
1303 ULONG ulStatus, SESTtype;
1309 ENTER("cpqfcTS_queuecommand");
1311 PCI_TRACEO( (ULONG)Cmnd, 0x98)
1314 Cmnd->scsi_done = done;
1316 cpqfcTS_print_scsi_cmd( Cmnd);
1319 // prevent board contention with kernel thread...
1321 if( cpqfcHBAdata->BoardLock )
1323 // printk(" @BrdLck Hld@ ");
1324 QueCmndOnBoardLock( cpqfcHBAdata, Cmnd);
1330 // in the current system (2.2.12), this routine is called
1331 // after spin_lock_irqsave(), so INTs are disabled. However,
1332 // we might have something pending in the LinkQ, which
1333 // might cause the WorkerTask to run. In case that
1334 // happens, make sure we lock it out.
1339 CPQ_SPINLOCK_HBA( cpqfcHBAdata)
1342 // can we find an FC device mapping to this SCSI target?
1343 pLoggedInPort = fcFindLoggedInPort( fcChip,
1344 Cmnd, // search Scsi Nexus
1345 0, // DON'T search linked list for FC port id
1346 NULL, // DON'T search linked list for FC WWN
1347 NULL); // DON'T care about end of list
1349 if( pLoggedInPort == NULL ) // not found!
1351 // printk(" @Q bad targ cmnd %p@ ", Cmnd);
1352 QueBadTargetCmnd( cpqfcHBAdata, Cmnd);
1354 else if (Cmnd->device->lun >= CPQFCTS_MAX_LUN)
1356 printk(KERN_WARNING "cpqfc: Invalid LUN: %d\n", Cmnd->device->lun);
1357 QueBadTargetCmnd( cpqfcHBAdata, Cmnd);
1360 else // we know what FC device to send to...
1363 // does this device support FCP target functions?
1364 // (determined by PRLI field)
1366 if( !(pLoggedInPort->fcp_info & TARGET_FUNCTION) )
1368 printk(" Doesn't support TARGET functions port_id %Xh\n",
1369 pLoggedInPort->port_id );
1370 QueBadTargetCmnd( cpqfcHBAdata, Cmnd);
1373 // In this case (previous login OK), the device is temporarily
1374 // unavailable waiting for re-login, in which case we expect it
1375 // to be back in between 25 - 500ms.
1376 // If the FC port doesn't log back in within several seconds
1377 // (i.e. implicit "logout"), or we get an explicit logout,
1378 // we set "device_blocked" in Scsi_Device struct; in this
1379 // case 30 seconds will elapse before Linux/Scsi sends another
1380 // command to the device.
1381 else if( pLoggedInPort->prli != TRUE )
1383 // printk("Device (Chnl/Target %d/%d) invalid PRLI, port_id %06lXh\n",
1384 // Cmnd->channel, Cmnd->target, pLoggedInPort->port_id);
1385 QueLinkDownCmnd( cpqfcHBAdata, Cmnd);
1386 // Need to use "blocked" flag??
1387 // Cmnd->device->device_blocked = TRUE; // just let it timeout
1389 else // device supports TARGET functions, and is logged in...
1391 // (context of fchs is to "reply" to...)
1392 fchs.s_id = pLoggedInPort->port_id; // destination FC address
1394 // what is the data direction? For data TO the device,
1395 // we need IWE (Intiator Write Entry). Otherwise, IRE.
1397 if( Cmnd->cmnd[0] == WRITE_10 ||
1398 Cmnd->cmnd[0] == WRITE_6 ||
1399 Cmnd->cmnd[0] == WRITE_BUFFER ||
1400 Cmnd->cmnd[0] == VENDOR_WRITE_OPCODE || // CPQ specific
1401 Cmnd->cmnd[0] == MODE_SELECT )
1403 SESTtype = SCSI_IWE; // data from HBA to Device
1406 SESTtype = SCSI_IRE; // data from Device to HBA
1408 ulStatus = cpqfcTSBuildExchange(
1410 SESTtype, // e.g. Initiator Read Entry (IRE)
1411 &fchs, // we are originator; only use d_id
1412 Cmnd, // Linux SCSI command (with scatter/gather list)
1413 &ExchangeID );// fcController->fcExchanges index, -1 if failed
1415 if( !ulStatus ) // Exchange setup?
1418 if( cpqfcHBAdata->BoardLock )
1420 TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
1421 printk(" @bl! %d, xID %Xh@ ", current->pid, ExchangeID);
1424 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
1427 PCI_TRACEO( ExchangeID, 0xB8)
1428 // submitted to Tach's Outbound Que (ERQ PI incremented)
1429 // waited for completion for ELS type (Login frames issued
1433 // check reason for Exchange not being started - we might
1434 // want to Queue and start later, or fail with error
1436 printk("quecommand: cpqfcTSStartExchange failed: %Xh\n", ulStatus );
1438 } // end good BuildExchange status
1440 else // SEST table probably full -- why? hardware hang?
1442 printk("quecommand: cpqfcTSBuildExchange faild: %Xh\n", ulStatus);
1444 } // end can't do FCP-SCSI target functions
1445 } // end can't find target (FC device)
1447 CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
1450 PCI_TRACEO( (ULONG)Cmnd, 0x9C)
1451 LEAVE("cpqfcTS_queuecommand");
1456 // Entry point for upper Scsi layer intiated abort. Typically
1457 // this is called if the command (for hard disk) fails to complete
1458 // in 30 seconds. This driver intends to complete all disk commands
1459 // within Exchange ".timeOut" seconds (now 7) with target status, or
1460 // in case of ".timeOut" expiration, a DID_SOFT_ERROR which causes
1462 // If any disk commands get the _abort call, except for the case that
1463 // the physical device was removed or unavailable due to hardware
1464 // errors, it should be considered a driver error and reported to
1467 int cpqfcTS_abort(Scsi_Cmnd *Cmnd)
1469 // printk(" cpqfcTS_abort called?? \n");
1473 int cpqfcTS_eh_abort(Scsi_Cmnd *Cmnd)
1476 struct Scsi_Host *HostAdapter = Cmnd->device->host;
1477 // get the pointer to our Scsi layer HBA buffer
1478 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
1479 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1480 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1482 ENTER("cpqfcTS_eh_abort");
1484 Cmnd->result = DID_ABORT <<16; // assume we'll find it
1486 printk(" @Linux _abort Scsi_Cmnd %p ", Cmnd);
1487 // See if we can find a Cmnd pointer that matches...
1488 // The most likely case is we accepted the command
1489 // from Linux Scsi (e.g. ceated a SEST entry) and it
1490 // got lost somehow. If we can't find any reference
1491 // to the passed pointer, we can only presume it
1492 // got completed as far as our driver is concerned.
1493 // If we found it, we will try to abort it through
1494 // common mechanism. If FC ABTS is successful (ACC)
1495 // or is rejected (RJT) by target, we will call
1496 // Scsi "done" quickly. Otherwise, the ABTS will timeout
1497 // and we'll call "done" later.
1499 // Search the SEST exchanges for a matching Cmnd ptr.
1500 for( i=0; i< TACH_SEST_LEN; i++)
1502 if( Exchanges->fcExchange[i].Cmnd == Cmnd )
1506 printk(" x_ID %Xh, type %Xh\n", i, Exchanges->fcExchange[i].type);
1508 Exchanges->fcExchange[i].status = INITIATOR_ABORT; // seconds default
1509 Exchanges->fcExchange[i].timeOut = 10; // seconds default (changed later)
1511 // Since we need to immediately return the aborted Cmnd to Scsi
1512 // upper layers, we can't make future reference to any of its
1513 // fields (e.g the Nexus).
1515 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &i);
1521 if( i >= TACH_SEST_LEN ) // didn't find Cmnd ptr in chip's SEST?
1523 // now search our non-SEST buffers (i.e. Cmnd waiting to
1524 // start on the HBA or waiting to complete with error for retry).
1526 // first check BadTargetCmnd
1527 for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++)
1529 if( cpqfcHBAdata->BadTargetCmnd[i] == Cmnd )
1531 cpqfcHBAdata->BadTargetCmnd[i] = NULL;
1532 printk("in BadTargetCmnd Q\n");
1537 // if not found above...
1539 for( i=0; i < CPQFCTS_REQ_QUEUE_LEN; i++)
1541 if( cpqfcHBAdata->LinkDnCmnd[i] == Cmnd )
1543 cpqfcHBAdata->LinkDnCmnd[i] = NULL;
1544 printk("in LinkDnCmnd Q\n");
1550 for( i=0; i< CPQFCTS_REQ_QUEUE_LEN; i++)
1551 { // find spare slot
1552 if( cpqfcHBAdata->BoardLockCmnd[i] == Cmnd )
1554 cpqfcHBAdata->BoardLockCmnd[i] = NULL;
1555 printk("in BoardLockCmnd Q\n");
1560 Cmnd->result = DID_ERROR <<16; // Hmmm...
1561 printk("Not found! ");
1568 LEAVE("cpqfcTS_eh_abort");
1569 return 0; // (see scsi.h)
1573 // FCP-SCSI Target Device Reset
1574 // See dpANS Fibre Channel Protocol for SCSI
1575 // X3.269-199X revision 12, pg 25
1577 #ifdef SUPPORT_RESET
1579 int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev,
1580 unsigned int reset_flags)
1582 int timeout = 10*HZ;
1587 Scsi_Device * SDpnt;
1589 // FIXME, cpqfcTS_TargetDeviceReset needs to be fixed
1590 // similarly to how the passthrough ioctl was fixed
1591 // around the 2.5.30 kernel. Scsi_Cmnd replaced with
1592 // Scsi_Request, etc.
1593 // For now, so people don't fall into a hole...
1595 // printk(" ENTERING cpqfcTS_TargetDeviceReset() - flag=%d \n",reset_flags);
1597 if (ScsiDev->host->eh_active) return FAILED;
1599 memset( scsi_cdb, 0, sizeof( scsi_cdb));
1601 scsi_cdb[0] = RELEASE;
1603 SCpnt = scsi_get_command(ScsiDev, GFP_KERNEL);
1605 CPQFC_DECLARE_COMPLETION(wait);
1607 SCpnt->SCp.buffers_residual = FCP_TARGET_RESET;
1609 // FIXME: this would panic, SCpnt->request would be NULL.
1610 SCpnt->request->CPQFC_WAITING = &wait;
1611 scsi_do_cmd(SCpnt, scsi_cdb, NULL, 0, my_ioctl_done, timeout, retries);
1612 CPQFC_WAIT_FOR_COMPLETION(&wait);
1613 SCpnt->request->CPQFC_WAITING = NULL;
1617 if(driver_byte(SCpnt->result) != 0)
1618 switch(SCpnt->sense_buffer[2] & 0xf) {
1619 case ILLEGAL_REQUEST:
1620 if(cmd[0] == ALLOW_MEDIUM_REMOVAL) dev->lockable = 0;
1621 else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n");
1623 case NOT_READY: // This happens if there is no disc in drive
1624 if(dev->removable && (cmd[0] != TEST_UNIT_READY)){
1625 printk(KERN_INFO "Device not ready. Make sure there is a disc in the drive.\n");
1628 case UNIT_ATTENTION:
1629 if (dev->removable){
1631 SCpnt->result = 0; // This is no longer considered an error
1632 // gag this error, VFS will log it anyway /axboe
1633 // printk(KERN_INFO "Disc change detected.\n");
1636 default: // Fall through for non-removable media
1637 printk("SCSI error: host %d id %d lun %d return code = %x\n",
1642 printk("\tSense class %x, sense error %x, extended sense %x\n",
1643 sense_class(SCpnt->sense_buffer[0]),
1644 sense_error(SCpnt->sense_buffer[0]),
1645 SCpnt->sense_buffer[2] & 0xf);
1648 result = SCpnt->result;
1650 SDpnt = SCpnt->device;
1651 scsi_put_command(SCpnt);
1654 // printk(" LEAVING cpqfcTS_TargetDeviceReset() - return SUCCESS \n");
1659 int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev,
1660 unsigned int reset_flags)
1665 #endif /* SUPPORT_RESET */
1667 int cpqfcTS_eh_device_reset(Scsi_Cmnd *Cmnd)
1670 Scsi_Device *SDpnt = Cmnd->device;
1671 // printk(" ENTERING cpqfcTS_eh_device_reset() \n");
1672 spin_unlock_irq(Cmnd->device->host->host_lock);
1673 retval = cpqfcTS_TargetDeviceReset( SDpnt, 0);
1674 spin_lock_irq(Cmnd->device->host->host_lock);
1679 int cpqfcTS_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags)
1682 ENTER("cpqfcTS_reset");
1684 LEAVE("cpqfcTS_reset");
1685 return SCSI_RESET_ERROR; /* Bus Reset Not supported */
1688 /* This function determines the bios parameters for a given
1689 harddisk. These tend to be numbers that are made up by the
1690 host adapter. Parameters:
1691 size, device number, list (heads, sectors,cylinders).
1695 int cpqfcTS_biosparam(struct scsi_device *sdev, struct block_device *n,
1696 sector_t capacity, int ip[])
1698 int size = capacity;
1700 ENTER("cpqfcTS_biosparam");
1709 ip[2] = size / (ip[0] * ip[1]);
1712 LEAVE("cpqfcTS_biosparam");
1718 irqreturn_t cpqfcTS_intr_handler( int irq,
1720 struct pt_regs *regs)
1723 unsigned long flags, InfLoopBrk=0;
1724 struct Scsi_Host *HostAdapter = dev_id;
1725 CPQFCHBA *cpqfcHBA = (CPQFCHBA *)HostAdapter->hostdata;
1726 int MoreMessages = 1; // assume we have something to do
1730 ENTER("intr_handler");
1731 spin_lock_irqsave( HostAdapter->host_lock, flags);
1733 IntPending = readb( cpqfcHBA->fcChip.Registers.INTPEND.address);
1735 // broken boards can generate messages forever, so
1736 // prevent the infinite loop
1737 #define INFINITE_IMQ_BREAK 10000
1741 // mask our HBA interrupts until we handle it...
1742 writeb( 0, cpqfcHBA->fcChip.Registers.INTEN.address);
1744 if( IntPending & 0x4) // "INT" - Tach wrote to IMQ
1746 while( (++InfLoopBrk < INFINITE_IMQ_BREAK) && (MoreMessages ==1) )
1748 MoreMessages = CpqTsProcessIMQEntry( HostAdapter); // ret 0 when done
1750 if( InfLoopBrk >= INFINITE_IMQ_BREAK )
1752 printk("WARNING: Compaq FC adapter generating excessive INTs -REPLACE\n");
1753 printk("or investigate alternate causes (e.g. physical FC layer)\n");
1756 else // working normally - re-enable INTs and continue
1757 writeb( 0x1F, cpqfcHBA->fcChip.Registers.INTEN.address);
1759 } // (...ProcessIMQEntry() clears INT by writing IMQ consumer)
1760 else // indications of errors or problems...
1761 // these usually indicate critical system hardware problems.
1763 if( IntPending & 0x10 )
1764 printk(" cpqfcTS adapter external memory parity error detected\n");
1765 if( IntPending & 0x8 )
1766 printk(" cpqfcTS adapter PCI master address crossed 45-bit boundary\n");
1767 if( IntPending & 0x2 )
1768 printk(" cpqfcTS adapter DMA error detected\n");
1769 if( IntPending & 0x1 ) {
1771 printk(" cpqfcTS adapter PCI error detected\n");
1772 IntStat = readb( cpqfcHBA->fcChip.Registers.INTSTAT.address);
1773 printk("cpqfc: ISR = 0x%02x\n", IntStat);
1774 if (IntStat & 0x1) {
1776 /* read the pci status register */
1777 pci_read_config_word(cpqfcHBA->PciDev, 0x06, &pcistat);
1778 printk("PCI status register is 0x%04x\n", pcistat);
1779 if (pcistat & 0x8000) printk("Parity Error Detected.\n");
1780 if (pcistat & 0x4000) printk("Signalled System Error\n");
1781 if (pcistat & 0x2000) printk("Received Master Abort\n");
1782 if (pcistat & 0x1000) printk("Received Target Abort\n");
1783 if (pcistat & 0x0800) printk("Signalled Target Abort\n");
1785 if (IntStat & 0x4) printk("(INT)\n");
1787 printk("CRS: PCI master address crossed 46 bit bouandary\n");
1788 if (IntStat & 0x10) printk("MRE: external memory parity error.\n");
1792 spin_unlock_irqrestore( HostAdapter->host_lock, flags);
1793 LEAVE("intr_handler");
1794 return IRQ_RETVAL(handled);
1800 int cpqfcTSDecodeGBICtype( PTACHYON fcChip, char cErrorString[])
1802 // Verify GBIC type (if any) and correct Tachyon Port State Machine
1803 // (GBIC) module definition is:
1804 // GPIO1, GPIO0, GPIO4 for MD2, MD1, MD0. The input states appear
1805 // to be inverted -- i.e., a setting of 111 is read when there is NO
1806 // GBIC present. The Module Def (MD) spec says 000 is "no GBIC"
1807 // Hard code the bit states to detect Copper,
1808 // Long wave (single mode), Short wave (multi-mode), and absent GBIC
1812 sprintf( cErrorString, "\nGBIC detected: ");
1814 ulBuff = fcChip->Registers.TYstatus.value & 0x13;
1817 case 0x13: // GPIO4, GPIO1, GPIO0 = 111; no GBIC!
1818 sprintf( &cErrorString[ strlen( cErrorString)],
1823 case 0x11: // Copper GBIC detected
1824 sprintf( &cErrorString[ strlen( cErrorString)],
1828 case 0x10: // Long-wave (single mode) GBIC detected
1829 sprintf( &cErrorString[ strlen( cErrorString)],
1832 case 0x1: // Short-wave (multi mode) GBIC detected
1833 sprintf( &cErrorString[ strlen( cErrorString)],
1836 default: // unknown GBIC - presumably it will work (?)
1837 sprintf( &cErrorString[ strlen( cErrorString)],
1841 } // end switch GBIC detection
1851 int cpqfcTSGetLPSM( PTACHYON fcChip, char cErrorString[])
1853 // Tachyon's Frame Manager LPSM in LinkDown state?
1854 // (For non-loop port, check PSM instead.)
1855 // return string with state and FALSE is Link Down
1859 if( fcChip->Registers.FMstatus.value & 0x80 )
1864 sprintf( &cErrorString[ strlen( cErrorString)],
1866 (fcChip->Registers.FMstatus.value >>4) & 0xf );
1869 switch( fcChip->Registers.FMstatus.value & 0xF0)
1873 sprintf( &cErrorString[ strlen( cErrorString)], "ARB");
1876 sprintf( &cErrorString[ strlen( cErrorString)], "ARBwon");
1879 sprintf( &cErrorString[ strlen( cErrorString)], "OPEN");
1882 sprintf( &cErrorString[ strlen( cErrorString)], "OPENed");
1885 sprintf( &cErrorString[ strlen( cErrorString)], "XmitCLS");
1888 sprintf( &cErrorString[ strlen( cErrorString)], "RxCLS");
1891 sprintf( &cErrorString[ strlen( cErrorString)], "Xfer");
1894 sprintf( &cErrorString[ strlen( cErrorString)], "Init");
1897 sprintf( &cErrorString[ strlen( cErrorString)], "O-IInitFin");
1900 sprintf( &cErrorString[ strlen( cErrorString)], "O-IProtocol");
1903 sprintf( &cErrorString[ strlen( cErrorString)], "O-ILipRcvd");
1906 sprintf( &cErrorString[ strlen( cErrorString)], "HostControl");
1909 sprintf( &cErrorString[ strlen( cErrorString)], "LoopFail");
1912 sprintf( &cErrorString[ strlen( cErrorString)], "Offline");
1915 sprintf( &cErrorString[ strlen( cErrorString)], "OldPort");
1919 sprintf( &cErrorString[ strlen( cErrorString)], "Monitor");
1930 #include "linux/slab.h"
1932 // Dynamic memory allocation alignment routines
1933 // HP's Tachyon Fibre Channel Controller chips require
1934 // certain memory queues and register pointers to be aligned
1935 // on various boundaries, usually the size of the Queue in question.
1936 // Alignment might be on 2, 4, 8, ... or even 512 byte boundaries.
1937 // Since most O/Ss don't allow this (usually only Cache aligned -
1938 // 32-byte boundary), these routines provide generic alignment (after
1939 // O/S allocation) at any boundary, and store the original allocated
1940 // pointer for deletion (O/S free function). Typically, we expect
1941 // these functions to only be called at HBA initialization and
1942 // removal time (load and unload times)
1944 // Memory allocation varies by compiler and platform. In the worst case,
1945 // we are only assured BYTE alignment, but in the best case, we can
1946 // request allocation on any desired boundary. Our strategy: pad the
1947 // allocation request size (i.e. waste memory) so that we are assured
1948 // of passing desired boundary near beginning of contiguous space, then
1949 // mask out lower address bits.
1950 // We define the following algorithm:
1951 // allocBoundary - compiler/platform specific address alignment
1952 // in number of bytes (default is single byte; i.e. 1)
1953 // n_alloc - number of bytes application wants @ aligned address
1954 // ab - alignment boundary, in bytes (e.g. 4, 32, ...)
1955 // t_alloc - total allocation needed to ensure desired boundary
1956 // mask - to clear least significant address bits for boundary
1958 // t_alloc = n_alloc + (ab - allocBoundary)
1959 // allocate t_alloc bytes @ alloc_address
1960 // mask = NOT (ab - 1)
1961 // (e.g. if ab=32 _0001 1111 -> _1110 0000
1962 // aligned_address = alloc_address & mask
1963 // set n_alloc bytes to 0
1964 // return aligned_address (NULL if failed)
1966 // If u32_AlignedAddress is non-zero, then search for BaseAddress (stored
1967 // from previous allocation). If found, invoke call to FREE the memory.
1968 // Return NULL if BaseAddress not found
1970 // we need about 8 allocations per HBA. Figuring at most 10 HBAs per server
1971 // size the dynamic_mem array at 80.
1973 void* fcMemManager( struct pci_dev *pdev, ALIGNED_MEM *dynamic_mem,
1974 ULONG n_alloc, ULONG ab, ULONG u32_AlignedAddress,
1975 dma_addr_t *dma_handle)
1977 USHORT allocBoundary=1; // compiler specific - worst case 1
1978 // best case - replace malloc() call
1979 // with function that allocates exactly
1980 // at desired boundary
1982 unsigned long ulAddress;
1984 void *alloc_address = 0; // def. error code / address not found
1985 LONG mask; // must be 32-bits wide!
1987 ENTER("fcMemManager");
1988 if( u32_AlignedAddress ) // are we freeing existing memory?
1990 // printk(" freeing AlignedAddress %Xh\n", u32_AlignedAddress);
1991 for( i=0; i<DYNAMIC_ALLOCATIONS; i++) // look for the base address
1993 // printk("dynamic_mem[%u].AlignedAddress %lX\n", i, dynamic_mem[i].AlignedAddress);
1994 if( dynamic_mem[i].AlignedAddress == u32_AlignedAddress )
1996 alloc_address = dynamic_mem[i].BaseAllocated; // 'success' status
1997 pci_free_consistent(pdev,dynamic_mem[i].size,
1999 dynamic_mem[i].dma_handle);
2000 dynamic_mem[i].BaseAllocated = 0; // clear for next use
2001 dynamic_mem[i].AlignedAddress = 0;
2002 dynamic_mem[i].size = 0;
2003 break; // quit for loop; done
2007 else if( n_alloc ) // want new memory?
2010 t_alloc = n_alloc + (ab - allocBoundary); // pad bytes for alignment
2011 // printk("pci_alloc_consistent() for Tach alignment: %ld bytes\n", t_alloc);
2013 // (would like to) allow thread block to free pages
2014 alloc_address = // total bytes (NumberOfBytes)
2015 pci_alloc_consistent(pdev, t_alloc, &handle);
2017 // now mask off least sig. bits of address
2018 if( alloc_address ) // (only if non-NULL)
2020 // find place to store ptr, so we
2021 // can free it later...
2023 mask = (LONG)(ab - 1); // mask all low-order bits
2024 mask = ~mask; // invert bits
2025 for( i=0; i<DYNAMIC_ALLOCATIONS; i++) // look for free slot
2027 if( dynamic_mem[i].BaseAllocated == 0) // take 1st available
2029 dynamic_mem[i].BaseAllocated = alloc_address;// address from O/S
2030 dynamic_mem[i].dma_handle = handle;
2031 if (dma_handle != NULL)
2033 // printk("handle = %p, ab=%d, boundary = %d, mask=0x%08x\n",
2034 // handle, ab, allocBoundary, mask);
2035 *dma_handle = (dma_addr_t)
2036 ((((ULONG)handle) + (ab - allocBoundary)) & mask);
2038 dynamic_mem[i].size = t_alloc;
2042 ulAddress = (unsigned long)alloc_address;
2044 ulAddress += (ab - allocBoundary); // add the alignment bytes-
2045 // then truncate address...
2046 alloc_address = (void*)(ulAddress & mask);
2048 dynamic_mem[i].AlignedAddress =
2049 (ULONG)(ulAddress & mask); // 32bit Tach address
2050 memset( alloc_address, 0, n_alloc ); // clear new memory
2052 else // O/S dynamic mem alloc failed!
2053 alloc_address = 0; // (for debugging breakpt)
2057 LEAVE("fcMemManager");
2058 return alloc_address; // good (or NULL) address
2062 static Scsi_Host_Template driver_template = {
2063 .detect = cpqfcTS_detect,
2064 .release = cpqfcTS_release,
2065 .info = cpqfcTS_info,
2066 .proc_info = cpqfcTS_proc_info,
2067 .ioctl = cpqfcTS_ioctl,
2068 .queuecommand = cpqfcTS_queuecommand,
2069 .eh_device_reset_handler = cpqfcTS_eh_device_reset,
2070 .eh_abort_handler = cpqfcTS_eh_abort,
2071 .bios_param = cpqfcTS_biosparam,
2072 .can_queue = CPQFCTS_REQ_QUEUE_LEN,
2074 .sg_tablesize = SG_ALL,
2075 .cmd_per_lun = CPQFCTS_CMD_PER_LUN,
2076 .use_clustering = ENABLE_CLUSTERING,
2078 #include "scsi_module.c"