aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/cpqfcTSinit.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/cpqfcTSinit.c')
-rw-r--r--drivers/scsi/cpqfcTSinit.c2096
1 files changed, 0 insertions, 2096 deletions
diff --git a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c
deleted file mode 100644
index 3fda8d455c5b..000000000000
--- a/drivers/scsi/cpqfcTSinit.c
+++ /dev/null
@@ -1,2096 +0,0 @@
1/* Copyright(c) 2000, Compaq Computer Corporation
2 * Fibre Channel Host Bus Adapter
3 * 64-bit, 66MHz PCI
4 * Originally developed and tested on:
5 * (front): [chip] Tachyon TS HPFC-5166A/1.2 L2C1090 ...
6 * SP# P225CXCBFIEL6T, Rev XC
7 * SP# 161290-001, Rev XD
8 * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2, or (at your option) any
13 * later version.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 * Written by Don Zimmerman
20 * 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#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
33
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>
48
49#include <asm/io.h>
50#include <asm/uaccess.h> // ioctl related
51#include <asm/irq.h>
52#include <linux/spinlock.h>
53#include "scsi.h"
54#include <scsi/scsi_host.h>
55#include <scsi/scsi_ioctl.h>
56#include "cpqfcTSchip.h"
57#include "cpqfcTSstructs.h"
58#include "cpqfcTStrigger.h"
59
60#include "cpqfcTS.h"
61
62/* Embedded module documentation macros - see module.h */
63MODULE_AUTHOR("Compaq Computer Corporation");
64MODULE_DESCRIPTION("Driver for Compaq 64-bit/66Mhz PCI Fibre Channel HBA v. 2.5.4");
65MODULE_LICENSE("GPL");
66
67int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, unsigned int reset_flags);
68
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
72// few fields...
73// NOTE: proc_fs changes in 2.4 kernel
74
75#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
76static struct proc_dir_entry proc_scsi_cpqfcTS =
77{
78 PROC_SCSI_CPQFCTS, // ushort low_ino (enumerated list)
79 7, // ushort namelen
80 DEV_NAME, // const char* name
81 S_IFDIR | S_IRUGO | S_IXUGO, // mode_t mode
82 2 // nlink_t nlink
83 // etc. ...
84};
85
86
87#endif
88
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);
94#else
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)
99#endif
100
101static int cpqfc_alloc_private_data_pool(CPQFCHBA *hba);
102
103/* local function to load our per-HBA (local) data for chip
104 registers, FC link state, all FC exchanges, etc.
105
106 We allocate space and compute address offsets for the
107 most frequently accessed addresses; others (like World Wide
108 Name) are not necessary.
109*/
110static void Cpqfc_initHBAdata(CPQFCHBA *cpqfcHBAdata, struct pci_dev *PciDev )
111{
112
113 cpqfcHBAdata->PciDev = PciDev; // copy PCI info ptr
114
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;
118
119 cpqfcHBAdata->fcChip.Registers.IOBaseU =
120 PciDev->resource[2].start & PCI_BASE_ADDRESS_IO_MASK;
121
122 // 32-bit memory addresses
123 cpqfcHBAdata->fcChip.Registers.MemBase =
124 PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK;
125
126 cpqfcHBAdata->fcChip.Registers.ReMapMemBase =
127 ioremap( PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK,
128 0x200);
129
130 cpqfcHBAdata->fcChip.Registers.RAMBase =
131 PciDev->resource[4].start;
132
133 cpqfcHBAdata->fcChip.Registers.SROMBase = // NULL for HP TS adapter
134 PciDev->resource[5].start;
135
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)
139
140 cpqfcHBAdata->fcChip.Registers.SFQconsumerIndex.address =
141 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_SFQ_CONSUMER_INDEX;
142
143 cpqfcHBAdata->fcChip.Registers.ERQproducerIndex.address =
144 cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_ERQ_PRODUCER_INDEX;
145
146 // TL Frame Manager
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;
159
160 // TL Control Regs
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;
171
172
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;
179
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));
185
186 /* printk(" ioremap'd Membase: %p\n", cpqfcHBAdata->fcChip.Registers.ReMapMemBase); */
187
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));
198
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
204
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;
209
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;
222
223 if (cpqfc_alloc_private_data_pool(cpqfcHBAdata) != 0) {
224 printk(KERN_WARNING
225 "cpqfc: unable to allocate pool for passthru ioctls. "
226 "Passthru ioctls disabled.\n");
227 }
228}
229
230
231/* (borrowed from linux/drivers/scsi/hosts.c) */
232static void launch_FCworker_thread(struct Scsi_Host *HostAdapter)
233{
234 DECLARE_MUTEX_LOCKED(sem);
235
236 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
237
238 ENTER("launch_FC_worker_thread");
239
240 cpqfcHBAdata->notify_wt = &sem;
241
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);
246 /*
247 * Now wait for the kernel error thread to initialize itself
248
249 */
250 down (&sem);
251 spin_lock_irq(HostAdapter->host_lock);
252 cpqfcHBAdata->notify_wt = NULL;
253
254 LEAVE("launch_FC_worker_thread");
255
256}
257
258
259/* "Entry" point to discover if any supported PCI
260 bus adapter can be found
261*/
262/* We're supporting:
263 * Compaq 64-bit, 66MHz HBA with Tachyon TS
264 * Agilent XL2
265 * HP Tachyon
266 */
267#define HBA_TYPES 3
268
269#ifndef PCI_DEVICE_ID_COMPAQ_
270#define PCI_DEVICE_ID_COMPAQ_TACHYON 0xa0fc
271#endif
272
273static 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},
277};
278
279
280int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate)
281{
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;
287 int i;
288
289 ENTER("cpqfcTS_detect");
290
291#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
292 ScsiHostTemplate->proc_dir = &proc_scsi_cpqfcTS;
293#else
294 ScsiHostTemplate->proc_name = "cpqfcTS";
295#endif
296
297 for( i=0; i < HBA_TYPES; i++)
298 {
299 // look for all HBAs of each type
300
301 while((PciDev = pci_find_device(cpqfc_boards[i].vendor_id,
302 cpqfc_boards[i].device_id, PciDev)))
303 {
304
305 if (pci_enable_device(PciDev)) {
306 printk(KERN_ERR
307 "cpqfc: can't enable PCI device at %s\n", pci_name(PciDev));
308 goto err_continue;
309 }
310
311 if (pci_set_dma_mask(PciDev, CPQFCTS_DMA_MASK) != 0) {
312 printk(KERN_WARNING
313 "cpqfc: HBA cannot support required DMA mask, skipping.\n");
314 goto err_disable_dev;
315 }
316
317 // NOTE: (kernel 2.2.12-32) limits allocation to 128k bytes...
318 /* printk(" scsi_register allocating %d bytes for FC HBA\n",
319 (ULONG)sizeof(CPQFCHBA)); */
320
321 HostAdapter = scsi_register( ScsiHostTemplate, sizeof( CPQFCHBA ) );
322
323 if(HostAdapter == NULL) {
324 printk(KERN_WARNING
325 "cpqfc: can't register SCSI HBA, skipping.\n");
326 goto err_disable_dev;
327 }
328 DEBUG_PCI( printk(" HBA found!\n"));
329 DEBUG_PCI( printk(" HostAdapter->PciDev->irq = %u\n", PciDev->irq) );
330 DEBUG_PCI(printk(" PciDev->baseaddress[0]= %lx\n",
331 PciDev->resource[0].start));
332 DEBUG_PCI(printk(" PciDev->baseaddress[1]= %lx\n",
333 PciDev->resource[1].start));
334 DEBUG_PCI(printk(" PciDev->baseaddress[2]= %lx\n",
335 PciDev->resource[2].start));
336 DEBUG_PCI(printk(" PciDev->baseaddress[3]= %lx\n",
337 PciDev->resource[3].start));
338
339 HostAdapter->irq = PciDev->irq; // copy for Scsi layers
340
341 // HP Tachlite uses two (255-byte) ranges of Port I/O (lower & upper),
342 // for a total I/O port address space of 512 bytes.
343 // mask out the I/O port address (lower) & record
344 HostAdapter->io_port = (unsigned int)
345 PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
346 HostAdapter->n_io_port = 0xff;
347
348 // i.e., expect 128 targets (arbitrary number), while the
349 // RA-4000 supports 32 LUNs
350 HostAdapter->max_id = 0; // incremented as devices log in
351 HostAdapter->max_lun = CPQFCTS_MAX_LUN; // LUNs per FC device
352 HostAdapter->max_channel = CPQFCTS_MAX_CHANNEL; // multiple busses?
353
354 // get the pointer to our HBA specific data... (one for
355 // each HBA on the PCI bus(ses)).
356 cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
357
358 // make certain our data struct is clear
359 memset( cpqfcHBAdata, 0, sizeof( CPQFCHBA ) );
360
361
362 // initialize our HBA info
363 cpqfcHBAdata->HBAnum = NumberOfAdapters;
364
365 cpqfcHBAdata->HostAdapter = HostAdapter; // back ptr
366 Cpqfc_initHBAdata( cpqfcHBAdata, PciDev ); // fill MOST fields
367
368 cpqfcHBAdata->HBAnum = NumberOfAdapters;
369 spin_lock_init(&cpqfcHBAdata->hba_spinlock);
370
371 // request necessary resources and check for conflicts
372 if( request_irq( HostAdapter->irq,
373 cpqfcTS_intr_handler,
374 SA_INTERRUPT | SA_SHIRQ,
375 DEV_NAME,
376 HostAdapter) )
377 {
378 printk(KERN_WARNING "cpqfc: IRQ %u already used\n", HostAdapter->irq);
379 goto err_unregister;
380 }
381
382 // Since we have two 256-byte I/O port ranges (upper
383 // and lower), check them both
384 if( !request_region( cpqfcHBAdata->fcChip.Registers.IOBaseU,
385 0xff, DEV_NAME ) )
386 {
387 printk(KERN_WARNING "cpqfc: address in use: %x\n",
388 cpqfcHBAdata->fcChip.Registers.IOBaseU);
389 goto err_free_irq;
390 }
391
392 if( !request_region( cpqfcHBAdata->fcChip.Registers.IOBaseL,
393 0xff, DEV_NAME ) )
394 {
395 printk(KERN_WARNING "cpqfc: address in use: %x\n",
396 cpqfcHBAdata->fcChip.Registers.IOBaseL);
397 goto err_release_region_U;
398 }
399
400 // OK, we have grabbed everything we need now.
401 DEBUG_PCI(printk(" Reserved 255 I/O addresses @ %x\n",
402 cpqfcHBAdata->fcChip.Registers.IOBaseL ));
403 DEBUG_PCI(printk(" Reserved 255 I/O addresses @ %x\n",
404 cpqfcHBAdata->fcChip.Registers.IOBaseU ));
405
406
407
408 // start our kernel worker thread
409
410 spin_lock_irq(HostAdapter->host_lock);
411 launch_FCworker_thread(HostAdapter);
412
413
414 // start our TimerTask...
415
416 cpqfcTStimer = &cpqfcHBAdata->cpqfcTStimer;
417
418 init_timer( cpqfcTStimer); // Linux clears next/prev values
419 cpqfcTStimer->expires = jiffies + HZ; // one second
420 cpqfcTStimer->data = (unsigned long)cpqfcHBAdata; // this adapter
421 cpqfcTStimer->function = cpqfcTSheartbeat; // handles timeouts, housekeeping
422
423 add_timer( cpqfcTStimer); // give it to Linux
424
425
426 // now initialize our hardware...
427 if (cpqfcHBAdata->fcChip.InitializeTachyon( cpqfcHBAdata, 1,1)) {
428 printk(KERN_WARNING "cpqfc: initialization of HBA hardware failed.\n");
429 goto err_release_region_L;
430 }
431
432 cpqfcHBAdata->fcStatsTime = jiffies; // (for FC Statistics delta)
433
434 // give our HBA time to initialize and login current devices...
435 {
436 // The Brocade switch (e.g. 2400, 2010, etc.) as of March 2000,
437 // has the following algorithm for FL_Port startup:
438 // Time(sec) Action
439 // 0: Device Plugin and LIP(F7,F7) transmission
440 // 1.0 LIP incoming
441 // 1.027 LISA incoming, no CLS! (link not up)
442 // 1.028 NOS incoming (switch test for N_Port)
443 // 1.577 ED_TOV expired, transmit LIPs again
444 // 3.0 LIP(F8,F7) incoming (switch passes Tach Prim.Sig)
445 // 3.028 LILP received, link up, FLOGI starts
446 // slowest(worst) case, measured on 1Gb Finisar GT analyzer
447
448 unsigned long stop_time;
449
450 spin_unlock_irq(HostAdapter->host_lock);
451 stop_time = jiffies + 4*HZ;
452 while ( time_before(jiffies, stop_time) )
453 schedule(); // (our worker task needs to run)
454
455 }
456
457 spin_lock_irq(HostAdapter->host_lock);
458 NumberOfAdapters++;
459 spin_unlock_irq(HostAdapter->host_lock);
460
461 continue;
462
463err_release_region_L:
464 release_region( cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff );
465err_release_region_U:
466 release_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff );
467err_free_irq:
468 free_irq( HostAdapter->irq, HostAdapter);
469err_unregister:
470 scsi_unregister( HostAdapter);
471err_disable_dev:
472 pci_disable_device( PciDev );
473err_continue:
474 continue;
475 } // end of while()
476 }
477
478 LEAVE("cpqfcTS_detect");
479
480 return NumberOfAdapters;
481}
482
483#ifdef SUPPORT_RESET
484static void my_ioctl_done (Scsi_Cmnd * SCpnt)
485{
486 struct request * req;
487
488 req = SCpnt->request;
489 req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */
490
491 if (req->CPQFC_WAITING != NULL)
492 CPQFC_COMPLETE(req->CPQFC_WAITING);
493}
494#endif
495
496static int cpqfc_alloc_private_data_pool(CPQFCHBA *hba)
497{
498 hba->private_data_bits = NULL;
499 hba->private_data_pool = NULL;
500 hba->private_data_bits =
501 kmalloc(((CPQFC_MAX_PASSTHRU_CMDS+BITS_PER_LONG-1) /
502 BITS_PER_LONG)*sizeof(unsigned long),
503 GFP_KERNEL);
504 if (hba->private_data_bits == NULL)
505 return -1;
506 memset(hba->private_data_bits, 0,
507 ((CPQFC_MAX_PASSTHRU_CMDS+BITS_PER_LONG-1) /
508 BITS_PER_LONG)*sizeof(unsigned long));
509 hba->private_data_pool = kmalloc(sizeof(cpqfc_passthru_private_t) *
510 CPQFC_MAX_PASSTHRU_CMDS, GFP_KERNEL);
511 if (hba->private_data_pool == NULL) {
512 kfree(hba->private_data_bits);
513 hba->private_data_bits = NULL;
514 return -1;
515 }
516 return 0;
517}
518
519static void cpqfc_free_private_data_pool(CPQFCHBA *hba)
520{
521 kfree(hba->private_data_bits);
522 kfree(hba->private_data_pool);
523}
524
525int is_private_data_of_cpqfc(CPQFCHBA *hba, void *pointer)
526{
527 /* Is pointer within our private data pool?
528 We use Scsi_Request->upper_private_data (normally
529 reserved for upper layer drivers, e.g. the sg driver)
530 We check to see if the pointer is ours by looking at
531 its address. Is this ok? Hmm, it occurs to me that
532 a user app might do something bad by using sg to send
533 a cpqfc passthrough ioctl with upper_data_private
534 forged to be somewhere in our pool..., though they'd
535 normally have to be root already to do this. */
536
537 return (pointer != NULL &&
538 pointer >= (void *) hba->private_data_pool &&
539 pointer < (void *) hba->private_data_pool +
540 sizeof(*hba->private_data_pool) *
541 CPQFC_MAX_PASSTHRU_CMDS);
542}
543
544cpqfc_passthru_private_t *cpqfc_alloc_private_data(CPQFCHBA *hba)
545{
546 int i;
547
548 do {
549 i = find_first_zero_bit(hba->private_data_bits,
550 CPQFC_MAX_PASSTHRU_CMDS);
551 if (i == CPQFC_MAX_PASSTHRU_CMDS)
552 return NULL;
553 } while ( test_and_set_bit(i & (BITS_PER_LONG - 1),
554 hba->private_data_bits+(i/BITS_PER_LONG)) != 0);
555 return &hba->private_data_pool[i];
556}
557
558void cpqfc_free_private_data(CPQFCHBA *hba, cpqfc_passthru_private_t *data)
559{
560 int i;
561 i = data - hba->private_data_pool;
562 clear_bit(i&(BITS_PER_LONG-1),
563 hba->private_data_bits+(i/BITS_PER_LONG));
564}
565
566int cpqfcTS_ioctl( struct scsi_device *ScsiDev, int Cmnd, void *arg)
567{
568 int result = 0;
569 struct Scsi_Host *HostAdapter = ScsiDev->host;
570 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
571 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
572 PFC_LOGGEDIN_PORT pLoggedInPort = NULL;
573 struct scsi_cmnd *DumCmnd;
574 int i, j;
575 VENDOR_IOCTL_REQ ioc;
576 cpqfc_passthru_t *vendor_cmd;
577 Scsi_Device *SDpnt;
578 Scsi_Request *ScsiPassThruReq;
579 cpqfc_passthru_private_t *privatedata;
580
581 ENTER("cpqfcTS_ioctl ");
582
583 // printk("ioctl CMND %d", Cmnd);
584 switch (Cmnd) {
585 // Passthrough provides a mechanism to bypass the RAID
586 // or other controller and talk directly to the devices
587 // (e.g. physical disk drive)
588 // Passthrough commands, unfortunately, tend to be vendor
589 // specific; this is tailored to COMPAQ's RAID (RA4x00)
590 case CPQFCTS_SCSI_PASSTHRU:
591 {
592 void *buf = NULL; // for kernel space buffer for user data
593
594 /* Check that our pool got allocated ok. */
595 if (cpqfcHBAdata->private_data_pool == NULL)
596 return -ENOMEM;
597
598 if( !arg)
599 return -EINVAL;
600
601 // must be super user to send stuff directly to the
602 // controller and/or physical drives...
603 if( !capable(CAP_SYS_RAWIO) )
604 return -EPERM;
605
606 // copy the caller's struct to our space.
607 if( copy_from_user( &ioc, arg, sizeof( VENDOR_IOCTL_REQ)))
608 return( -EFAULT);
609
610 vendor_cmd = ioc.argp; // i.e., CPQ specific command struct
611
612 // If necessary, grab a kernel/DMA buffer
613 if( vendor_cmd->len)
614 {
615 buf = kmalloc( vendor_cmd->len, GFP_KERNEL);
616 if( !buf)
617 return -ENOMEM;
618 }
619 // Now build a Scsi_Request to pass down...
620 ScsiPassThruReq = scsi_allocate_request(ScsiDev, GFP_KERNEL);
621 if (ScsiPassThruReq == NULL) {
622 kfree(buf);
623 return -ENOMEM;
624 }
625 ScsiPassThruReq->upper_private_data =
626 cpqfc_alloc_private_data(cpqfcHBAdata);
627 if (ScsiPassThruReq->upper_private_data == NULL) {
628 kfree(buf);
629 scsi_release_request(ScsiPassThruReq); // "de-allocate"
630 return -ENOMEM;
631 }
632
633 if (vendor_cmd->rw_flag == VENDOR_WRITE_OPCODE) {
634 if (vendor_cmd->len) { // Need data from user?
635 if (copy_from_user(buf, vendor_cmd->bufp,
636 vendor_cmd->len)) {
637 kfree(buf);
638 cpqfc_free_private_data(cpqfcHBAdata,
639 ScsiPassThruReq->upper_private_data);
640 scsi_release_request(ScsiPassThruReq);
641 return( -EFAULT);
642 }
643 }
644 ScsiPassThruReq->sr_data_direction = DMA_TO_DEVICE;
645 } else if (vendor_cmd->rw_flag == VENDOR_READ_OPCODE) {
646 ScsiPassThruReq->sr_data_direction = DMA_FROM_DEVICE;
647 } else
648 // maybe this means a bug in the user app
649 ScsiPassThruReq->sr_data_direction = DMA_BIDIRECTIONAL;
650
651 ScsiPassThruReq->sr_cmd_len = 0; // set correctly by scsi_do_req()
652 ScsiPassThruReq->sr_sense_buffer[0] = 0;
653 ScsiPassThruReq->sr_sense_buffer[2] = 0;
654
655 // We copy the scheme used by sd.c:spinup_disk() to submit commands
656 // to our own HBA. We do this in order to stall the
657 // thread calling the IOCTL until it completes, and use
658 // the same "_quecommand" function for synchronizing
659 // FC Link events with our "worker thread".
660
661 privatedata = ScsiPassThruReq->upper_private_data;
662 privatedata->bus = vendor_cmd->bus;
663 privatedata->pdrive = vendor_cmd->pdrive;
664
665 // eventually gets us to our own _quecommand routine
666 scsi_wait_req(ScsiPassThruReq,
667 &vendor_cmd->cdb[0], buf, vendor_cmd->len,
668 10*HZ, // timeout
669 1); // retries
670 result = ScsiPassThruReq->sr_result;
671
672 // copy any sense data back to caller
673 if( result != 0 )
674 {
675 memcpy( vendor_cmd->sense_data, // see struct def - size=40
676 ScsiPassThruReq->sr_sense_buffer,
677 sizeof(ScsiPassThruReq->sr_sense_buffer) <
678 sizeof(vendor_cmd->sense_data) ?
679 sizeof(ScsiPassThruReq->sr_sense_buffer) :
680 sizeof(vendor_cmd->sense_data)
681 );
682 }
683 SDpnt = ScsiPassThruReq->sr_device;
684 /* upper_private_data is already freed in call_scsi_done() */
685 scsi_release_request(ScsiPassThruReq); // "de-allocate"
686 ScsiPassThruReq = NULL;
687
688 // need to pass data back to user (space)?
689 if( (vendor_cmd->rw_flag == VENDOR_READ_OPCODE) &&
690 vendor_cmd->len )
691 if( copy_to_user( vendor_cmd->bufp, buf, vendor_cmd->len))
692 result = -EFAULT;
693
694 kfree(buf);
695
696 return result;
697 }
698
699 case CPQFCTS_GETPCIINFO:
700 {
701 cpqfc_pci_info_struct pciinfo;
702
703 if( !arg)
704 return -EINVAL;
705
706
707
708 pciinfo.bus = cpqfcHBAdata->PciDev->bus->number;
709 pciinfo.dev_fn = cpqfcHBAdata->PciDev->devfn;
710 pciinfo.board_id = cpqfcHBAdata->PciDev->device |
711 (cpqfcHBAdata->PciDev->vendor <<16);
712
713 if(copy_to_user( arg, &pciinfo, sizeof(cpqfc_pci_info_struct)))
714 return( -EFAULT);
715 return 0;
716 }
717
718 case CPQFCTS_GETDRIVVER:
719 {
720 DriverVer_type DriverVer =
721 CPQFCTS_DRIVER_VER( VER_MAJOR,VER_MINOR,VER_SUBMINOR);
722
723 if( !arg)
724 return -EINVAL;
725
726 if(copy_to_user( arg, &DriverVer, sizeof(DriverVer)))
727 return( -EFAULT);
728 return 0;
729 }
730
731
732
733 case CPQFC_IOCTL_FC_TARGET_ADDRESS:
734 // can we find an FC device mapping to this SCSI target?
735/* DumCmnd.channel = ScsiDev->channel; */ // For searching
736/* DumCmnd.target = ScsiDev->id; */
737/* DumCmnd.lun = ScsiDev->lun; */
738
739 DumCmnd = scsi_get_command (ScsiDev, GFP_KERNEL);
740 if (!DumCmnd)
741 return -ENOMEM;
742
743 pLoggedInPort = fcFindLoggedInPort( fcChip,
744 DumCmnd, // search Scsi Nexus
745 0, // DON'T search linked list for FC port id
746 NULL, // DON'T search linked list for FC WWN
747 NULL); // DON'T care about end of list
748 scsi_put_command (DumCmnd);
749 if (pLoggedInPort == NULL) {
750 result = -ENXIO;
751 break;
752 }
753 result = access_ok(VERIFY_WRITE, arg, sizeof(Scsi_FCTargAddress)) ? 0 : -EFAULT;
754 if (result) break;
755
756 put_user(pLoggedInPort->port_id,
757 &((Scsi_FCTargAddress *) arg)->host_port_id);
758
759 for( i=3,j=0; i>=0; i--) // copy the LOGIN port's WWN
760 put_user(pLoggedInPort->u.ucWWN[i],
761 &((Scsi_FCTargAddress *) arg)->host_wwn[j++]);
762 for( i=7; i>3; i--) // copy the LOGIN port's WWN
763 put_user(pLoggedInPort->u.ucWWN[i],
764 &((Scsi_FCTargAddress *) arg)->host_wwn[j++]);
765 break;
766
767
768 case CPQFC_IOCTL_FC_TDR:
769
770 result = cpqfcTS_TargetDeviceReset( ScsiDev, 0);
771
772 break;
773
774
775
776
777 default:
778 result = -EINVAL;
779 break;
780 }
781
782 LEAVE("cpqfcTS_ioctl");
783 return result;
784}
785
786
787/* "Release" the Host Bus Adapter...
788 disable interrupts, stop the HBA, release the interrupt,
789 and free all resources */
790
791int cpqfcTS_release(struct Scsi_Host *HostAdapter)
792{
793 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
794
795
796 ENTER("cpqfcTS_release");
797
798 DEBUG_PCI( printk(" cpqfcTS: delete timer...\n"));
799 del_timer( &cpqfcHBAdata->cpqfcTStimer);
800
801 // disable the hardware...
802 DEBUG_PCI( printk(" disable hardware, destroy queues, free mem\n"));
803 cpqfcHBAdata->fcChip.ResetTachyon( cpqfcHBAdata, CLEAR_FCPORTS);
804
805 // kill kernel thread
806 if( cpqfcHBAdata->worker_thread ) // (only if exists)
807 {
808 DECLARE_MUTEX_LOCKED(sem); // synchronize thread kill
809
810 cpqfcHBAdata->notify_wt = &sem;
811 DEBUG_PCI( printk(" killing kernel thread\n"));
812 send_sig( SIGKILL, cpqfcHBAdata->worker_thread, 1);
813 down( &sem);
814 cpqfcHBAdata->notify_wt = NULL;
815
816 }
817
818 cpqfc_free_private_data_pool(cpqfcHBAdata);
819 // free Linux resources
820 DEBUG_PCI( printk(" cpqfcTS: freeing resources...\n"));
821 free_irq( HostAdapter->irq, HostAdapter);
822 scsi_unregister( HostAdapter);
823 release_region( cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff);
824 release_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff);
825 /* we get "vfree: bad address" executing this - need to investigate...
826 if( (void*)((unsigned long)cpqfcHBAdata->fcChip.Registers.MemBase) !=
827 cpqfcHBAdata->fcChip.Registers.ReMapMemBase)
828 vfree( cpqfcHBAdata->fcChip.Registers.ReMapMemBase);
829*/
830 pci_disable_device( cpqfcHBAdata->PciDev);
831
832 LEAVE("cpqfcTS_release");
833 return 0;
834}
835
836
837const char * cpqfcTS_info(struct Scsi_Host *HostAdapter)
838{
839 static char buf[300];
840 CPQFCHBA *cpqfcHBA;
841 int BusSpeed, BusWidth;
842
843 // get the pointer to our Scsi layer HBA buffer
844 cpqfcHBA = (CPQFCHBA *)HostAdapter->hostdata;
845
846 BusWidth = (cpqfcHBA->fcChip.Registers.PCIMCTR &0x4) > 0 ?
847 64 : 32;
848
849 if( cpqfcHBA->fcChip.Registers.TYconfig.value & 0x80000000)
850 BusSpeed = 66;
851 else
852 BusSpeed = 33;
853
854 sprintf(buf,
855"%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",
856 cpqfcHBA->fcChip.Name,
857 cpqfcHBA->fcChip.Registers.wwn_hi,
858 cpqfcHBA->fcChip.Registers.wwn_lo,
859 cpqfcHBA->PciDev->bus->number,
860 cpqfcHBA->PciDev->device,
861 HostAdapter->irq,
862 cpqfcHBA->fcChip.Registers.IOBaseL,
863 cpqfcHBA->fcChip.Registers.MemBase,
864 BusWidth,
865 BusSpeed,
866 VER_MAJOR, VER_MINOR, VER_SUBMINOR
867);
868
869
870 cpqfcTSDecodeGBICtype( &cpqfcHBA->fcChip, &buf[ strlen(buf)]);
871 cpqfcTSGetLPSM( &cpqfcHBA->fcChip, &buf[ strlen(buf)]);
872 return buf;
873}
874
875//
876// /proc/scsi support. The following routines allow us to do 'normal'
877// sprintf like calls to return the currently requested piece (buflenght
878// chars, starting at bufoffset) of the file. Although procfs allows for
879// a 1 Kb bytes overflow after te supplied buffer, I consider it bad
880// programming to use it to make programming a little simpler. This piece
881// of coding is borrowed from ncr53c8xx.c with some modifications
882//
883struct info_str
884{
885 char *buffer; // Pointer to output buffer
886 int buflength; // It's length
887 int bufoffset; // File offset corresponding with buf[0]
888 int buffillen; // Current filled length
889 int filpos; // Current file offset
890};
891
892static void copy_mem_info(struct info_str *info, char *data, int datalen)
893{
894
895 if (info->filpos < info->bufoffset) { // Current offset before buffer offset
896 if (info->filpos + datalen <= info->bufoffset) {
897 info->filpos += datalen; // Discard if completely before buffer
898 return;
899 } else { // Partial copy, set to begin
900 data += (info->bufoffset - info->filpos);
901 datalen -= (info->bufoffset - info->filpos);
902 info->filpos = info->bufoffset;
903 }
904 }
905
906 info->filpos += datalen; // Update current offset
907
908 if (info->buffillen == info->buflength) // Buffer full, discard
909 return;
910
911 if (info->buflength - info->buffillen < datalen) // Overflows buffer ?
912 datalen = info->buflength - info->buffillen;
913
914 memcpy(info->buffer + info->buffillen, data, datalen);
915 info->buffillen += datalen;
916}
917
918static int copy_info(struct info_str *info, char *fmt, ...)
919{
920 va_list args;
921 char buf[400];
922 int len;
923
924 va_start(args, fmt);
925 len = vsprintf(buf, fmt, args);
926 va_end(args);
927
928 copy_mem_info(info, buf, len);
929 return len;
930}
931
932
933// Routine to get data for /proc RAM filesystem
934//
935int cpqfcTS_proc_info (struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length,
936 int inout)
937{
938 struct scsi_cmnd *DumCmnd;
939 struct scsi_device *ScsiDev;
940 int Chan, Targ, i;
941 struct info_str info;
942 CPQFCHBA *cpqfcHBA;
943 PTACHYON fcChip;
944 PFC_LOGGEDIN_PORT pLoggedInPort;
945 char buf[81];
946
947 if (inout) return -EINVAL;
948
949 // get the pointer to our Scsi layer HBA buffer
950 cpqfcHBA = (CPQFCHBA *)host->hostdata;
951 fcChip = &cpqfcHBA->fcChip;
952
953 *start = buffer;
954
955 info.buffer = buffer;
956 info.buflength = length;
957 info.bufoffset = offset;
958 info.filpos = 0;
959 info.buffillen = 0;
960 copy_info(&info, "Driver version = %d.%d.%d", VER_MAJOR, VER_MINOR, VER_SUBMINOR);
961 cpqfcTSDecodeGBICtype( &cpqfcHBA->fcChip, &buf[0]);
962 cpqfcTSGetLPSM( &cpqfcHBA->fcChip, &buf[ strlen(buf)]);
963 copy_info(&info, "%s\n", buf);
964
965#define DISPLAY_WWN_INFO
966#ifdef DISPLAY_WWN_INFO
967 ScsiDev = scsi_get_host_dev (host);
968 if (!ScsiDev)
969 return -ENOMEM;
970 DumCmnd = scsi_get_command (ScsiDev, GFP_KERNEL);
971 if (!DumCmnd) {
972 scsi_free_host_dev (ScsiDev);
973 return -ENOMEM;
974 }
975 copy_info(&info, "WWN database: (\"port_id: 000000\" means disconnected)\n");
976 for ( Chan=0; Chan <= host->max_channel; Chan++) {
977 DumCmnd->device->channel = Chan;
978 for (Targ=0; Targ <= host->max_id; Targ++) {
979 DumCmnd->device->id = Targ;
980 if ((pLoggedInPort = fcFindLoggedInPort( fcChip,
981 DumCmnd, // search Scsi Nexus
982 0, // DON'T search list for FC port id
983 NULL, // DON'T search list for FC WWN
984 NULL))){ // DON'T care about end of list
985 copy_info(&info, "Host: scsi%d Channel: %02d TargetId: %02d -> WWN: ",
986 host->host_no, Chan, Targ);
987 for( i=3; i>=0; i--) // copy the LOGIN port's WWN
988 copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]);
989 for( i=7; i>3; i--) // copy the LOGIN port's WWN
990 copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]);
991 copy_info(&info, " port_id: %06X\n", pLoggedInPort->port_id);
992 }
993 }
994 }
995
996 scsi_put_command (DumCmnd);
997 scsi_free_host_dev (ScsiDev);
998#endif
999
1000
1001
1002
1003
1004// Unfortunately, the proc_info buffer isn't big enough
1005// for everything we would like...
1006// For FC stats, compile this and turn off WWN stuff above
1007//#define DISPLAY_FC_STATS
1008#ifdef DISPLAY_FC_STATS
1009// get the Fibre Channel statistics
1010 {
1011 int DeltaSecs = (jiffies - cpqfcHBA->fcStatsTime) / HZ;
1012 int days,hours,minutes,secs;
1013
1014 days = DeltaSecs / (3600*24); // days
1015 hours = (DeltaSecs% (3600*24)) / 3600; // hours
1016 minutes = (DeltaSecs%3600 /60); // minutes
1017 secs = DeltaSecs%60; // secs
1018copy_info( &info, "Fibre Channel Stats (time dd:hh:mm:ss %02u:%02u:%02u:%02u\n",
1019 days, hours, minutes, secs);
1020 }
1021
1022 cpqfcHBA->fcStatsTime = jiffies; // (for next delta)
1023
1024 copy_info( &info, " LinkUp %9u LinkDown %u\n",
1025 fcChip->fcStats.linkUp, fcChip->fcStats.linkDown);
1026
1027 copy_info( &info, " Loss of Signal %9u Loss of Sync %u\n",
1028 fcChip->fcStats.LossofSignal, fcChip->fcStats.LossofSync);
1029
1030 copy_info( &info, " Discarded Frames %9u Bad CRC Frame %u\n",
1031 fcChip->fcStats.Dis_Frm, fcChip->fcStats.Bad_CRC);
1032
1033 copy_info( &info, " TACH LinkFailTX %9u TACH LinkFailRX %u\n",
1034 fcChip->fcStats.linkFailTX, fcChip->fcStats.linkFailRX);
1035
1036 copy_info( &info, " TACH RxEOFa %9u TACH Elastic Store %u\n",
1037 fcChip->fcStats.Rx_EOFa, fcChip->fcStats.e_stores);
1038
1039 copy_info( &info, " BufferCreditWait %9uus TACH FM Inits %u\n",
1040 fcChip->fcStats.BB0_Timer*10, fcChip->fcStats.FMinits );
1041
1042 copy_info( &info, " FC-2 Timeouts %9u FC-2 Logouts %u\n",
1043 fcChip->fcStats.timeouts, fcChip->fcStats.logouts);
1044
1045 copy_info( &info, " FC-2 Aborts %9u FC-4 Aborts %u\n",
1046 fcChip->fcStats.FC2aborted, fcChip->fcStats.FC4aborted);
1047
1048 // clear the counters
1049 cpqfcTSClearLinkStatusCounters( fcChip);
1050#endif
1051
1052 return info.buffillen;
1053}
1054
1055
1056#if DEBUG_CMND
1057
1058UCHAR *ScsiToAscii( UCHAR ScsiCommand)
1059{
1060
1061/*++
1062
1063Routine Description:
1064
1065 Converts a SCSI command to a text string for debugging purposes.
1066
1067
1068Arguments:
1069
1070 ScsiCommand -- hex value SCSI Command
1071
1072
1073Return Value:
1074
1075 An ASCII, null-terminated string if found, else returns NULL.
1076
1077Original code from M. McGowen, Compaq
1078--*/
1079
1080
1081 switch (ScsiCommand)
1082 {
1083 case 0x00:
1084 return( "Test Unit Ready" );
1085
1086 case 0x01:
1087 return( "Rezero Unit or Rewind" );
1088
1089 case 0x02:
1090 return( "Request Block Address" );
1091
1092 case 0x03:
1093 return( "Requese Sense" );
1094
1095 case 0x04:
1096 return( "Format Unit" );
1097
1098 case 0x05:
1099 return( "Read Block Limits" );
1100
1101 case 0x07:
1102 return( "Reassign Blocks" );
1103
1104 case 0x08:
1105 return( "Read (6)" );
1106
1107 case 0x0a:
1108 return( "Write (6)" );
1109
1110 case 0x0b:
1111 return( "Seek (6)" );
1112
1113 case 0x12:
1114 return( "Inquiry" );
1115
1116 case 0x15:
1117 return( "Mode Select (6)" );
1118
1119 case 0x16:
1120 return( "Reserve" );
1121
1122 case 0x17:
1123 return( "Release" );
1124
1125 case 0x1a:
1126 return( "ModeSen(6)" );
1127
1128 case 0x1b:
1129 return( "Start/Stop Unit" );
1130
1131 case 0x1c:
1132 return( "Receive Diagnostic Results" );
1133
1134 case 0x1d:
1135 return( "Send Diagnostic" );
1136
1137 case 0x25:
1138 return( "Read Capacity" );
1139
1140 case 0x28:
1141 return( "Read (10)" );
1142
1143 case 0x2a:
1144 return( "Write (10)" );
1145
1146 case 0x2b:
1147 return( "Seek (10)" );
1148
1149 case 0x2e:
1150 return( "Write and Verify" );
1151
1152 case 0x2f:
1153 return( "Verify" );
1154
1155 case 0x34:
1156 return( "Pre-Fetch" );
1157
1158 case 0x35:
1159 return( "Synchronize Cache" );
1160
1161 case 0x37:
1162 return( "Read Defect Data (10)" );
1163
1164 case 0x3b:
1165 return( "Write Buffer" );
1166
1167 case 0x3c:
1168 return( "Read Buffer" );
1169
1170 case 0x3e:
1171 return( "Read Long" );
1172
1173 case 0x3f:
1174 return( "Write Long" );
1175
1176 case 0x41:
1177 return( "Write Same" );
1178
1179 case 0x4c:
1180 return( "Log Select" );
1181
1182 case 0x4d:
1183 return( "Log Sense" );
1184
1185 case 0x56:
1186 return( "Reserve (10)" );
1187
1188 case 0x57:
1189 return( "Release (10)" );
1190
1191 case 0xa0:
1192 return( "ReportLuns" );
1193
1194 case 0xb7:
1195 return( "Read Defect Data (12)" );
1196
1197 case 0xca:
1198 return( "Peripheral Device Addressing SCSI Passthrough" );
1199
1200 case 0xcb:
1201 return( "Compaq Array Firmware Passthrough" );
1202
1203 default:
1204 return( NULL );
1205 }
1206
1207} // end ScsiToAscii()
1208
1209void cpqfcTS_print_scsi_cmd(Scsi_Cmnd * cmd)
1210{
1211
1212printk("cpqfcTS: (%s) chnl 0x%02x, trgt = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n",
1213 ScsiToAscii( cmd->cmnd[0]), cmd->channel, cmd->target, cmd->lun, cmd->cmd_len);
1214
1215if( cmd->cmnd[0] == 0) // Test Unit Ready?
1216{
1217 int i;
1218
1219 printk("Cmnd->request_bufflen = 0x%X, ->use_sg = %d, ->bufflen = %d\n",
1220 cmd->request_bufflen, cmd->use_sg, cmd->bufflen);
1221 printk("Cmnd->request_buffer = %p, ->sglist_len = %d, ->buffer = %p\n",
1222 cmd->request_buffer, cmd->sglist_len, cmd->buffer);
1223 for (i = 0; i < cmd->cmd_len; i++)
1224 printk("0x%02x ", cmd->cmnd[i]);
1225 printk("\n");
1226}
1227
1228}
1229
1230#endif /* DEBUG_CMND */
1231
1232
1233
1234
1235static void QueCmndOnBoardLock( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd)
1236{
1237 int i;
1238
1239 for( i=0; i< CPQFCTS_REQ_QUEUE_LEN; i++)
1240 { // find spare slot
1241 if( cpqfcHBAdata->BoardLockCmnd[i] == NULL )
1242 {
1243 cpqfcHBAdata->BoardLockCmnd[i] = Cmnd;
1244// printk(" BoardLockCmnd[%d] %p Queued, chnl/target/lun %d/%d/%d\n",
1245// i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
1246 break;
1247 }
1248 }
1249 if( i >= CPQFCTS_REQ_QUEUE_LEN)
1250 {
1251 printk(" cpqfcTS WARNING: Lost Cmnd %p on BoardLock Q full!", Cmnd);
1252 }
1253
1254}
1255
1256
1257static void QueLinkDownCmnd( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd)
1258{
1259 int indx;
1260
1261 // Remember the command ptr so we can return; we'll complete when
1262 // the device comes back, causing immediate retry
1263 for( indx=0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++)//, SCptr++)
1264 {
1265 if( cpqfcHBAdata->LinkDnCmnd[indx] == NULL ) // available?
1266 {
1267#ifdef DUMMYCMND_DBG
1268 printk(" @add Cmnd %p to LnkDnCmnd[%d]@ ", Cmnd,indx);
1269#endif
1270 cpqfcHBAdata->LinkDnCmnd[indx] = Cmnd;
1271 break;
1272 }
1273 }
1274
1275 if( indx >= CPQFCTS_REQ_QUEUE_LEN ) // no space for Cmnd??
1276 {
1277 // this will result in an _abort call later (with possible trouble)
1278 printk("no buffer for LinkDnCmnd!! %p\n", Cmnd);
1279 }
1280}
1281
1282
1283
1284
1285
1286// The file <scsi/scsi_host.h> says not to call scsi_done from
1287// inside _queuecommand, so we'll do it from the heartbeat timer
1288// (clarification: Turns out it's ok to call scsi_done from queuecommand
1289// for cases that don't go to the hardware like scsi cmds destined
1290// for LUNs we know don't exist, so this code might be simplified...)
1291
1292static void QueBadTargetCmnd( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd)
1293{
1294 int i;
1295 // printk(" can't find target %d\n", Cmnd->target);
1296
1297 for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++)
1298 { // find spare slot
1299 if( cpqfcHBAdata->BadTargetCmnd[i] == NULL )
1300 {
1301 cpqfcHBAdata->BadTargetCmnd[i] = Cmnd;
1302// printk(" BadTargetCmnd[%d] %p Queued, chnl/target/lun %d/%d/%d\n",
1303// i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
1304 break;
1305 }
1306 }
1307}
1308
1309
1310// This is the "main" entry point for Linux Scsi commands --
1311// it all starts here.
1312
1313int cpqfcTS_queuecommand(Scsi_Cmnd *Cmnd, void (* done)(Scsi_Cmnd *))
1314{
1315 struct Scsi_Host *HostAdapter = Cmnd->device->host;
1316 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
1317 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1318 TachFCHDR_GCMND fchs; // only use for FC destination id field
1319 PFC_LOGGEDIN_PORT pLoggedInPort;
1320 ULONG ulStatus, SESTtype;
1321 LONG ExchangeID;
1322
1323
1324
1325
1326 ENTER("cpqfcTS_queuecommand");
1327
1328 PCI_TRACEO( (ULONG)Cmnd, 0x98)
1329
1330
1331 Cmnd->scsi_done = done;
1332#ifdef DEBUG_CMND
1333 cpqfcTS_print_scsi_cmd( Cmnd);
1334#endif
1335
1336 // prevent board contention with kernel thread...
1337
1338 if( cpqfcHBAdata->BoardLock )
1339 {
1340// printk(" @BrdLck Hld@ ");
1341 QueCmndOnBoardLock( cpqfcHBAdata, Cmnd);
1342 }
1343
1344 else
1345 {
1346
1347 // in the current system (2.2.12), this routine is called
1348 // after spin_lock_irqsave(), so INTs are disabled. However,
1349 // we might have something pending in the LinkQ, which
1350 // might cause the WorkerTask to run. In case that
1351 // happens, make sure we lock it out.
1352
1353
1354
1355 PCI_TRACE( 0x98)
1356 CPQ_SPINLOCK_HBA( cpqfcHBAdata)
1357 PCI_TRACE( 0x98)
1358
1359 // can we find an FC device mapping to this SCSI target?
1360 pLoggedInPort = fcFindLoggedInPort( fcChip,
1361 Cmnd, // search Scsi Nexus
1362 0, // DON'T search linked list for FC port id
1363 NULL, // DON'T search linked list for FC WWN
1364 NULL); // DON'T care about end of list
1365
1366 if( pLoggedInPort == NULL ) // not found!
1367 {
1368// printk(" @Q bad targ cmnd %p@ ", Cmnd);
1369 QueBadTargetCmnd( cpqfcHBAdata, Cmnd);
1370 }
1371 else if (Cmnd->device->lun >= CPQFCTS_MAX_LUN)
1372 {
1373 printk(KERN_WARNING "cpqfc: Invalid LUN: %d\n", Cmnd->device->lun);
1374 QueBadTargetCmnd( cpqfcHBAdata, Cmnd);
1375 }
1376
1377 else // we know what FC device to send to...
1378 {
1379
1380 // does this device support FCP target functions?
1381 // (determined by PRLI field)
1382
1383 if( !(pLoggedInPort->fcp_info & TARGET_FUNCTION) )
1384 {
1385 printk(" Doesn't support TARGET functions port_id %Xh\n",
1386 pLoggedInPort->port_id );
1387 QueBadTargetCmnd( cpqfcHBAdata, Cmnd);
1388 }
1389
1390 // In this case (previous login OK), the device is temporarily
1391 // unavailable waiting for re-login, in which case we expect it
1392 // to be back in between 25 - 500ms.
1393 // If the FC port doesn't log back in within several seconds
1394 // (i.e. implicit "logout"), or we get an explicit logout,
1395 // we set "device_blocked" in Scsi_Device struct; in this
1396 // case 30 seconds will elapse before Linux/Scsi sends another
1397 // command to the device.
1398 else if( pLoggedInPort->prli != TRUE )
1399 {
1400// printk("Device (Chnl/Target %d/%d) invalid PRLI, port_id %06lXh\n",
1401// Cmnd->channel, Cmnd->target, pLoggedInPort->port_id);
1402 QueLinkDownCmnd( cpqfcHBAdata, Cmnd);
1403// Need to use "blocked" flag??
1404// Cmnd->device->device_blocked = TRUE; // just let it timeout
1405 }
1406 else // device supports TARGET functions, and is logged in...
1407 {
1408 // (context of fchs is to "reply" to...)
1409 fchs.s_id = pLoggedInPort->port_id; // destination FC address
1410
1411 // what is the data direction? For data TO the device,
1412 // we need IWE (Intiator Write Entry). Otherwise, IRE.
1413
1414 if( Cmnd->cmnd[0] == WRITE_10 ||
1415 Cmnd->cmnd[0] == WRITE_6 ||
1416 Cmnd->cmnd[0] == WRITE_BUFFER ||
1417 Cmnd->cmnd[0] == VENDOR_WRITE_OPCODE || // CPQ specific
1418 Cmnd->cmnd[0] == MODE_SELECT )
1419 {
1420 SESTtype = SCSI_IWE; // data from HBA to Device
1421 }
1422 else
1423 SESTtype = SCSI_IRE; // data from Device to HBA
1424
1425 ulStatus = cpqfcTSBuildExchange(
1426 cpqfcHBAdata,
1427 SESTtype, // e.g. Initiator Read Entry (IRE)
1428 &fchs, // we are originator; only use d_id
1429 Cmnd, // Linux SCSI command (with scatter/gather list)
1430 &ExchangeID );// fcController->fcExchanges index, -1 if failed
1431
1432 if( !ulStatus ) // Exchange setup?
1433
1434 {
1435 if( cpqfcHBAdata->BoardLock )
1436 {
1437 TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
1438 printk(" @bl! %d, xID %Xh@ ", current->pid, ExchangeID);
1439 }
1440
1441 ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
1442 if( !ulStatus )
1443 {
1444 PCI_TRACEO( ExchangeID, 0xB8)
1445 // submitted to Tach's Outbound Que (ERQ PI incremented)
1446 // waited for completion for ELS type (Login frames issued
1447 // synchronously)
1448 }
1449 else
1450 // check reason for Exchange not being started - we might
1451 // want to Queue and start later, or fail with error
1452 {
1453 printk("quecommand: cpqfcTSStartExchange failed: %Xh\n", ulStatus );
1454 }
1455 } // end good BuildExchange status
1456
1457 else // SEST table probably full -- why? hardware hang?
1458 {
1459 printk("quecommand: cpqfcTSBuildExchange faild: %Xh\n", ulStatus);
1460 }
1461 } // end can't do FCP-SCSI target functions
1462 } // end can't find target (FC device)
1463
1464 CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
1465 }
1466
1467 PCI_TRACEO( (ULONG)Cmnd, 0x9C)
1468 LEAVE("cpqfcTS_queuecommand");
1469 return 0;
1470}
1471
1472
1473// Entry point for upper Scsi layer intiated abort. Typically
1474// this is called if the command (for hard disk) fails to complete
1475// in 30 seconds. This driver intends to complete all disk commands
1476// within Exchange ".timeOut" seconds (now 7) with target status, or
1477// in case of ".timeOut" expiration, a DID_SOFT_ERROR which causes
1478// immediate retry.
1479// If any disk commands get the _abort call, except for the case that
1480// the physical device was removed or unavailable due to hardware
1481// errors, it should be considered a driver error and reported to
1482// the author.
1483
1484int cpqfcTS_abort(Scsi_Cmnd *Cmnd)
1485{
1486// printk(" cpqfcTS_abort called?? \n");
1487 return 0;
1488}
1489
1490int cpqfcTS_eh_abort(Scsi_Cmnd *Cmnd)
1491{
1492
1493 struct Scsi_Host *HostAdapter = Cmnd->device->host;
1494 // get the pointer to our Scsi layer HBA buffer
1495 CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
1496 PTACHYON fcChip = &cpqfcHBAdata->fcChip;
1497 FC_EXCHANGES *Exchanges = fcChip->Exchanges;
1498 int i;
1499 ENTER("cpqfcTS_eh_abort");
1500
1501 Cmnd->result = DID_ABORT <<16; // assume we'll find it
1502
1503 printk(" @Linux _abort Scsi_Cmnd %p ", Cmnd);
1504 // See if we can find a Cmnd pointer that matches...
1505 // The most likely case is we accepted the command
1506 // from Linux Scsi (e.g. ceated a SEST entry) and it
1507 // got lost somehow. If we can't find any reference
1508 // to the passed pointer, we can only presume it
1509 // got completed as far as our driver is concerned.
1510 // If we found it, we will try to abort it through
1511 // common mechanism. If FC ABTS is successful (ACC)
1512 // or is rejected (RJT) by target, we will call
1513 // Scsi "done" quickly. Otherwise, the ABTS will timeout
1514 // and we'll call "done" later.
1515
1516 // Search the SEST exchanges for a matching Cmnd ptr.
1517 for( i=0; i< TACH_SEST_LEN; i++)
1518 {
1519 if( Exchanges->fcExchange[i].Cmnd == Cmnd )
1520 {
1521
1522 // found it!
1523 printk(" x_ID %Xh, type %Xh\n", i, Exchanges->fcExchange[i].type);
1524
1525 Exchanges->fcExchange[i].status = INITIATOR_ABORT; // seconds default
1526 Exchanges->fcExchange[i].timeOut = 10; // seconds default (changed later)
1527
1528 // Since we need to immediately return the aborted Cmnd to Scsi
1529 // upper layers, we can't make future reference to any of its
1530 // fields (e.g the Nexus).
1531
1532 cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &i);
1533
1534 break;
1535 }
1536 }
1537
1538 if( i >= TACH_SEST_LEN ) // didn't find Cmnd ptr in chip's SEST?
1539 {
1540 // now search our non-SEST buffers (i.e. Cmnd waiting to
1541 // start on the HBA or waiting to complete with error for retry).
1542
1543 // first check BadTargetCmnd
1544 for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++)
1545 {
1546 if( cpqfcHBAdata->BadTargetCmnd[i] == Cmnd )
1547 {
1548 cpqfcHBAdata->BadTargetCmnd[i] = NULL;
1549 printk("in BadTargetCmnd Q\n");
1550 goto Done; // exit
1551 }
1552 }
1553
1554 // if not found above...
1555
1556 for( i=0; i < CPQFCTS_REQ_QUEUE_LEN; i++)
1557 {
1558 if( cpqfcHBAdata->LinkDnCmnd[i] == Cmnd )
1559 {
1560 cpqfcHBAdata->LinkDnCmnd[i] = NULL;
1561 printk("in LinkDnCmnd Q\n");
1562 goto Done;
1563 }
1564 }
1565
1566
1567 for( i=0; i< CPQFCTS_REQ_QUEUE_LEN; i++)
1568 { // find spare slot
1569 if( cpqfcHBAdata->BoardLockCmnd[i] == Cmnd )
1570 {
1571 cpqfcHBAdata->BoardLockCmnd[i] = NULL;
1572 printk("in BoardLockCmnd Q\n");
1573 goto Done;
1574 }
1575 }
1576
1577 Cmnd->result = DID_ERROR <<16; // Hmmm...
1578 printk("Not found! ");
1579// panic("_abort");
1580 }
1581
1582Done:
1583
1584// panic("_abort");
1585 LEAVE("cpqfcTS_eh_abort");
1586 return 0; // (see scsi.h)
1587}
1588
1589
1590// FCP-SCSI Target Device Reset
1591// See dpANS Fibre Channel Protocol for SCSI
1592// X3.269-199X revision 12, pg 25
1593
1594#ifdef SUPPORT_RESET
1595
1596int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev,
1597 unsigned int reset_flags)
1598{
1599 int timeout = 10*HZ;
1600 int retries = 1;
1601 char scsi_cdb[12];
1602 int result;
1603 Scsi_Cmnd * SCpnt;
1604 Scsi_Device * SDpnt;
1605
1606// FIXME, cpqfcTS_TargetDeviceReset needs to be fixed
1607// similarly to how the passthrough ioctl was fixed
1608// around the 2.5.30 kernel. Scsi_Cmnd replaced with
1609// Scsi_Request, etc.
1610// For now, so people don't fall into a hole...
1611
1612 // printk(" ENTERING cpqfcTS_TargetDeviceReset() - flag=%d \n",reset_flags);
1613
1614 if (ScsiDev->host->eh_active) return FAILED;
1615
1616 memset( scsi_cdb, 0, sizeof( scsi_cdb));
1617
1618 scsi_cdb[0] = RELEASE;
1619
1620 SCpnt = scsi_get_command(ScsiDev, GFP_KERNEL);
1621 {
1622 CPQFC_DECLARE_COMPLETION(wait);
1623
1624 SCpnt->SCp.buffers_residual = FCP_TARGET_RESET;
1625
1626 // FIXME: this would panic, SCpnt->request would be NULL.
1627 SCpnt->request->CPQFC_WAITING = &wait;
1628 scsi_do_cmd(SCpnt, scsi_cdb, NULL, 0, my_ioctl_done, timeout, retries);
1629 CPQFC_WAIT_FOR_COMPLETION(&wait);
1630 SCpnt->request->CPQFC_WAITING = NULL;
1631 }
1632
1633
1634 if(driver_byte(SCpnt->result) != 0)
1635 switch(SCpnt->sense_buffer[2] & 0xf) {
1636 case ILLEGAL_REQUEST:
1637 if(cmd[0] == ALLOW_MEDIUM_REMOVAL) dev->lockable = 0;
1638 else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n");
1639 break;
1640 case NOT_READY: // This happens if there is no disc in drive
1641 if(dev->removable && (cmd[0] != TEST_UNIT_READY)){
1642 printk(KERN_INFO "Device not ready. Make sure there is a disc in the drive.\n");
1643 break;
1644 }
1645 case UNIT_ATTENTION:
1646 if (dev->removable){
1647 dev->changed = 1;
1648 SCpnt->result = 0; // This is no longer considered an error
1649 // gag this error, VFS will log it anyway /axboe
1650 // printk(KERN_INFO "Disc change detected.\n");
1651 break;
1652 };
1653 default: // Fall through for non-removable media
1654 printk("SCSI error: host %d id %d lun %d return code = %x\n",
1655 dev->host->host_no,
1656 dev->id,
1657 dev->lun,
1658 SCpnt->result);
1659 printk("\tSense class %x, sense error %x, extended sense %x\n",
1660 sense_class(SCpnt->sense_buffer[0]),
1661 sense_error(SCpnt->sense_buffer[0]),
1662 SCpnt->sense_buffer[2] & 0xf);
1663
1664 };
1665 result = SCpnt->result;
1666
1667 SDpnt = SCpnt->device;
1668 scsi_put_command(SCpnt);
1669 SCpnt = NULL;
1670
1671 // printk(" LEAVING cpqfcTS_TargetDeviceReset() - return SUCCESS \n");
1672 return SUCCESS;
1673}
1674
1675#else
1676int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev,
1677 unsigned int reset_flags)
1678{
1679 return -ENOTSUPP;
1680}
1681
1682#endif /* SUPPORT_RESET */
1683
1684int cpqfcTS_eh_device_reset(Scsi_Cmnd *Cmnd)
1685{
1686 int retval;
1687 Scsi_Device *SDpnt = Cmnd->device;
1688 // printk(" ENTERING cpqfcTS_eh_device_reset() \n");
1689 spin_unlock_irq(Cmnd->device->host->host_lock);
1690 retval = cpqfcTS_TargetDeviceReset( SDpnt, 0);
1691 spin_lock_irq(Cmnd->device->host->host_lock);
1692 return retval;
1693}
1694
1695
1696int cpqfcTS_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags)
1697{
1698
1699 ENTER("cpqfcTS_reset");
1700
1701 LEAVE("cpqfcTS_reset");
1702 return SCSI_RESET_ERROR; /* Bus Reset Not supported */
1703}
1704
1705/* This function determines the bios parameters for a given
1706 harddisk. These tend to be numbers that are made up by the
1707 host adapter. Parameters:
1708 size, device number, list (heads, sectors,cylinders).
1709 (from hosts.h)
1710*/
1711
1712int cpqfcTS_biosparam(struct scsi_device *sdev, struct block_device *n,
1713 sector_t capacity, int ip[])
1714{
1715 int size = capacity;
1716
1717 ENTER("cpqfcTS_biosparam");
1718 ip[0] = 64;
1719 ip[1] = 32;
1720 ip[2] = size >> 11;
1721
1722 if( ip[2] > 1024 )
1723 {
1724 ip[0] = 255;
1725 ip[1] = 63;
1726 ip[2] = size / (ip[0] * ip[1]);
1727 }
1728
1729 LEAVE("cpqfcTS_biosparam");
1730 return 0;
1731}
1732
1733
1734
1735irqreturn_t cpqfcTS_intr_handler( int irq,
1736 void *dev_id,
1737 struct pt_regs *regs)
1738{
1739
1740 unsigned long flags, InfLoopBrk=0;
1741 struct Scsi_Host *HostAdapter = dev_id;
1742 CPQFCHBA *cpqfcHBA = (CPQFCHBA *)HostAdapter->hostdata;
1743 int MoreMessages = 1; // assume we have something to do
1744 UCHAR IntPending;
1745 int handled = 0;
1746
1747 ENTER("intr_handler");
1748 spin_lock_irqsave( HostAdapter->host_lock, flags);
1749 // is this our INT?
1750 IntPending = readb( cpqfcHBA->fcChip.Registers.INTPEND.address);
1751
1752 // broken boards can generate messages forever, so
1753 // prevent the infinite loop
1754#define INFINITE_IMQ_BREAK 10000
1755 if( IntPending )
1756 {
1757 handled = 1;
1758 // mask our HBA interrupts until we handle it...
1759 writeb( 0, cpqfcHBA->fcChip.Registers.INTEN.address);
1760
1761 if( IntPending & 0x4) // "INT" - Tach wrote to IMQ
1762 {
1763 while( (++InfLoopBrk < INFINITE_IMQ_BREAK) && (MoreMessages ==1) )
1764 {
1765 MoreMessages = CpqTsProcessIMQEntry( HostAdapter); // ret 0 when done
1766 }
1767 if( InfLoopBrk >= INFINITE_IMQ_BREAK )
1768 {
1769 printk("WARNING: Compaq FC adapter generating excessive INTs -REPLACE\n");
1770 printk("or investigate alternate causes (e.g. physical FC layer)\n");
1771 }
1772
1773 else // working normally - re-enable INTs and continue
1774 writeb( 0x1F, cpqfcHBA->fcChip.Registers.INTEN.address);
1775
1776 } // (...ProcessIMQEntry() clears INT by writing IMQ consumer)
1777 else // indications of errors or problems...
1778 // these usually indicate critical system hardware problems.
1779 {
1780 if( IntPending & 0x10 )
1781 printk(" cpqfcTS adapter external memory parity error detected\n");
1782 if( IntPending & 0x8 )
1783 printk(" cpqfcTS adapter PCI master address crossed 45-bit boundary\n");
1784 if( IntPending & 0x2 )
1785 printk(" cpqfcTS adapter DMA error detected\n");
1786 if( IntPending & 0x1 ) {
1787 UCHAR IntStat;
1788 printk(" cpqfcTS adapter PCI error detected\n");
1789 IntStat = readb( cpqfcHBA->fcChip.Registers.INTSTAT.address);
1790 printk("cpqfc: ISR = 0x%02x\n", IntStat);
1791 if (IntStat & 0x1) {
1792 __u16 pcistat;
1793 /* read the pci status register */
1794 pci_read_config_word(cpqfcHBA->PciDev, 0x06, &pcistat);
1795 printk("PCI status register is 0x%04x\n", pcistat);
1796 if (pcistat & 0x8000) printk("Parity Error Detected.\n");
1797 if (pcistat & 0x4000) printk("Signalled System Error\n");
1798 if (pcistat & 0x2000) printk("Received Master Abort\n");
1799 if (pcistat & 0x1000) printk("Received Target Abort\n");
1800 if (pcistat & 0x0800) printk("Signalled Target Abort\n");
1801 }
1802 if (IntStat & 0x4) printk("(INT)\n");
1803 if (IntStat & 0x8)
1804 printk("CRS: PCI master address crossed 46 bit bouandary\n");
1805 if (IntStat & 0x10) printk("MRE: external memory parity error.\n");
1806 }
1807 }
1808 }
1809 spin_unlock_irqrestore( HostAdapter->host_lock, flags);
1810 LEAVE("intr_handler");
1811 return IRQ_RETVAL(handled);
1812}
1813
1814
1815
1816
1817int cpqfcTSDecodeGBICtype( PTACHYON fcChip, char cErrorString[])
1818{
1819 // Verify GBIC type (if any) and correct Tachyon Port State Machine
1820 // (GBIC) module definition is:
1821 // GPIO1, GPIO0, GPIO4 for MD2, MD1, MD0. The input states appear
1822 // to be inverted -- i.e., a setting of 111 is read when there is NO
1823 // GBIC present. The Module Def (MD) spec says 000 is "no GBIC"
1824 // Hard code the bit states to detect Copper,
1825 // Long wave (single mode), Short wave (multi-mode), and absent GBIC
1826
1827 ULONG ulBuff;
1828
1829 sprintf( cErrorString, "\nGBIC detected: ");
1830
1831 ulBuff = fcChip->Registers.TYstatus.value & 0x13;
1832 switch( ulBuff )
1833 {
1834 case 0x13: // GPIO4, GPIO1, GPIO0 = 111; no GBIC!
1835 sprintf( &cErrorString[ strlen( cErrorString)],
1836 "NONE! ");
1837 return FALSE;
1838
1839
1840 case 0x11: // Copper GBIC detected
1841 sprintf( &cErrorString[ strlen( cErrorString)],
1842 "Copper. ");
1843 break;
1844
1845 case 0x10: // Long-wave (single mode) GBIC detected
1846 sprintf( &cErrorString[ strlen( cErrorString)],
1847 "Long-wave. ");
1848 break;
1849 case 0x1: // Short-wave (multi mode) GBIC detected
1850 sprintf( &cErrorString[ strlen( cErrorString)],
1851 "Short-wave. ");
1852 break;
1853 default: // unknown GBIC - presumably it will work (?)
1854 sprintf( &cErrorString[ strlen( cErrorString)],
1855 "Unknown. ");
1856
1857 break;
1858 } // end switch GBIC detection
1859
1860 return TRUE;
1861}
1862
1863
1864
1865
1866
1867
1868int cpqfcTSGetLPSM( PTACHYON fcChip, char cErrorString[])
1869{
1870 // Tachyon's Frame Manager LPSM in LinkDown state?
1871 // (For non-loop port, check PSM instead.)
1872 // return string with state and FALSE is Link Down
1873
1874 int LinkUp;
1875
1876 if( fcChip->Registers.FMstatus.value & 0x80 )
1877 LinkUp = FALSE;
1878 else
1879 LinkUp = TRUE;
1880
1881 sprintf( &cErrorString[ strlen( cErrorString)],
1882 " LPSM %Xh ",
1883 (fcChip->Registers.FMstatus.value >>4) & 0xf );
1884
1885
1886 switch( fcChip->Registers.FMstatus.value & 0xF0)
1887 {
1888 // bits set in LPSM
1889 case 0x10:
1890 sprintf( &cErrorString[ strlen( cErrorString)], "ARB");
1891 break;
1892 case 0x20:
1893 sprintf( &cErrorString[ strlen( cErrorString)], "ARBwon");
1894 break;
1895 case 0x30:
1896 sprintf( &cErrorString[ strlen( cErrorString)], "OPEN");
1897 break;
1898 case 0x40:
1899 sprintf( &cErrorString[ strlen( cErrorString)], "OPENed");
1900 break;
1901 case 0x50:
1902 sprintf( &cErrorString[ strlen( cErrorString)], "XmitCLS");
1903 break;
1904 case 0x60:
1905 sprintf( &cErrorString[ strlen( cErrorString)], "RxCLS");
1906 break;
1907 case 0x70:
1908 sprintf( &cErrorString[ strlen( cErrorString)], "Xfer");
1909 break;
1910 case 0x80:
1911 sprintf( &cErrorString[ strlen( cErrorString)], "Init");
1912 break;
1913 case 0x90:
1914 sprintf( &cErrorString[ strlen( cErrorString)], "O-IInitFin");
1915 break;
1916 case 0xa0:
1917 sprintf( &cErrorString[ strlen( cErrorString)], "O-IProtocol");
1918 break;
1919 case 0xb0:
1920 sprintf( &cErrorString[ strlen( cErrorString)], "O-ILipRcvd");
1921 break;
1922 case 0xc0:
1923 sprintf( &cErrorString[ strlen( cErrorString)], "HostControl");
1924 break;
1925 case 0xd0:
1926 sprintf( &cErrorString[ strlen( cErrorString)], "LoopFail");
1927 break;
1928 case 0xe0:
1929 sprintf( &cErrorString[ strlen( cErrorString)], "Offline");
1930 break;
1931 case 0xf0:
1932 sprintf( &cErrorString[ strlen( cErrorString)], "OldPort");
1933 break;
1934 case 0:
1935 default:
1936 sprintf( &cErrorString[ strlen( cErrorString)], "Monitor");
1937 break;
1938
1939 }
1940
1941 return LinkUp;
1942}
1943
1944
1945
1946
1947#include "linux/slab.h"
1948
1949// Dynamic memory allocation alignment routines
1950// HP's Tachyon Fibre Channel Controller chips require
1951// certain memory queues and register pointers to be aligned
1952// on various boundaries, usually the size of the Queue in question.
1953// Alignment might be on 2, 4, 8, ... or even 512 byte boundaries.
1954// Since most O/Ss don't allow this (usually only Cache aligned -
1955// 32-byte boundary), these routines provide generic alignment (after
1956// O/S allocation) at any boundary, and store the original allocated
1957// pointer for deletion (O/S free function). Typically, we expect
1958// these functions to only be called at HBA initialization and
1959// removal time (load and unload times)
1960// ALGORITHM notes:
1961// Memory allocation varies by compiler and platform. In the worst case,
1962// we are only assured BYTE alignment, but in the best case, we can
1963// request allocation on any desired boundary. Our strategy: pad the
1964// allocation request size (i.e. waste memory) so that we are assured
1965// of passing desired boundary near beginning of contiguous space, then
1966// mask out lower address bits.
1967// We define the following algorithm:
1968// allocBoundary - compiler/platform specific address alignment
1969// in number of bytes (default is single byte; i.e. 1)
1970// n_alloc - number of bytes application wants @ aligned address
1971// ab - alignment boundary, in bytes (e.g. 4, 32, ...)
1972// t_alloc - total allocation needed to ensure desired boundary
1973// mask - to clear least significant address bits for boundary
1974// Compute:
1975// t_alloc = n_alloc + (ab - allocBoundary)
1976// allocate t_alloc bytes @ alloc_address
1977// mask = NOT (ab - 1)
1978// (e.g. if ab=32 _0001 1111 -> _1110 0000
1979// aligned_address = alloc_address & mask
1980// set n_alloc bytes to 0
1981// return aligned_address (NULL if failed)
1982//
1983// If u32_AlignedAddress is non-zero, then search for BaseAddress (stored
1984// from previous allocation). If found, invoke call to FREE the memory.
1985// Return NULL if BaseAddress not found
1986
1987// we need about 8 allocations per HBA. Figuring at most 10 HBAs per server
1988// size the dynamic_mem array at 80.
1989
1990void* fcMemManager( struct pci_dev *pdev, ALIGNED_MEM *dynamic_mem,
1991 ULONG n_alloc, ULONG ab, ULONG u32_AlignedAddress,
1992 dma_addr_t *dma_handle)
1993{
1994 USHORT allocBoundary=1; // compiler specific - worst case 1
1995 // best case - replace malloc() call
1996 // with function that allocates exactly
1997 // at desired boundary
1998
1999 unsigned long ulAddress;
2000 ULONG t_alloc, i;
2001 void *alloc_address = 0; // def. error code / address not found
2002 LONG mask; // must be 32-bits wide!
2003
2004 ENTER("fcMemManager");
2005 if( u32_AlignedAddress ) // are we freeing existing memory?
2006 {
2007// printk(" freeing AlignedAddress %Xh\n", u32_AlignedAddress);
2008 for( i=0; i<DYNAMIC_ALLOCATIONS; i++) // look for the base address
2009 {
2010// printk("dynamic_mem[%u].AlignedAddress %lX\n", i, dynamic_mem[i].AlignedAddress);
2011 if( dynamic_mem[i].AlignedAddress == u32_AlignedAddress )
2012 {
2013 alloc_address = dynamic_mem[i].BaseAllocated; // 'success' status
2014 pci_free_consistent(pdev,dynamic_mem[i].size,
2015 alloc_address,
2016 dynamic_mem[i].dma_handle);
2017 dynamic_mem[i].BaseAllocated = 0; // clear for next use
2018 dynamic_mem[i].AlignedAddress = 0;
2019 dynamic_mem[i].size = 0;
2020 break; // quit for loop; done
2021 }
2022 }
2023 }
2024 else if( n_alloc ) // want new memory?
2025 {
2026 dma_addr_t handle;
2027 t_alloc = n_alloc + (ab - allocBoundary); // pad bytes for alignment
2028// printk("pci_alloc_consistent() for Tach alignment: %ld bytes\n", t_alloc);
2029
2030// (would like to) allow thread block to free pages
2031 alloc_address = // total bytes (NumberOfBytes)
2032 pci_alloc_consistent(pdev, t_alloc, &handle);
2033
2034 // now mask off least sig. bits of address
2035 if( alloc_address ) // (only if non-NULL)
2036 {
2037 // find place to store ptr, so we
2038 // can free it later...
2039
2040 mask = (LONG)(ab - 1); // mask all low-order bits
2041 mask = ~mask; // invert bits
2042 for( i=0; i<DYNAMIC_ALLOCATIONS; i++) // look for free slot
2043 {
2044 if( dynamic_mem[i].BaseAllocated == 0) // take 1st available
2045 {
2046 dynamic_mem[i].BaseAllocated = alloc_address;// address from O/S
2047 dynamic_mem[i].dma_handle = handle;
2048 if (dma_handle != NULL)
2049 {
2050// printk("handle = %p, ab=%d, boundary = %d, mask=0x%08x\n",
2051// handle, ab, allocBoundary, mask);
2052 *dma_handle = (dma_addr_t)
2053 ((((ULONG)handle) + (ab - allocBoundary)) & mask);
2054 }
2055 dynamic_mem[i].size = t_alloc;
2056 break;
2057 }
2058 }
2059 ulAddress = (unsigned long)alloc_address;
2060
2061 ulAddress += (ab - allocBoundary); // add the alignment bytes-
2062 // then truncate address...
2063 alloc_address = (void*)(ulAddress & mask);
2064
2065 dynamic_mem[i].AlignedAddress =
2066 (ULONG)(ulAddress & mask); // 32bit Tach address
2067 memset( alloc_address, 0, n_alloc ); // clear new memory
2068 }
2069 else // O/S dynamic mem alloc failed!
2070 alloc_address = 0; // (for debugging breakpt)
2071
2072 }
2073
2074 LEAVE("fcMemManager");
2075 return alloc_address; // good (or NULL) address
2076}
2077
2078
2079static Scsi_Host_Template driver_template = {
2080 .detect = cpqfcTS_detect,
2081 .release = cpqfcTS_release,
2082 .info = cpqfcTS_info,
2083 .proc_info = cpqfcTS_proc_info,
2084 .ioctl = cpqfcTS_ioctl,
2085 .queuecommand = cpqfcTS_queuecommand,
2086 .eh_device_reset_handler = cpqfcTS_eh_device_reset,
2087 .eh_abort_handler = cpqfcTS_eh_abort,
2088 .bios_param = cpqfcTS_biosparam,
2089 .can_queue = CPQFCTS_REQ_QUEUE_LEN,
2090 .this_id = -1,
2091 .sg_tablesize = SG_ALL,
2092 .cmd_per_lun = CPQFCTS_CMD_PER_LUN,
2093 .use_clustering = ENABLE_CLUSTERING,
2094};
2095#include "scsi_module.c"
2096