| /****************************************************************************** |
| * QLOGIC LINUX SOFTWARE |
| * |
| * QLogic QLA1280 (Ultra2) and QLA12160 (Ultra3) SCSI driver |
| * Copyright (C) 2000 Qlogic Corporation (www.qlogic.com) |
| * Copyright (C) 2001-2002 Jes Sorensen, Wild Open Source Inc. |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License as published by the |
| * Free Software Foundation; either version 2, or (at your option) any |
| * later version. |
| * |
| * This program is distributed in the hope that it will be useful, but |
| * WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * General Public License for more details. |
| * |
| ******************************************************************************/ |
| #define QLA1280_VERSION "3.23.19 Beta" |
| /****************************************************************************** |
| Revision History: |
| Rev 3.23.19 Beta April 11, 2002, Linus Torvalds |
| - Do qla1280_pci_config() before calling request_irq() and |
| request_region() |
| - Use pci_dma_hi32() to handle upper word of DMA addresses instead |
| of large shifts |
| - Hand correct arguments to free_irq() in case of failure |
| Rev 3.23.18 Beta April 11, 2002, Jes Sorensen |
| - Run source through Lindent and clean up the output |
| Rev 3.23.17 Beta April 11, 2002, Jes Sorensen |
| - Update SCSI firmware to qla1280 v8.15.00 and qla12160 v10.04.32 |
| Rev 3.23.16 Beta March 19, 2002, Jes Sorensen |
| - Rely on mailbox commands generating interrupts - do not |
| run qla1280_isr() from ql1280_mailbox_command() |
| - Remove device_reg_t |
| - Integrate ql12160_set_target_parameters() with 1280 version |
| - Make qla1280_setup() non static |
| - Do not call qla1280_check_for_dead_scsi_bus() on every I/O request |
| sent to the card - this command pauses the firmare!!! |
| Rev 3.23.15 Beta March 19, 2002, Jes Sorensen |
| - Clean up qla1280.h - remove obsolete QL_DEBUG_LEVEL_x definitions |
| - Remove a pile of pointless and confusing (srb_t **) and |
| (scsi_lu_t *) typecasts |
| - Explicit mark that we do not use the new error handling (for now) |
| - Remove scsi_qla_host_t and use 'struct' instead |
| - Remove in_abort, watchdog_enabled, dpc, dpc_sched, bios_enabled, |
| pci_64bit_slot flags which weren't used for anything anyway |
| - Grab host->host_lock while calling qla1280_isr() from abort() |
| - Use spin_lock()/spin_unlock() in qla1280_intr_handler() - we |
| do not need to save/restore flags in the interrupt handler |
| - Enable interrupts early (before any mailbox access) in preparation |
| for cleaning up the mailbox handling |
| Rev 3.23.14 Beta March 14, 2002, Jes Sorensen |
| - Further cleanups. Remove all trace of QL_DEBUG_LEVEL_x and replace |
| it with proper use of dprintk(). |
| - Make qla1280_print_scsi_cmd() and qla1280_dump_buffer() both take |
| a debug level argument to determine if data is to be printed |
| - Add KERN_* info to printk() |
| Rev 3.23.13 Beta March 14, 2002, Jes Sorensen |
| - Significant cosmetic cleanups |
| - Change debug code to use dprintk() and remove #if mess |
| Rev 3.23.12 Beta March 13, 2002, Jes Sorensen |
| - More cosmetic cleanups, fix places treating return as function |
| - use cpu_relax() in qla1280_debounce_register() |
| Rev 3.23.11 Beta March 13, 2002, Jes Sorensen |
| - Make it compile under 2.5.5 |
| Rev 3.23.10 Beta October 1, 2001, Jes Sorensen |
| - Do no typecast short * to long * in QL1280BoardTbl, this |
| broke miserably on big endian boxes |
| Rev 3.23.9 Beta September 30, 2001, Jes Sorensen |
| - Remove pre 2.2 hack for checking for reentrance in interrupt handler |
| - Make data types used to receive from SCSI_{BUS,TCN,LUN}_32 |
| unsigned int to match the types from struct scsi_cmnd |
| Rev 3.23.8 Beta September 29, 2001, Jes Sorensen |
| - Remove bogus timer_t typedef from qla1280.h |
| - Remove obsolete pre 2.2 PCI setup code, use proper #define's |
| for PCI_ values, call pci_set_master() |
| - Fix memleak of qla1280_buffer on module unload |
| - Only compile module parsing code #ifdef MODULE - should be |
| changed to use individual MODULE_PARM's later |
| - Remove dummy_buffer that was never modified nor printed |
| - ENTER()/LEAVE() are noops unless QL_DEBUG_LEVEL_3, hence remove |
| #ifdef QL_DEBUG_LEVEL_3/#endif around ENTER()/LEAVE() calls |
| - Remove \r from print statements, this is Linux, not DOS |
| - Remove obsolete QLA1280_{SCSILU,INTR,RING}_{LOCK,UNLOCK} |
| dummy macros |
| - Remove C++ compile hack in header file as Linux driver are not |
| supposed to be compiled as C++ |
| - Kill MS_64BITS macro as it makes the code more readable |
| - Remove unnecessary flags.in_interrupts bit |
| Rev 3.23.7 Beta August 20, 2001, Jes Sorensen |
| - Dont' check for set flags on q->q_flag one by one in qla1280_next() |
| - Check whether the interrupt was generated by the QLA1280 before |
| doing any processing |
| - qla1280_status_entry(): Only zero out part of sense_buffer that |
| is not being copied into |
| - Remove more superflouous typecasts |
| - qla1280_32bit_start_scsi() replace home-brew memcpy() with memcpy() |
| Rev 3.23.6 Beta August 20, 2001, Tony Luck, Intel |
| - Don't walk the entire list in qla1280_putq_t() just to directly |
| grab the pointer to the last element afterwards |
| Rev 3.23.5 Beta August 9, 2001, Jes Sorensen |
| - Don't use SA_INTERRUPT, it's use is deprecated for this kinda driver |
| Rev 3.23.4 Beta August 8, 2001, Jes Sorensen |
| - Set dev->max_sectors to 1024 |
| Rev 3.23.3 Beta August 6, 2001, Jes Sorensen |
| - Provide compat macros for pci_enable_device(), pci_find_subsys() |
| and scsi_set_pci_device() |
| - Call scsi_set_pci_device() for all devices |
| - Reduce size of kernel version dependent device probe code |
| - Move duplicate probe/init code to separate function |
| - Handle error if qla1280_mem_alloc() fails |
| - Kill OFFSET() macro and use Linux's PCI definitions instead |
| - Kill private structure defining PCI config space (struct config_reg) |
| - Only allocate I/O port region if not in MMIO mode |
| - Remove duplicate (unused) sanity check of sife of srb_t |
| Rev 3.23.2 Beta August 6, 2001, Jes Sorensen |
| - Change home-brew memset() implementations to use memset() |
| - Remove all references to COMTRACE() - accessing a PC's COM2 serial |
| port directly is not legal under Linux. |
| Rev 3.23.1 Beta April 24, 2001, Jes Sorensen |
| - Remove pre 2.2 kernel support |
| - clean up 64 bit DMA setting to use 2.4 API (provide backwards compat) |
| - Fix MMIO access to use readl/writel instead of directly |
| dereferencing pointers |
| - Nuke MSDOS debugging code |
| - Change true/false data types to int from uint8_t |
| - Use int for counters instead of uint8_t etc. |
| - Clean up size & byte order conversion macro usage |
| Rev 3.23 Beta January 11, 2001 BN Qlogic |
| - Added check of device_id when handling non |
| QLA12160s during detect(). |
| Rev 3.22 Beta January 5, 2001 BN Qlogic |
| - Changed queue_task() to schedule_work() |
| for kernels 2.4.0 and higher. |
| Note: 2.4.0-testxx kernels released prior to |
| the actual 2.4.0 kernel release on January 2001 |
| will get compile/link errors with schedule_work(). |
| Please update your kernel to released 2.4.0 level, |
| or comment lines in this file flagged with 3.22 |
| to resolve compile/link error of schedule_work(). |
| - Added -DCONFIG_SMP in addition to -D__SMP__ |
| in Makefile for 2.4.0 builds of driver as module. |
| Rev 3.21 Beta January 4, 2001 BN Qlogic |
| - Changed criteria of 64/32 Bit mode of HBA |
| operation according to BITS_PER_LONG rather |
| than HBA's NVRAM setting of >4Gig memory bit; |
| so that the HBA auto-configures without the need |
| to setup each system individually. |
| Rev 3.20 Beta December 5, 2000 BN Qlogic |
| - Added priority handling to IA-64 onboard SCSI |
| ISP12160 chip for kernels greater than 2.3.18. |
| - Added irqrestore for qla1280_intr_handler. |
| - Enabled /proc/scsi/qla1280 interface. |
| - Clear /proc/scsi/qla1280 counters in detect(). |
| Rev 3.19 Beta October 13, 2000 BN Qlogic |
| - Declare driver_template for new kernel |
| (2.4.0 and greater) scsi initialization scheme. |
| - Update /proc/scsi entry for 2.3.18 kernels and |
| above as qla1280 |
| Rev 3.18 Beta October 10, 2000 BN Qlogic |
| - Changed scan order of adapters to map |
| the QLA12160 followed by the QLA1280. |
| Rev 3.17 Beta September 18, 2000 BN Qlogic |
| - Removed warnings for 32 bit 2.4.x compiles |
| - Corrected declared size for request and response |
| DMA addresses that are kept in each ha |
| Rev. 3.16 Beta August 25, 2000 BN Qlogic |
| - Corrected 64 bit addressing issue on IA-64 |
| where the upper 32 bits were not properly |
| passed to the RISC engine. |
| Rev. 3.15 Beta August 22, 2000 BN Qlogic |
| - Modified qla1280_setup_chip to properly load |
| ISP firmware for greater that 4 Gig memory on IA-64 |
| Rev. 3.14 Beta August 16, 2000 BN Qlogic |
| - Added setting of dma_mask to full 64 bit |
| if flags.enable_64bit_addressing is set in NVRAM |
| Rev. 3.13 Beta August 16, 2000 BN Qlogic |
| - Use new PCI DMA mapping APIs for 2.4.x kernel |
| Rev. 3.12 July 18, 2000 Redhat & BN Qlogic |
| - Added check of pci_enable_device to detect() for 2.3.x |
| - Use pci_resource_start() instead of |
| pdev->resource[0].start in detect() for 2.3.x |
| - Updated driver version |
| Rev. 3.11 July 14, 2000 BN Qlogic |
| - Updated SCSI Firmware to following versions: |
| qla1x80: 8.13.08 |
| qla1x160: 10.04.08 |
| - Updated driver version to 3.11 |
| Rev. 3.10 June 23, 2000 BN Qlogic |
| - Added filtering of AMI SubSys Vendor ID devices |
| Rev. 3.9 |
| - DEBUG_QLA1280 undefined and new version BN Qlogic |
| Rev. 3.08b May 9, 2000 MD Dell |
| - Added logic to check against AMI subsystem vendor ID |
| Rev. 3.08 May 4, 2000 DG Qlogic |
| - Added logic to check for PCI subsystem ID. |
| Rev. 3.07 Apr 24, 2000 DG & BN Qlogic |
| - Updated SCSI Firmware to following versions: |
| qla12160: 10.01.19 |
| qla1280: 8.09.00 |
| Rev. 3.06 Apr 12, 2000 DG & BN Qlogic |
| - Internal revision; not released |
| Rev. 3.05 Mar 28, 2000 DG & BN Qlogic |
| - Edit correction for virt_to_bus and PROC. |
| Rev. 3.04 Mar 28, 2000 DG & BN Qlogic |
| - Merge changes from ia64 port. |
| Rev. 3.03 Mar 28, 2000 BN Qlogic |
| - Increase version to reflect new code drop with compile fix |
| of issue with inclusion of linux/spinlock for 2.3 kernels |
| Rev. 3.02 Mar 15, 2000 BN Qlogic |
| - Merge qla1280_proc_info from 2.10 code base |
| Rev. 3.01 Feb 10, 2000 BN Qlogic |
| - Corrected code to compile on a 2.2.x kernel. |
| Rev. 3.00 Jan 17, 2000 DG Qlogic |
| - Added 64-bit support. |
| Rev. 2.07 Nov 9, 1999 DG Qlogic |
| - Added new routine to set target parameters for ISP12160. |
| Rev. 2.06 Sept 10, 1999 DG Qlogic |
| - Added support for ISP12160 Ultra 3 chip. |
| Rev. 2.03 August 3, 1999 Fred Lewis, Intel DuPont |
| - Modified code to remove errors generated when compiling with |
| Cygnus IA64 Compiler. |
| - Changed conversion of pointers to unsigned longs instead of integers. |
| - Changed type of I/O port variables from uint32_t to unsigned long. |
| - Modified OFFSET macro to work with 64-bit as well as 32-bit. |
| - Changed sprintf and printk format specifiers for pointers to %p. |
| - Changed some int to long type casts where needed in sprintf & printk. |
| - Added l modifiers to sprintf and printk format specifiers for longs. |
| - Removed unused local variables. |
| Rev. 1.20 June 8, 1999 DG, Qlogic |
| Changes to support RedHat release 6.0 (kernel 2.2.5). |
| - Added SCSI exclusive access lock (io_request_lock) when accessing |
| the adapter. |
| - Added changes for the new LINUX interface template. Some new error |
| handling routines have been added to the template, but for now we |
| will use the old ones. |
| - Initial Beta Release. |
| *****************************************************************************/ |
| |
| #include <linux/config.h> |
| #include <linux/module.h> |
| |
| #include <linux/version.h> |
| #include <linux/types.h> |
| #include <linux/string.h> |
| #include <linux/errno.h> |
| #include <linux/kernel.h> |
| #include <linux/interrupt.h> |
| #include <linux/ioport.h> |
| #include <linux/delay.h> |
| #include <linux/timer.h> |
| #include <linux/pci.h> |
| #include <linux/proc_fs.h> |
| #include <linux/blk.h> |
| #include <linux/workqueue.h> |
| #include <linux/stat.h> |
| #include <linux/slab.h> |
| |
| #include <asm/io.h> |
| #include <asm/irq.h> |
| #include <asm/byteorder.h> |
| #include <asm/processor.h> |
| |
| #ifndef KERNEL_VERSION |
| #define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z)) |
| #endif |
| |
| #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,18) |
| #include <linux/pci_ids.h> |
| #endif |
| |
| #include "scsi.h" |
| #include "hosts.h" |
| #define UNIQUE_FW_NAME |
| #include "qla1280.h" |
| #include "ql12160_fw.h" /* ISP RISC codes */ |
| #include "ql1280_fw.h" |
| |
| /* |
| * Compile time Options: |
| * 0 - Disable and 1 - Enable |
| */ |
| #define QL1280_TARGET_MODE_SUPPORT 0 /* Target mode support */ |
| #define QL1280_LUN_SUPPORT 0 |
| #define WATCHDOGTIMER 0 |
| #define MEMORY_MAPPED_IO 0 |
| #define DEBUG_QLA1280_INTR 0 |
| #define USE_NVRAM_DEFAULTS 0 |
| #define DEBUG_PRINT_NVRAM 0 |
| #define LOADING_RISC_ACTIVITY 0 |
| #define AUTO_ESCALATE_RESET 0 /* Automatically escalate resets */ |
| #define AUTO_ESCALATE_ABORT 0 /* Automatically escalate aborts */ |
| #define STOP_ON_ERROR 0 /* Stop on aborts and resets */ |
| #define STOP_ON_RESET 0 |
| #define STOP_ON_ABORT 0 |
| #define QLA1280_PROFILE 1 /* 3.20 */ |
| #define DEBUG_QLA1280 0 |
| |
| /* |
| * Missing PCI ID's |
| */ |
| #ifndef PCI_DEVICE_ID_QLOGIC_ISP1080 |
| #define PCI_DEVICE_ID_QLOGIC_ISP1080 0x1080 |
| #endif |
| #ifndef PCI_DEVICE_ID_QLOGIC_ISP1240 |
| #define PCI_DEVICE_ID_QLOGIC_ISP1240 0x1240 |
| #endif |
| #ifndef PCI_DEVICE_ID_QLOGIC_ISP1280 |
| #define PCI_DEVICE_ID_QLOGIC_ISP1280 0x1280 |
| #endif |
| #ifndef PCI_DEVICE_ID_QLOGIC_ISP10160 |
| #define PCI_DEVICE_ID_QLOGIC_ISP10160 0x1016 |
| #endif |
| #ifndef PCI_DEVICE_ID_QLOGIC_ISP12160 |
| #define PCI_DEVICE_ID_QLOGIC_ISP12160 0x1216 |
| #endif |
| |
| #ifndef PCI_VENDOR_ID_AMI |
| #define PCI_VENDOR_ID_AMI 0x101e |
| #endif |
| |
| #if (BITS_PER_LONG == 64) || defined CONFIG_HIGHMEM |
| #define QLA_64BIT_PTR 1 |
| #endif |
| |
| /* 3.16 */ |
| #ifdef QLA_64BIT_PTR |
| #define pci_dma_lo32(a) (a & 0xffffffff) |
| #define pci_dma_hi32(a) (a >> 32) |
| #else |
| #define pci_dma_lo32(a) (a & 0xffffffff) |
| #define pci_dma_hi32(a) 0 |
| #endif |
| |
| #define NVRAM_DELAY() udelay(500) /* 2 microsecond delay */ |
| |
| #define CACHE_FLUSH(a) RD_REG_WORD(a) |
| #define INVALID_HANDLE (MAX_OUTSTANDING_COMMANDS + 1) |
| |
| /* |
| * Compat macros |
| */ |
| #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) |
| #define pci_set_dma_mask(dev, mask) dev->dma_mask = mask; |
| #define pci_present() pcibios_present() |
| #define pci_enable_device(pdev) 0 |
| #define pci_find_subsys(id, dev, sid, sdev, pdev) pci_find_device(id,dev,pdev) |
| #define scsi_set_pci_device(host, pdev) |
| #endif |
| |
| #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) |
| typedef unsigned long dma_addr_t; |
| |
| static inline void * |
| pci_alloc_consistent(struct pci_dev *hwdev, size_t size, |
| dma_addr_t * dma_handle) |
| { |
| void *virt_ptr; |
| |
| virt_ptr = kmalloc(size, GFP_KERNEL); |
| if (!virt_ptr) |
| return NULL; |
| *dma_handle = virt_to_bus(virt_ptr); |
| return virt_ptr; |
| } |
| |
| #define pci_free_consistent(cookie, size, ptr, dma_ptr) kfree(ptr) |
| #define pci_map_single(cookie, address, size, dir) virt_to_bus(address) |
| #define pci_map_sg(cookie, scatter, ents, dir) ents |
| #define pci_unmap_single(cookie, address, size, dir) |
| #define pci_unmap_sg(cookie, scatter, ents, dir) |
| |
| #define pci_resource_start(dev, i) dev->base_address[i] |
| #endif |
| |
| /* |
| * QLogic Driver Support Function Prototypes. |
| */ |
| static void qla1280_done(struct scsi_qla_host *, srb_t **, srb_t **); |
| static void qla1280_next(struct scsi_qla_host *, scsi_lu_t *, int); |
| static void qla1280_putq_t(scsi_lu_t *, srb_t *); |
| static void qla1280_done_q_put(srb_t *, srb_t **, srb_t **); |
| static int qla1280_slave_configure(Scsi_Device *); |
| #if STOP_ON_ERROR |
| static void qla1280_panic(char *, struct Scsi_Host *host); |
| #endif |
| static void qla1280_abort_queue_single(struct scsi_qla_host *, int, int, |
| int, uint32_t); |
| |
| static int qla1280_return_status(sts_entry_t * sts, Scsi_Cmnd * cp); |
| static void qla1280_removeq(scsi_lu_t * q, srb_t * sp); |
| static void qla1280_mem_free(struct scsi_qla_host *ha); |
| void qla1280_do_dpc(void *p); |
| #ifdef MODULE |
| static char *qla1280_get_token(char *, char *); |
| #endif |
| static inline void qla1280_enable_intrs(struct scsi_qla_host *); |
| static inline void qla1280_disable_intrs(struct scsi_qla_host *); |
| |
| /* |
| * QLogic ISP1280 Hardware Support Function Prototypes. |
| */ |
| static int qla1280_initialize_adapter(struct scsi_qla_host *ha); |
| static int qla1280_enable_tgt(struct scsi_qla_host *, int); |
| static int qla1280_isp_firmware(struct scsi_qla_host *); |
| static int qla1280_pci_config(struct scsi_qla_host *); |
| static int qla1280_chip_diag(struct scsi_qla_host *); |
| static int qla1280_setup_chip(struct scsi_qla_host *); |
| static int qla1280_init_rings(struct scsi_qla_host *); |
| static int qla1280_nvram_config(struct scsi_qla_host *); |
| static int qla1280_mailbox_command(struct scsi_qla_host *, |
| uint8_t, uint16_t *); |
| static int qla1280_bus_reset(struct scsi_qla_host *, int); |
| static int qla1280_device_reset(struct scsi_qla_host *, int, int); |
| static int qla1280_abort_device(struct scsi_qla_host *, int, int, int); |
| static int qla1280_abort_command(struct scsi_qla_host *, srb_t *); |
| static int qla1280_abort_isp(struct scsi_qla_host *); |
| static int qla1280_64bit_start_scsi(struct scsi_qla_host *, srb_t *); |
| static int qla1280_32bit_start_scsi(struct scsi_qla_host *, srb_t *); |
| static void qla1280_nv_write(struct scsi_qla_host *, uint16_t); |
| static void qla1280_poll(struct scsi_qla_host *); |
| static void qla1280_reset_adapter(struct scsi_qla_host *); |
| static void qla1280_marker(struct scsi_qla_host *, int, int, int, u8); |
| static void qla1280_isp_cmd(struct scsi_qla_host *); |
| static void qla1280_isr(struct scsi_qla_host *, srb_t **, srb_t **); |
| static void qla1280_rst_aen(struct scsi_qla_host *); |
| static void qla1280_status_entry(struct scsi_qla_host *, sts_entry_t *, |
| srb_t **, srb_t **); |
| static void qla1280_error_entry(struct scsi_qla_host *, response_t *, |
| srb_t **, srb_t **); |
| static void qla1280_restart_queues(struct scsi_qla_host *); |
| static void qla1280_abort_queues(struct scsi_qla_host *); |
| static uint16_t qla1280_get_nvram_word(struct scsi_qla_host *, uint32_t); |
| static uint16_t qla1280_nvram_request(struct scsi_qla_host *, uint32_t); |
| static uint16_t qla1280_debounce_register(volatile uint16_t *); |
| static request_t *qla1280_req_pkt(struct scsi_qla_host *); |
| static int qla1280_check_for_dead_scsi_bus(struct scsi_qla_host *, |
| unsigned int); |
| static int qla1280_mem_alloc(struct scsi_qla_host *ha); |
| |
| static void qla12160_get_target_parameters(struct scsi_qla_host *, |
| uint32_t, uint32_t, uint32_t); |
| |
| #if QL1280_LUN_SUPPORT |
| static void qla1280_enable_lun(struct scsi_qla_host *, int, int); |
| #endif |
| |
| #if QL1280_TARGET_MODE_SUPPORT |
| static void qla1280_notify_ack(struct scsi_qla_host *, notify_entry_t *); |
| static void qla1280_immed_notify(struct scsi_qla_host *, notify_entry_t *); |
| static void qla1280_accept_io(struct scsi_qla_host *, ctio_ret_entry_t *); |
| static void qla1280_64bit_continue_io(struct scsi_qla_host *, atio_entry_t *, |
| uint32_t, paddr32_t *); |
| static void qla1280_32bit_continue_io(struct scsi_qla_host *, atio_entry_t *, |
| uint32_t, paddr32_t *); |
| static void qla1280_atio_entry(struct scsi_qla_host *, atio_entry_t *); |
| static void qla1280_notify_entry(struct scsi_qla_host *, notify_entry_t *); |
| #endif /* QLA1280_TARGET_MODE_SUPPORT */ |
| |
| #ifdef QL_DEBUG_ROUTINES |
| /* |
| * Driver Debug Function Prototypes. |
| */ |
| static u8 qla1280_getbyte(u8 *); |
| static u16 qla1280_getword(u16 *); |
| static u32 qla1280_getdword(u32 *); |
| static void qla1280_putbyte(u8 *, u8); |
| static void qla1280_putword(u16 *, u8); |
| static void qla1280_putdword(u32 *, u32); |
| static void __qla1280_print_scsi_cmd(Scsi_Cmnd * cmd); |
| static void __qla1280_dump_buffer(char *, u32); |
| #endif |
| |
| /* |
| * insmod needs to find the variable and make it point to something |
| */ |
| #ifdef MODULE |
| static char *options = NULL; |
| |
| /* insmod qla1280 options=verbose" */ |
| MODULE_PARM(options, "s"); |
| #endif |
| |
| MODULE_LICENSE("GPL"); |
| |
| #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) |
| /* |
| * Our directory Entry in /proc/scsi for the user to |
| * access the driver. |
| */ |
| /* Need to add in proc_fs.h PROC_SCSI_QL1280 */ |
| #define PROC_SCSI_QL1280 PROC_SCSI_QLOGICISP |
| |
| struct proc_dir_entry proc_scsi_qla1280 = { |
| PROC_SCSI_QL1280, 7, "qla1280", |
| S_IFDIR | S_IRUGO | S_IXUGO, 2, |
| 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL |
| }; |
| #endif |
| |
| /* We use the Scsi_Pointer structure that's included with each command |
| * SCSI_Cmnd as a scratchpad for our SRB. |
| * |
| * SCp will always point to the SRB structure (defined in qla1280.h). |
| * It is define as follows: |
| * - SCp.ptr -- > pointer back to the cmd |
| * - SCp.this_residual --> used as forward pointer to next srb |
| * - SCp.buffer --> used as backward pointer to next srb |
| * - SCp.buffers_residual --> used as flags field |
| * - SCp.have_data_in --> not used |
| * - SCp.sent_command --> not used |
| * - SCp.phase --> not used |
| */ |
| |
| #define CMD_SP(Cmnd) &Cmnd->SCp |
| #define CMD_CDBLEN(Cmnd) Cmnd->cmd_len |
| #define CMD_CDBP(Cmnd) Cmnd->cmnd |
| #define CMD_SNSP(Cmnd) Cmnd->sense_buffer |
| #define CMD_SNSLEN(Cmnd) sizeof(Cmnd->sense_buffer) |
| #define CMD_RESULT(Cmnd) Cmnd->result |
| #define CMD_HANDLE(Cmnd) Cmnd->host_scribble |
| |
| /*****************************************/ |
| /* ISP Boards supported by this driver */ |
| /*****************************************/ |
| |
| #define NUM_OF_ISP_DEVICES 6 |
| |
| struct qla_boards { |
| unsigned char bdName[9]; /* Board ID String */ |
| unsigned long device_id; /* Device PCI ID */ |
| int numPorts; /* Number of SCSI ports */ |
| unsigned short *fwcode; /* pointer to FW array */ |
| unsigned short *fwlen; /* number of words in array */ |
| unsigned short *fwstart; /* start address for F/W */ |
| unsigned char *fwver; /* Ptr to F/W version array */ |
| }; |
| |
| struct qla_boards ql1280_board_tbl[NUM_OF_ISP_DEVICES] = { |
| /* Name , Board PCI Device ID, Number of ports */ |
| {"QLA12160 ", PCI_DEVICE_ID_QLOGIC_ISP12160, 2, |
| &fw12160i_code01[0], &fw12160i_length01, |
| &fw12160i_addr01, &fw12160i_version_str[0]}, |
| {"QLA1080 ", PCI_DEVICE_ID_QLOGIC_ISP1080, 1, |
| &fw1280ei_code01[0], &fw1280ei_length01, |
| &fw1280ei_addr01, &fw1280ei_version_str[0]}, |
| {"QLA1240 ", PCI_DEVICE_ID_QLOGIC_ISP1240, 2, |
| &fw1280ei_code01[0], &fw1280ei_length01, |
| &fw1280ei_addr01, &fw1280ei_version_str[0]}, |
| {"QLA1280 ", PCI_DEVICE_ID_QLOGIC_ISP1280, 2, |
| &fw1280ei_code01[0], &fw1280ei_length01, |
| &fw1280ei_addr01, &fw1280ei_version_str[0]}, |
| {"QLA10160 ", PCI_DEVICE_ID_QLOGIC_ISP10160, 1, |
| &fw12160i_code01[0], &fw12160i_length01, |
| &fw12160i_addr01, &fw12160i_version_str[0]}, |
| {" ", 0, 0} |
| }; |
| |
| static int qla1280_verbose = 1; |
| static struct scsi_qla_host *qla1280_hostlist = NULL; |
| #if QLA1280_PROFILE |
| static int qla1280_buffer_size = 0; |
| static char *qla1280_buffer = NULL; |
| #endif |
| |
| #if DEBUG_QLA1280 |
| static int ql_debug_print = 1; |
| char debug_buff[80]; |
| #define DEBUG(x) x |
| static int ql_debug_level = 0; |
| #define dprintk(level, format, a...) \ |
| if ((ql_debug_level >= level) && ql_debug_print) printk(KERN_DEBUG format, ##a) |
| #define qla1280_dump_buffer(level, buf, size) \ |
| if (ql_debug_level >= level) __qla1280_dump_buffer(buf, size) |
| #define qla1280_dump_print_cmd(level, cmd) \ |
| if (ql_debug_level >= level) __qla1280_print_scsi_cmd(cmd) |
| #else |
| #define DEBUG(x) |
| #define ql_debug_level 0 |
| #define dprintk(level, format, a...) do{}while(0) |
| #define qla1280_dump_buffer(a, b, c) do{}while(0) |
| #define qla1280_print_scsi_cmd(a, b) do{}while(0) |
| #endif |
| |
| #define ENTER(x) dprintk(3, "qla1280 : Entering %s()\n", x); |
| #define LEAVE(x) dprintk(3, "qla1280 : Leaving %s()\n", x); |
| #define ENTER_INTR(x) dprintk(3, "qla1280 : Entering %s()\n", x); |
| #define LEAVE_INTR(x) dprintk(3, "qla1280 : Leaving %s()\n", x); |
| |
| #define SCSI_BUS_32(scp) scp->device->channel |
| #define SCSI_TCN_32(scp) scp->device->id |
| #define SCSI_LUN_32(scp) scp->device->lun |
| |
| /****************************************************************************/ |
| /* LINUX - Loadable Module Functions. */ |
| /****************************************************************************/ |
| |
| /************************************************************************* |
| * qla1280_set_info |
| * |
| * Description: |
| * Set parameters for the driver from the /proc filesystem. |
| * |
| * Returns: |
| *************************************************************************/ |
| int |
| qla1280_set_info(char *buffer, int length, struct Scsi_Host *HBAptr) |
| { |
| return -ENOSYS; /* Currently this is a no-op */ |
| } |
| |
| /************************************************************************* |
| * qla1280_proc_info |
| * |
| * Description: |
| * Return information to handle /proc support for the driver. |
| * |
| * buffer - ptrs to a page buffer |
| * |
| * Returns: |
| *************************************************************************/ |
| #define PROC_BUF &qla1280_buffer[len] |
| |
| int |
| qla1280_proc_info(char *buffer, char **start, off_t offset, int length, |
| int hostno, int inout) |
| { |
| #if QLA1280_PROFILE |
| struct Scsi_Host *host; |
| struct scsi_qla_host *ha; |
| int size = 0; |
| scsi_lu_t *up; |
| int len = 0; |
| struct qla_boards *bdp; |
| uint32_t b, t, l; |
| host = NULL; |
| |
| /* Find the host that was specified */ |
| for (ha = qla1280_hostlist; (ha != NULL) && ha->host->host_no != hostno; |
| ha = ha->next) ; |
| |
| /* if host wasn't found then exit */ |
| if (!ha) { |
| size = sprintf(buffer, "Can't find adapter for host " |
| "number %d\n", hostno); |
| if (size > length) { |
| return size; |
| } else { |
| return 0; |
| } |
| } |
| |
| host = ha->host; |
| |
| if (inout == TRUE) { /* Has data been written to the file? */ |
| printk(KERN_INFO |
| "qla1280_proc: has data been written to the file.\n"); |
| return qla1280_set_info(buffer, length, host); |
| } |
| |
| /* |
| * if our old buffer is the right size use it otherwise |
| * allocate a new one. |
| */ |
| if (qla1280_buffer_size != PAGE_SIZE) { |
| /* deallocate this buffer and get a new one */ |
| if (qla1280_buffer != NULL) { |
| free_page((unsigned long)qla1280_buffer); |
| qla1280_buffer_size = 0; |
| } |
| qla1280_buffer = (char *)get_zeroed_page(GFP_KERNEL); |
| } |
| if (qla1280_buffer == NULL) { |
| size = sprintf(buffer, "qla1280 - kmalloc error at line %d\n", |
| __LINE__); |
| return size; |
| } |
| /* save the size of our buffer */ |
| qla1280_buffer_size = PAGE_SIZE; |
| |
| /* 3.20 clear the buffer we use for proc display */ |
| memset(qla1280_buffer, 0, PAGE_SIZE); |
| |
| /* start building the print buffer */ |
| bdp = &ql1280_board_tbl[ha->devnum]; |
| size = sprintf(PROC_BUF, |
| "QLogic PCI to SCSI Adapter for ISP 1280/12160:\n" |
| " Firmware version: %2d.%02d.%02d, Driver version %s\n", |
| bdp->fwver[0], bdp->fwver[1], bdp->fwver[2], |
| QLA1280_VERSION); |
| |
| len += size; |
| |
| size = sprintf(PROC_BUF, "SCSI Host Adapter Information: %s\n", |
| bdp->bdName); |
| len += size; |
| size = sprintf(PROC_BUF, "Request Queue = 0x%p, Response Queue = 0x%p\n", |
| (void *)ha->request_dma, (void *)ha->response_dma); |
| len += size; |
| size = sprintf(PROC_BUF, "Request Queue count= 0x%x, Response " |
| "Queue count= 0x%x\n", |
| REQUEST_ENTRY_CNT, RESPONSE_ENTRY_CNT); |
| len += size; |
| size = sprintf(PROC_BUF, "Number of pending commands = 0x%lx\n", |
| ha->actthreads); |
| len += size; |
| size = sprintf(PROC_BUF, "Number of queued commands = 0x%lx\n", |
| ha->qthreads); |
| len += size; |
| size = sprintf(PROC_BUF, "Number of free request entries = %d\n", |
| ha->req_q_cnt); |
| len += size; |
| size = sprintf(PROC_BUF, "\n"); /* 1 */ |
| len += size; |
| |
| size = sprintf(PROC_BUF, "SCSI device Information:\n"); |
| len += size; |
| /* scan for all equipment stats */ |
| for (b = 0; b < MAX_BUSES; b++) |
| for (t = 0; t < MAX_TARGETS; t++) { |
| for (l = 0; l < MAX_LUNS; l++) { |
| up = LU_Q(ha, b, t, l); |
| if (up == NULL) |
| continue; |
| /* unused device/lun */ |
| if (up->io_cnt == 0 || up->io_cnt < 2) |
| continue; |
| /* total reads since boot */ |
| /* total writes since boot */ |
| /* total requests since boot */ |
| size = sprintf (PROC_BUF, |
| "(%2d:%2d:%2d): Total reqs %ld,", |
| b, t, l, up->io_cnt); |
| len += size; |
| /* current number of pending requests */ |
| size = sprintf(PROC_BUF, " Pend reqs %d,", |
| up->q_outcnt); |
| len += size; |
| #if 0 |
| /* avg response time */ |
| size = sprintf(PROC_BUF, " Avg resp time %ld%%,", |
| (up->resp_time / up->io_cnt) * |
| 100); |
| len += size; |
| |
| /* avg active time */ |
| size = sprintf(PROC_BUF, |
| " Avg active time %ld%%\n", |
| (up->act_time / up->io_cnt) * 100); |
| #else |
| size = sprintf(PROC_BUF, "\n"); |
| #endif |
| len += size; |
| } |
| if (len >= qla1280_buffer_size) |
| break; |
| } |
| |
| if (len >= qla1280_buffer_size) { |
| printk(KERN_WARNING |
| "qla1280: Overflow buffer in qla1280_proc.c\n"); |
| } |
| |
| if (offset > len - 1) { |
| free_page((unsigned long) qla1280_buffer); |
| qla1280_buffer = NULL; |
| qla1280_buffer_size = length = 0; |
| *start = NULL; |
| } else { |
| *start = &qla1280_buffer[offset]; /* Start of wanted data */ |
| if (len - offset < length) { |
| length = len - offset; |
| } |
| } |
| return length; |
| #else |
| return 0; |
| #endif |
| } |
| |
| /************************************************************************** |
| * qla1280_do_device_init |
| * This routine will register the device with the SCSI subsystem, |
| * initialize the host adapter structure and call the device init |
| * routines. |
| * |
| * Input: |
| * pdev - pointer to struct pci_dev for adapter |
| * template - pointer to SCSI template |
| * devnum - the device number |
| * bdp - pointer to struct _qlaboards |
| * num_hosts - the host number |
| * |
| * Returns: |
| * host - pointer to SCSI host structure |
| **************************************************************************/ |
| struct Scsi_Host * |
| qla1280_do_device_init(struct pci_dev *pdev, |
| Scsi_Host_Template * template, |
| int devnum, struct qla_boards *bdp, int num_hosts) |
| { |
| struct Scsi_Host *host; |
| struct scsi_qla_host *ha; |
| struct device_reg *reg; |
| |
| printk("qla1x160: Initializing ISP12160 on PCI bus %i, dev %i, irq %i\n", |
| pdev->bus->number, PCI_SLOT(pdev->devfn), pdev->irq); |
| |
| host = scsi_register(template, sizeof(struct scsi_qla_host)); |
| if (!host) { |
| printk(KERN_WARNING |
| "qla1280: Failed to register host, aborting.\n"); |
| goto error; |
| } |
| |
| scsi_set_device(host, &pdev->dev); |
| ha = (struct scsi_qla_host *)host->hostdata; |
| /* Clear our data area */ |
| memset(ha, 0, sizeof(struct scsi_qla_host)); |
| /* Sanitize the information from PCI BIOS. */ |
| host->irq = pdev->irq; |
| ha->pci_bus = pdev->bus->number; |
| ha->pci_device_fn = pdev->devfn; |
| ha->pdev = pdev; |
| ha->device_id = bdp->device_id; |
| ha->devnum = devnum; /* specifies microcode load address */ |
| |
| if (qla1280_mem_alloc(ha)) { |
| printk(KERN_INFO "qla1x160: Failed to get memory\n"); |
| goto error; |
| } |
| |
| ha->ports = bdp->numPorts; |
| /* following needed for all cases of OS versions */ |
| ha->host = host; |
| ha->host_no = host->host_no; |
| |
| host->can_queue = 0xfffff; /* unlimited */ |
| host->cmd_per_lun = 1; |
| #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) |
| host->base = (unsigned char *)ha->mmpbase; |
| #else |
| host->base = (unsigned long)ha->mmpbase; |
| #endif |
| host->max_channel = bdp->numPorts - 1; |
| host->max_lun = MAX_LUNS - 1; |
| host->max_id = MAX_TARGETS; |
| #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7) |
| host->max_sectors = 1024; |
| #endif |
| |
| ha->instance = num_hosts; |
| host->unique_id = ha->instance; |
| |
| if (qla1280_pci_config(ha)) { |
| printk(KERN_INFO "qla1x160: Unable to configure PCI\n"); |
| goto error_mem_alloced; |
| } |
| |
| /* Disable ISP interrupts. */ |
| qla1280_disable_intrs(ha); |
| |
| /* Register the IRQ with Linux (sharable) */ |
| if (request_irq(host->irq, qla1280_intr_handler, SA_SHIRQ, |
| "qla1280", ha)) { |
| printk("qla1280 : Failed to reserve interrupt %d already " |
| "in use\n", host->irq); |
| goto error_unmap; |
| } |
| #if !MEMORY_MAPPED_IO |
| /* Register the I/O space with Linux */ |
| if (!request_region(host->io_port, 0xff, "qla1280")) { |
| printk("qla1280 : Failed to reserve i/o region 0x%04lx-0x%04lx" |
| " already in use\n", |
| host->io_port, host->io_port + 0xff); |
| goto error_irq; |
| } |
| |
| #endif |
| |
| reg = ha->iobase; |
| |
| /* load the F/W, read paramaters, and init the H/W */ |
| if (qla1280_initialize_adapter(ha)) { |
| printk(KERN_INFO "qla1x160:Failed to initialize adapter\n"); |
| goto error_region; |
| } |
| |
| /* set our host ID (need to do something about our two IDs) */ |
| host->this_id = ha->bus_settings[0].id; |
| |
| return host; |
| |
| error_region: |
| #if !MEMORY_MAPPED_IO |
| release_region(host->io_port, 0xff); |
| #endif |
| |
| error_irq: |
| free_irq(host->irq, ha); |
| |
| error_unmap: |
| #if MEMORY_MAPPED_IO |
| if (ha->mmpbase) |
| iounmap((void *)(((unsigned long) ha->mmpbase) & PAGE_MASK)); |
| #endif |
| |
| |
| error_mem_alloced: |
| qla1280_mem_free(ha); |
| |
| error: |
| if (host) { |
| scsi_unregister(host); |
| } |
| return NULL; |
| } |
| |
| /************************************************************************** |
| * qla1280_detect |
| * This routine will probe for Qlogic 1280 SCSI host adapters. |
| * It returns the number of host adapters of a particular |
| * type that were found. It also initialize all data necessary for |
| * the driver. It is passed-in the host number, so that it |
| * knows where its first entry is in the scsi_hosts[] array. |
| * |
| * Input: |
| * template - pointer to SCSI template |
| * |
| * Returns: |
| * num - number of host adapters found. |
| **************************************************************************/ |
| int |
| qla1280_detect(Scsi_Host_Template * template) |
| { |
| struct pci_dev *pdev = NULL; |
| struct Scsi_Host *host; |
| struct scsi_qla_host *ha, *cur_ha; |
| struct qla_boards *bdp; |
| uint16_t subsys_vendor, subsys_device; |
| int num_hosts = 0; |
| int devnum = 0; |
| |
| ENTER("qla1280_detect"); |
| |
| if (sizeof(srb_t) > sizeof(Scsi_Pointer)) { |
| printk(KERN_WARNING |
| "qla1280_detect: [WARNING] srb_t too big\n"); |
| return 0; |
| } |
| #ifdef MODULE |
| dprintk(1, "DEBUG: qla1280_detect starts at address = %p\n", |
| qla1280_detect); |
| /* |
| * If we are called as a module, the qla1280 pointer may not be null |
| * and it would point to our bootup string, just like on the lilo |
| * command line. IF not NULL, then process this config string with |
| * qla1280_setup |
| * |
| * Boot time Options |
| * To add options at boot time add a line to your lilo.conf file like: |
| * append="qla1280=verbose,max_tags:{{255,255,255,255},{255,255,255,255}}" |
| * which will result in the first four devices on the first two |
| * controllers being set to a tagged queue depth of 32. |
| */ |
| if (options) |
| qla1280_setup(options, NULL); |
| |
| printk(KERN_WARNING |
| "qla1280: Please read the file /usr/src/linux/Documentation" |
| "/scsi/qla1280.txt\n" |
| "qla1280: to see the proper way to specify options to the qla1280 " |
| "module\n" |
| "qla1280: Specifically, don't use any commas when passing " |
| "arguments to\n" |
| "qla1280: insmod or else it might trash certain memory areas.\n"); |
| #endif |
| |
| if (!pci_present()) { |
| printk(KERN_INFO "scsi: PCI not present\n"); |
| return 0; |
| } |
| |
| bdp = &ql1280_board_tbl[0]; |
| qla1280_hostlist = NULL; |
| #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) |
| template->proc_dir = &proc_scsi_qla1280; |
| #else |
| template->proc_name = "qla1280"; |
| #endif |
| |
| /* 3.20 */ |
| /* First Initialize QLA12160 on PCI Bus 1 Dev 2 */ |
| while ((pdev = pci_find_subsys(PCI_VENDOR_ID_QLOGIC, bdp->device_id, |
| PCI_ANY_ID, PCI_ANY_ID, pdev))) { |
| |
| /* find QLA12160 device on PCI bus=1 slot=2 */ |
| if ((pdev->bus->number != 1) || (PCI_SLOT(pdev->devfn) != 2)) |
| continue; |
| |
| /* Bypass all AMI SUBSYS VENDOR IDs */ |
| if (pdev->subsystem_vendor == PCI_VENDOR_ID_AMI) { |
| printk(KERN_INFO |
| "qla1x160: Skip AMI SubSys Vendor ID Chip\n"); |
| continue; |
| } |
| |
| if (pci_enable_device(pdev)) |
| goto find_devices; |
| |
| host = qla1280_do_device_init(pdev, template, devnum, |
| bdp, num_hosts); |
| if (!host) |
| continue; |
| ha = (struct scsi_qla_host *)host->hostdata; |
| |
| /* this preferred device will always be the first one found */ |
| cur_ha = qla1280_hostlist = ha; |
| num_hosts++; |
| } |
| |
| find_devices: |
| |
| pdev = NULL; |
| /* Try and find each different type of adapter we support */ |
| for (devnum = 0; bdp->device_id != 0 && devnum < NUM_OF_ISP_DEVICES; |
| devnum++, bdp++) { |
| /* PCI_SUBSYSTEM_IDS supported */ |
| while ((pdev = pci_find_subsys(PCI_VENDOR_ID_QLOGIC, |
| bdp->device_id, PCI_ANY_ID, |
| PCI_ANY_ID, pdev))) { |
| if (pci_enable_device(pdev)) |
| continue; |
| /* found an adapter */ |
| #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,18) |
| subsys_vendor = pdev->subsystem_vendor; |
| subsys_device = pdev->subsystem_device; |
| #else |
| pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, |
| &subsys_vendor); |
| pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, |
| &subsys_device); |
| #endif |
| /* |
| * skip QLA12160 already initialized on |
| * PCI Bus 1 Dev 2 since we already initialized |
| * and presented it |
| */ |
| if ((bdp->device_id == PCI_DEVICE_ID_QLOGIC_ISP12160)&& |
| (pdev->bus->number == 1) && |
| (PCI_SLOT(pdev->devfn) == 2)) |
| continue; |
| |
| /* Bypass all AMI SUBSYS VENDOR IDs */ |
| if (subsys_vendor == PCI_VENDOR_ID_AMI) { |
| printk(KERN_INFO |
| "qla1x160: Skip AMI SubSys Vendor ID Chip\n"); |
| continue; |
| } |
| printk(KERN_INFO |
| "qla1x160: Supported Device Found VID=%x " |
| "DID=%x SSVID=%x SSDID=%x\n", pdev->vendor, |
| pdev->device, subsys_vendor, subsys_device); |
| |
| host = qla1280_do_device_init(pdev, template, |
| devnum, bdp, num_hosts); |
| if (!host) |
| continue; |
| ha = (struct scsi_qla_host *)host->hostdata; |
| |
| if (qla1280_hostlist == NULL) { |
| cur_ha = qla1280_hostlist = ha; |
| } else { |
| cur_ha = qla1280_hostlist; |
| while (cur_ha->next != NULL) |
| cur_ha = cur_ha->next; |
| cur_ha->next = ha; |
| } |
| num_hosts++; |
| } /* end of WHILE */ |
| } /* end of FOR */ |
| |
| LEAVE("qla1280_detect"); |
| return num_hosts; |
| } |
| |
| /************************************************************************** |
| * qla1280_release |
| * Free the passed in Scsi_Host memory structures prior to unloading the |
| * module. |
| **************************************************************************/ |
| int |
| qla1280_release(struct Scsi_Host *host) |
| { |
| struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata; |
| |
| ENTER("qla1280_release"); |
| |
| if (!ha->flags.online) |
| return 0; |
| |
| /* turn-off interrupts on the card */ |
| WRT_REG_WORD(&ha->iobase->ictrl, 0); |
| |
| /* Detach interrupts */ |
| if (host->irq) |
| free_irq(host->irq, ha); |
| |
| #if MEMORY_MAPPED_IO |
| if (ha->mmpbase) |
| iounmap((void *)(((unsigned long) ha->mmpbase) & PAGE_MASK)); |
| #else |
| /* release io space registers */ |
| if (host->io_port) |
| release_region(host->io_port, 0xff); |
| #endif /* MEMORY_MAPPED_IO */ |
| |
| qla1280_mem_free(ha); |
| |
| ENTER("qla1280_release"); |
| return 0; |
| } |
| |
| /************************************************************************** |
| * qla1280_info |
| * Return a string describing the driver. |
| **************************************************************************/ |
| const char * |
| qla1280_info(struct Scsi_Host *host) |
| { |
| static char qla1280_scsi_name_buffer[125]; |
| char *bp; |
| struct scsi_qla_host *ha; |
| struct qla_boards *bdp; |
| |
| bp = &qla1280_scsi_name_buffer[0]; |
| ha = (struct scsi_qla_host *)host->hostdata; |
| bdp = &ql1280_board_tbl[ha->devnum]; |
| memset(bp, 0, sizeof(qla1280_scsi_name_buffer)); |
| sprintf (bp, |
| "QLogic %s PCI to SCSI Host Adapter: bus %d device %d irq %d\n" |
| " Firmware version: %2d.%02d.%02d, Driver version %s", |
| &bdp->bdName[0], ha->pci_bus, (ha->pci_device_fn & 0xf8) >> 3, |
| host->irq, bdp->fwver[0], bdp->fwver[1], bdp->fwver[2], |
| QLA1280_VERSION); |
| return bp; |
| } |
| |
| /************************************************************************** |
| * qla1200_queuecommand |
| * Queue a command to the controller. |
| * |
| * Note: |
| * The mid-level driver tries to ensures that queuecommand never gets invoked |
| * concurrently with itself or the interrupt handler (although the |
| * interrupt handler may call this routine as part of request-completion |
| * handling). Unfortunely, it sometimes calls the scheduler in interrupt |
| * context which is a big NO! NO!. |
| **************************************************************************/ |
| int |
| qla1280_queuecommand(Scsi_Cmnd * cmd, void (*fn) (Scsi_Cmnd *)) |
| { |
| struct scsi_qla_host *ha; |
| srb_t *sp; |
| struct Scsi_Host *host; |
| int bus, target, lun; |
| scsi_lu_t *q; |
| |
| /*ENTER("qla1280_queuecommand"); |
| */ |
| |
| host = cmd->device->host; |
| ha = (struct scsi_qla_host *)host->hostdata; |
| |
| /* send command to adapter */ |
| sp = (srb_t *)CMD_SP(cmd); |
| sp->cmd = cmd; |
| cmd->scsi_done = fn; |
| if (cmd->flags == 0) { /* new command */ |
| sp->flags = 0; |
| } |
| |
| qla1280_print_scsi_cmd(5, cmd); |
| |
| /* Generate LU queue on bus, target, LUN */ |
| bus = SCSI_BUS_32(cmd); |
| target = SCSI_TCN_32(cmd); |
| lun = SCSI_LUN_32(cmd); |
| if ((q = LU_Q(ha, bus, target, lun)) == NULL) { |
| if ((q = (scsi_lu_t *)kmalloc(sizeof(struct scsi_lu), |
| GFP_ATOMIC))) { |
| LU_Q(ha, bus, target, lun) = q; |
| memset(q, 0, sizeof(struct scsi_lu)); |
| dprintk(1, "Allocate new device queue 0x%p\n", |
| (void *)q); |
| } else { |
| CMD_RESULT(cmd) = DID_BUS_BUSY << 16; |
| qla1280_done_q_put(sp, &ha->done_q_first, |
| &ha->done_q_last); |
| /* 3.22 */ |
| #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) /* 3.22 */ |
| schedule_work(&ha->run_qla_bh); |
| #else /* 3.22 */ |
| schedule_work(&ha->run_qla_bh); /* 3.22 */ |
| #endif /* 3.22 */ |
| return 0; |
| } |
| } |
| /* Set an invalid handle until we issue the command to ISP */ |
| /* then we will set the real handle value. */ |
| CMD_HANDLE(cmd) = (unsigned char *)INVALID_HANDLE; |
| |
| /* add the command to our queue */ |
| ha->qthreads++; |
| qla1280_putq_t(q, sp); |
| |
| dprintk(1, "qla1280_QC: t=%x CDB=%x I/OSize=0x%x haQueueCount=0x%lx\n", |
| target, cmd->cmnd[0], cmd->request_bufflen, ha->qthreads); |
| |
| /* send command to adapter */ |
| if (q->q_outcnt == 0) |
| qla1280_restart_queues(ha); |
| |
| /*LEAVE("qla1280_queuecommand"); */ |
| return 0; |
| } |
| |
| /************************************************************************** |
| * qla1200_abort |
| * Abort the speciifed SCSI command(s). |
| **************************************************************************/ |
| int |
| qla1280_abort(Scsi_Cmnd * cmd) |
| { |
| struct scsi_qla_host *ha; |
| srb_t *sp; |
| struct Scsi_Host *host; |
| unsigned int bus, target, lun; |
| scsi_lu_t *q; |
| int return_status = SCSI_ABORT_SUCCESS; |
| int found = 0; |
| int i; |
| unsigned char *handle; |
| u16 data; |
| |
| ENTER("qla1280_abort"); |
| ha = (struct scsi_qla_host *)cmd->device->host->hostdata; |
| host = cmd->device->host; |
| |
| /* Get the SCSI request ptr */ |
| sp = (srb_t *)CMD_SP(cmd); |
| handle = CMD_HANDLE(cmd); |
| if (qla1280_verbose) |
| printk(KERN_ERR "scsi(%li): ABORT Command=0x%p, handle=0x%p\n", |
| ha->host_no, (void *) cmd, (void *) handle); |
| |
| /* Check for pending interrupts. */ |
| if (handle == NULL) { |
| /* we never got this command */ |
| printk(KERN_INFO "qla1280: Aborting a NULL handle\n"); |
| return SCSI_ABORT_NOT_RUNNING; /* no action - we don't have command */ |
| } |
| data = qla1280_debounce_register(&ha->iobase->istatus); |
| /* |
| * The io_request_lock is held when the reset handler is called, hence |
| * the interrupt handler cannot be running in parallel as it also |
| * grabs the lock. No reason to play funny games with set_bit() in |
| * order to test for interrupt handler entry as the driver used to |
| * do here. |
| * /Jes |
| */ |
| if (data & RISC_INT) { |
| /* put any pending command in done queue */ |
| qla1280_isr(ha, &ha->done_q_first, &ha->done_q_last); |
| } |
| |
| /* |
| * This seems unnecessary, it's not used below! / Jes |
| */ |
| #ifdef UNUSED |
| handle = CMD_HANDLE(cmd); |
| #endif |
| |
| /* Generate LU queue on bus, target, LUN */ |
| bus = SCSI_BUS_32(cmd); |
| target = SCSI_TCN_32(cmd); |
| lun = SCSI_LUN_32(cmd); |
| if ((q = LU_Q(ha, bus, target, lun)) == NULL) { |
| /* No lun queue -- command must not be active */ |
| printk(KERN_WARNING "qla1280 (%d:%d:%d): No LUN queue for the " |
| "specified device\n", bus, target, lun); |
| return SCSI_ABORT_NOT_RUNNING; /* no action - we don't have command */ |
| } |
| #if AUTO_ESCALATE_ABORT |
| if ((sp->flags & SRB_ABORTED)) { |
| dprintk(1, "qla1280_abort: Abort escalayted - returning " |
| "SCSI_ABORT_SNOOZE.\n"); |
| return SCSI_ABORT_SNOOZE; |
| } |
| #endif |
| |
| if ((sp->flags & SRB_ABORT_PENDING)) { |
| if (qla1280_verbose) |
| printk(KERN_WARNING |
| "scsi(): Command has a pending abort " |
| "message - ABORT_PENDING.\n"); |
| |
| return SCSI_ABORT_PENDING; |
| } |
| #if STOP_ON_ABORT |
| printk(KERN_WARNING "Scsi layer issued a ABORT command= 0x%p\n", cmd); |
| qla1280_print_scsi_cmd(2, cmd); |
| #endif |
| |
| /* |
| * Normally, would would need to search our queue for the specified command |
| * but; since our sp contains the cmd ptr, we can just remove it from our |
| * LUN queue. |
| */ |
| if (!(sp->flags & SRB_SENT)) { |
| found++; |
| if (qla1280_verbose) |
| printk(KERN_WARNING |
| "scsi(): Command returned from queue " |
| "aborted.\n"); |
| |
| /* Remove srb from SCSI LU queue. */ |
| qla1280_removeq(q, sp); |
| sp->flags |= SRB_ABORTED; |
| CMD_RESULT(cmd) = DID_ABORT << 16; |
| qla1280_done_q_put(sp, &ha->done_q_first, &ha->done_q_last); |
| return_status = SCSI_ABORT_SUCCESS; |
| } else { /* find the command in our active list */ |
| for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) { |
| if (sp == ha->outstanding_cmds[i]) { |
| found++; |
| dprintk(1, |
| "qla1280: RISC aborting command.\n"); |
| qla1280_abort_command(ha, sp); |
| return_status = SCSI_ABORT_PENDING; |
| break; |
| } |
| } |
| } |
| |
| #if STOP_ON_ABORT |
| qla1280_panic("qla1280_abort", ha->host); |
| #endif |
| if (found == 0) |
| return_status = SCSI_ABORT_NOT_RUNNING; /* no action - we don't have command */ |
| |
| dprintk(1, "qla1280_abort: Aborted status returned = 0x%x.\n", |
| return_status); |
| |
| if (ha->done_q_first) |
| qla1280_done(ha, &ha->done_q_first, &ha->done_q_last); |
| if (found) |
| qla1280_restart_queues(ha); |
| |
| LEAVE("qla1280_abort"); |
| return return_status; |
| } |
| |
| int |
| qla1280_new_abort(Scsi_Cmnd * cmd) |
| { |
| struct scsi_qla_host *ha; |
| srb_t *sp; |
| struct Scsi_Host *host; |
| int bus, target, lun; |
| scsi_lu_t *q; |
| unsigned long cpu_flags; |
| int return_status = SCSI_ABORT_SUCCESS; |
| int found = 0; |
| int i; |
| unsigned char *handle; |
| u16 data; |
| |
| ENTER("qla1280_abort"); |
| host = cmd->device->host; |
| ha = (struct scsi_qla_host *)host->hostdata; |
| |
| /* Get the SCSI request ptr */ |
| sp = (srb_t *) CMD_SP(cmd); |
| handle = CMD_HANDLE(cmd); |
| if (qla1280_verbose) |
| printk(KERN_ERR "scsi(%li): ABORT Command=0x%p, handle=0x%p\n", |
| ha->host_no, cmd, handle); |
| |
| /* Check for pending interrupts. */ |
| if (handle == NULL) { |
| /* we never got this command */ |
| printk(KERN_INFO "qla1280: Aborting a NULL handle\n"); |
| return SUCCESS; /* no action - we don't have command */ |
| } |
| |
| spin_lock_irqsave (ha->host->host_lock, cpu_flags); |
| data = qla1280_debounce_register(&ha->iobase->istatus); |
| /* |
| * We grab the host lock in the interrupt handler to |
| * prevent racing here. |
| * |
| * Then again, running the interrupt handler from here is somewhat |
| * questionable. |
| * /Jes |
| */ |
| if (data & RISC_INT) { |
| /* put any pending command in done queue */ |
| qla1280_isr(ha, &ha->done_q_first, &ha->done_q_last); |
| } |
| |
| /* Generate LU queue on bus, target, LUN */ |
| bus = SCSI_BUS_32(cmd); |
| target = SCSI_TCN_32(cmd); |
| lun = SCSI_LUN_32(cmd); |
| if ((q = LU_Q(ha, bus, target, lun)) == NULL) { |
| /* No lun queue -- command must not be active */ |
| printk(KERN_WARNING "qla1280 (%d:%d:%d): No LUN queue for the " |
| "specified device\n", bus, target, lun); |
| return_status = SUCCESS; /* no action - we don't have command */ |
| goto out; |
| } |
| |
| if ((sp->flags & SRB_ABORT_PENDING)) { |
| if (qla1280_verbose) |
| printk(KERN_WARNING |
| "scsi(): Command has a pending abort " |
| "message - ABORT_PENDING.\n"); |
| |
| return_status = SCSI_ABORT_PENDING; |
| goto out; |
| } |
| #if STOP_ON_ABORT |
| printk(KERN_WARNING "Scsi layer issued a ABORT command= 0x%p\n", cmd); |
| qla1280_print_scsi_cmd(2, cmd); |
| #endif |
| |
| /* |
| * Normally, would would need to search our queue for the specified command |
| * but; since our sp contains the cmd ptr, we can just remove it from our |
| * LUN queue. |
| */ |
| if (!(sp->flags & SRB_SENT)) { |
| found++; |
| if (qla1280_verbose) |
| printk(KERN_WARNING |
| "scsi(): Command returned from queue " |
| "aborted.\n"); |
| |
| /* Remove srb from SCSI LU queue. */ |
| qla1280_removeq(q, sp); |
| sp->flags |= SRB_ABORTED; |
| CMD_RESULT(cmd) = DID_ABORT << 16; |
| qla1280_done_q_put(sp, &ha->done_q_first, &ha->done_q_last); |
| return_status = SUCCESS; |
| } else { /* find the command in our active list */ |
| for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) { |
| if (sp == ha->outstanding_cmds[i]) { |
| found++; |
| dprintk(1, |
| "qla1280: RISC aborting command.\n"); |
| qla1280_abort_command(ha, sp); |
| return_status = SCSI_ABORT_PENDING; |
| break; |
| } |
| } |
| } |
| |
| #if STOP_ON_ABORT |
| qla1280_panic("qla1280_abort", ha->host); |
| #endif |
| if (found == 0) |
| return_status = SUCCESS; /* no action - we don't have the command */ |
| |
| dprintk(1, "qla1280_abort: Aborted status returned = 0x%x.\n", |
| return_status); |
| |
| if (ha->done_q_first) |
| qla1280_done(ha, &ha->done_q_first, &ha->done_q_last); |
| if (found) |
| qla1280_restart_queues(ha); |
| |
| out: |
| spin_unlock_irqrestore(ha->host->host_lock, cpu_flags); |
| |
| LEAVE("qla1280_abort"); |
| return return_status; |
| } |
| |
| /************************************************************************** |
| * qla1200_reset |
| * The reset function will reset the SCSI bus and abort any executing |
| * commands. |
| * |
| * Input: |
| * cmd = Linux SCSI command packet of the command that cause the |
| * bus reset. |
| * flags = SCSI bus reset option flags (see scsi.h) |
| * |
| * Returns: |
| * DID_RESET in cmd.host_byte of aborted command(s) |
| * |
| * Note: |
| * Resetting the bus always succeeds - is has to, otherwise the |
| * kernel will panic! Try a surgical technique - sending a BUS |
| * DEVICE RESET message - on the offending target before pulling |
| * the SCSI bus reset line. |
| **************************************************************************/ |
| int |
| qla1280_reset(Scsi_Cmnd * cmd, unsigned int flags) |
| { |
| struct scsi_qla_host *ha; |
| int bus, target, lun; |
| srb_t *sp; |
| typedef enum { |
| ABORT_DEVICE = 1, |
| DEVICE_RESET = 2, |
| BUS_RESET = 3, |
| ADAPTER_RESET = 4, |
| RESET_DELAYED = 5, |
| FAIL = 6 |
| } action_t; |
| action_t action = ADAPTER_RESET; |
| u16 data; |
| scsi_lu_t *q; |
| int result; |
| |
| ENTER("qla1280_reset"); |
| if (qla1280_verbose) |
| printk(KERN_INFO "scsi(): Resetting Cmnd=0x%p, Handle=0x%p, " |
| "flags=0x%x\n", cmd, CMD_HANDLE(cmd), flags); |
| if (cmd == NULL) { |
| printk(KERN_WARNING |
| "(scsi?:?:?:?) Reset called with NULL Scsi_Cmnd " |
| "pointer, failing.\n"); |
| return SCSI_RESET_SNOOZE; |
| } |
| ha = (struct scsi_qla_host *)cmd->device->host->hostdata; |
| sp = (srb_t *)CMD_SP(cmd); |
| |
| #if STOP_ON_RESET |
| qla1280_panic("qla1280_reset", ha->host); |
| #endif |
| |
| /* Check for pending interrupts. */ |
| data = qla1280_debounce_register(&ha->iobase->istatus); |
| /* |
| * The io_request_lock is held when the reset handler is called, hence |
| * the interrupt handler cannot be running in parallel as it also |
| * grabs the lock. /Jes |
| */ |
| if (data & RISC_INT) |
| qla1280_isr(ha, &ha->done_q_first, &ha->done_q_last); |
| |
| /* |
| * Determine the suggested action that the mid-level driver wants |
| * us to perform. |
| */ |
| if (CMD_HANDLE(cmd) == NULL) { |
| /* |
| * if mid-level driver called reset with a orphan SCSI_Cmnd |
| * (i.e. a command that's not pending), so perform the |
| * function specified. |
| */ |
| if (flags & SCSI_RESET_SUGGEST_HOST_RESET) |
| action = ADAPTER_RESET; |
| else |
| action = BUS_RESET; |
| } else { |
| /* |
| * Mid-level driver has called reset with this SCSI_Cmnd and |
| * its pending. |
| */ |
| if (flags & SCSI_RESET_SUGGEST_HOST_RESET) |
| action = ADAPTER_RESET; |
| else if (flags & SCSI_RESET_SUGGEST_BUS_RESET) |
| action = BUS_RESET; |
| else |
| action = DEVICE_RESET; |
| } |
| |
| bus = SCSI_BUS_32(cmd); |
| target = SCSI_TCN_32(cmd); |
| lun = SCSI_LUN_32(cmd); |
| q = LU_Q(ha, bus, target, lun); |
| |
| #if AUTO_ESCALATE_RESET |
| if ((action & DEVICE_RESET) && (q->q_flag & QLA1280_QRESET)) { |
| printk(KERN_INFO |
| "qla1280(%ld): Bus device reset already sent to " |
| "device, escalating.\n", ha->host_no); |
| action = BUS_RESET; |
| } |
| if ((action & DEVICE_RESET) && (sp->flags & SRB_ABORT_PENDING)) { |
| printk(KERN_INFO |
| "qla1280(%ld):Have already attempted to reach " |
| "device with abort device\n", ha->host_no); |
| printk(KERN_INFO "qla1280(%ld):message, will escalate to BUS " |
| "RESET.\n", ha->host_no); |
| action = BUS_RESET; |
| } |
| #endif |
| |
| /* |
| * By this point, we want to already know what we are going to do, |
| * so we only need to perform the course of action. |
| */ |
| result = SCSI_RESET_ERROR; |
| switch (action) { |
| case FAIL: |
| break; |
| |
| case RESET_DELAYED: |
| result = SCSI_RESET_PENDING; |
| break; |
| |
| case ABORT_DEVICE: |
| ha->flags.in_reset = TRUE; |
| if (qla1280_verbose) |
| printk(KERN_INFO |
| "scsi(%ld:%d:%d:%d): Queueing abort device " |
| "command.\n", ha->host_no, bus, target, lun); |
| qla1280_abort_queue_single(ha, bus, target, lun, DID_ABORT); |
| if (qla1280_abort_device(ha, bus, target, lun) == 0) |
| result = SCSI_RESET_PENDING; |
| break; |
| |
| case DEVICE_RESET: |
| if (qla1280_verbose) |
| printk(KERN_INFO |
| "scsi(%ld:%d:%d:%d): Queueing device reset " |
| "command.\n", ha->host_no, bus, target, lun); |
| ha->flags.in_reset = TRUE; |
| for (lun = 0; lun < MAX_LUNS; lun++) |
| qla1280_abort_queue_single(ha, bus, target, lun, |
| DID_ABORT); |
| if (qla1280_device_reset(ha, bus, target) == 0) |
| result = SCSI_RESET_PENDING; |
| q->q_flag |= QLA1280_QRESET; |
| break; |
| |
| case BUS_RESET: |
| if (qla1280_verbose) |
| printk(KERN_INFO "qla1280(%ld:%d:%d:%d): Issuing BUS " |
| "DEVICE RESET.\n", ha->host_no, bus, target, |
| lun); |
| ha->flags.in_reset = TRUE; |
| for (target = 0; target < MAX_TARGETS; target++) |
| for (lun = 0; lun < MAX_LUNS; lun++) |
| qla1280_abort_queue_single(ha, bus, target, |
| lun, DID_RESET); |
| qla1280_bus_reset(ha, bus); |
| /* |
| * The bus reset routine returns all the outstanding commands |
| * back with "DID_RESET" in the status field after a short |
| * delay by the firmware. If the mid-level time out the SCSI |
| * reset before our delay we may need to ignore it. |
| */ |
| /* result = SCSI_RESET_PENDING | SCSI_RESET_BUS_RESET; */ |
| result = SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET; |
| /* |
| * Wheeeee!!! |
| */ |
| mdelay(4 * 1000); |
| barrier(); |
| if (flags & SCSI_RESET_SYNCHRONOUS) { |
| CMD_RESULT(cmd) = DID_BUS_BUSY << 16; |
| (*(cmd)->scsi_done)(cmd); |
| } |
| /* ha->reset_start = jiffies; */ |
| break; |
| |
| case ADAPTER_RESET: |
| default: |
| if (qla1280_verbose) { |
| printk(KERN_INFO |
| "scsi(%ld:%d:%d:%d): Issued an ADAPTER " |
| "RESET.\n", ha->host_no, bus, target, lun); |
| printk(KERN_INFO |
| "scsi(%ld:%d:%d:%d): I/O processing will " |
| "continue automatically.\n", ha->host_no, bus, |
| target, lun); |
| } |
| ha->flags.reset_active = TRUE; |
| /* |
| * We restarted all of the commands automatically, so the |
| * mid-level code can expect completions momentitarily. |
| */ |
| if (qla1280_abort_isp(ha) == 0) |
| result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET; |
| |
| ha->flags.reset_active = FALSE; |
| } |
| |
| if (ha->done_q_first) |
| qla1280_done(ha, &ha->done_q_first, &ha->done_q_last); |
| qla1280_restart_queues(ha); |
| ha->flags.in_reset = FALSE; |
| |
| dprintk(1, "RESET returning %d\n", result); |
| |
| LEAVE("qla1280_reset"); |
| return result; |
| } |
| |
| /************************************************************************** |
| * qla1280_biosparam |
| * Return the disk geometry for the given SCSI device. |
| **************************************************************************/ |
| int |
| qla1280_biosparam(struct scsi_device *sdev, struct block_device *bdev, |
| sector_t capacity, int geom[]) |
| { |
| int heads, sectors, cylinders; |
| |
| heads = 64; |
| sectors = 32; |
| cylinders = (unsigned long)capacity / (heads * sectors); |
| if (cylinders > 1024) { |
| heads = 255; |
| sectors = 63; |
| cylinders = (unsigned long)capacity / (heads * sectors); |
| /* if (cylinders > 1023) |
| cylinders = 1023; */ |
| } |
| |
| geom[0] = heads; |
| geom[1] = sectors; |
| geom[2] = cylinders; |
| |
| return 0; |
| } |
| |
| /************************************************************************** |
| * qla1280_intr_handler |
| * Handles the H/W interrupt |
| **************************************************************************/ |
| void |
| qla1280_intr_handler(int irq, void *dev_id, struct pt_regs *regs) |
| { |
| struct scsi_qla_host *ha; |
| struct device_reg *reg; |
| u16 data; |
| |
| ENTER_INTR ("qla1280_intr_handler"); |
| ha = (struct scsi_qla_host *)dev_id; |
| |
| spin_lock(ha->host->host_lock); |
| |
| ha->isr_count++; |
| reg = ha->iobase; |
| |
| WRT_REG_WORD(®->ictrl, 0); /* disable our interrupt. */ |
| |
| data = qla1280_debounce_register(®->istatus); |
| /* Check for pending interrupts. */ |
| if (data & RISC_INT) { |
| qla1280_isr(ha, &ha->done_q_first, &ha->done_q_last); |
| } else { |
| /* spurious interrupts can happen legally */ |
| dprintk(1, "scsi(%ld): Spurious interrupt - ignoring\n", |
| ha->host_no); |
| } |
| |
| if (ha->done_q_first) |
| qla1280_done(ha, &ha->done_q_first, &ha->done_q_last); |
| |
| spin_unlock(ha->host->host_lock); |
| |
| /* enable our interrupt. */ |
| WRT_REG_WORD(®->ictrl, (ISP_EN_INT | ISP_EN_RISC)); |
| |
| LEAVE_INTR("qla1280_intr_handler"); |
| } |
| |
| /************************************************************************** |
| * qla1280_do_dpc |
| * |
| * Description: |
| * This routine is a task that is schedule by the interrupt handler |
| * to perform the background processing for interrupts. We put it |
| * on a task queue that is consumed whenever the scheduler runs; that's |
| * so you can do anything (i.e. put the process to sleep etc). In fact, the |
| * mid-level tries to sleep when it reaches the driver threshold |
| * "host->can_queue". This can cause a panic if we were in our interrupt |
| * code . |
| **************************************************************************/ |
| void |
| qla1280_do_dpc(void *p) |
| { |
| struct scsi_qla_host *ha = (struct scsi_qla_host *) p; |
| unsigned long cpu_flags; |
| |
| spin_lock_irqsave(ha->host->host_lock, cpu_flags); |
| |
| if (ha->flags.isp_abort_needed) |
| qla1280_abort_isp(ha); |
| |
| if (ha->flags.reset_marker) |
| qla1280_rst_aen(ha); |
| |
| if (ha->done_q_first) |
| qla1280_done(ha, &ha->done_q_first, &ha->done_q_last); |
| |
| spin_unlock_irqrestore(ha->host->host_lock, cpu_flags); |
| } |
| |
| /************************************************************************** |
| * qla1280_slave_configure |
| * |
| * Description: |
| * Determines the queue depth for a given device. There are two ways |
| * a queue depth can be obtained for a tagged queueing device. One |
| * way is the default queue depth which is determined by whether |
| * If it is defined, then it is used |
| * as the default queue depth. Otherwise, we use either 4 or 8 as the |
| * default queue depth (dependent on the number of hardware SCBs). |
| **************************************************************************/ |
| static int |
| qla1280_slave_configure(Scsi_Device * device) |
| { |
| struct scsi_qla_host *p = (struct scsi_qla_host *)device->host->hostdata; |
| int bus = device->channel; |
| int target = device->id; |
| |
| if (qla1280_check_for_dead_scsi_bus(p, bus)) |
| return 1; |
| if (device->tagged_supported && |
| (p->bus_settings[bus].qtag_enables & (BIT_0 << target))) { |
| scsi_adjust_queue_depth(device, MSG_ORDERED_TAG, |
| p->bus_settings[bus].hiwat); |
| /* device->queue_depth = 20; */ |
| printk(KERN_INFO "scsi(%li:%d:%d:%d): Enabled tagged queuing, " |
| "queue depth %d.\n", p->host_no, device->channel, |
| device->id, device->lun, device->queue_depth); |
| } else { |
| scsi_adjust_queue_depth(device, 0 /* TCQ off */, 3); |
| } |
| qla12160_get_target_parameters(p, bus, target, device->lun); |
| return 0; |
| } |
| |
| /* |
| * Driver Support Routines |
| */ |
| |
| /* |
| * qla1280_done |
| * Process completed commands. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * done_q_first = done queue first pointer. |
| * done_q_last = done queue last pointer. |
| */ |
| static void |
| qla1280_done(struct scsi_qla_host *ha, srb_t ** done_q_first, |
| srb_t ** done_q_last) |
| { |
| srb_t *sp; |
| scsi_lu_t *q; |
| int bus, target, lun; |
| Scsi_Cmnd *cmd; |
| |
| ENTER("qla1280_done"); |
| |
| while (*done_q_first != NULL) { |
| /* remove command from done list */ |
| sp = *done_q_first; |
| if (!(*done_q_first = sp->s_next)) |
| *done_q_last = NULL; |
| else |
| (*done_q_first)->s_prev = NULL; |
| |
| cmd = sp->cmd; |
| bus = SCSI_BUS_32(cmd); |
| target = SCSI_TCN_32(cmd); |
| lun = SCSI_LUN_32(cmd); |
| q = LU_Q(ha, bus, target, lun); |
| |
| /* Decrement outstanding commands on device. */ |
| if (q->q_outcnt) |
| q->q_outcnt--; |
| if (q->q_outcnt < ha->bus_settings[bus].hiwat) { |
| q->q_flag &= ~QLA1280_QBUSY; |
| } |
| |
| q->io_cnt++; |
| if (sp->dir & BIT_5) |
| q->r_cnt++; |
| else |
| q->w_cnt++; |
| |
| switch ((CMD_RESULT(cmd) >> 16)) { |
| case DID_RESET: |
| q->q_flag &= ~QLA1280_QRESET; |
| /* Issue marker command. */ |
| qla1280_marker(ha, bus, target, 0, MK_SYNC_ID); |
| break; |
| case DID_ABORT: |
| sp->flags &= ~SRB_ABORT_PENDING; |
| sp->flags |= SRB_ABORTED; |
| if (sp->flags & SRB_TIMEOUT) |
| CMD_RESULT(sp->cmd) = DID_TIME_OUT << 16; |
| break; |
| default: |
| break; |
| } |
| |
| /* 3.13 64 and 32 bit */ |
| /* Release memory used for this I/O */ |
| if (cmd->use_sg) { |
| dprintk(1, "S/G unmap_sg cmd=%p\n", cmd); |
| |
| pci_unmap_sg(ha->pdev, cmd->request_buffer, |
| cmd->use_sg, |
| scsi_to_pci_dma_dir(cmd->sc_data_direction)); |
| } else if (cmd->request_bufflen) { |
| /*dprintk(1, "No S/G unmap_single cmd=%x saved_dma_handle=%lx\n", |
| cmd, sp->saved_dma_handle); */ |
| |
| pci_unmap_single(ha->pdev, sp->saved_dma_handle, |
| cmd->request_bufflen, |
| scsi_to_pci_dma_dir(cmd->sc_data_direction)); |
| } |
| |
| /* Call the mid-level driver interrupt handler */ |
| CMD_HANDLE(sp->cmd) = NULL; |
| ha->actthreads--; |
| |
| (*(cmd)->scsi_done)(cmd); |
| |
| qla1280_next(ha, q, bus); |
| } |
| LEAVE("qla1280_done"); |
| } |
| |
| /* |
| * Translates a ISP error to a Linux SCSI error |
| */ |
| static int |
| qla1280_return_status(sts_entry_t * sts, Scsi_Cmnd * cp) |
| { |
| int host_status = DID_ERROR; |
| #if DEBUG_QLA1280_INTR |
| static char *reason[] = { |
| "DID_OK", |
| "DID_NO_CONNECT", |
| "DID_BUS_BUSY", |
| "DID_TIME_OUT", |
| "DID_BAD_TARGET", |
| "DID_ABORT", |
| "DID_PARITY", |
| "DID_ERROR", |
| "DID_RESET", |
| "DID_BAD_INTR" |
| }; |
| #endif /* DEBUG_QLA1280_INTR */ |
| |
| ENTER("qla1280_return_status"); |
| |
| #if DEBUG_QLA1280_INTR |
| /* |
| dprintk(1, "qla1280_return_status: compl status = 0x%04x\n", |
| sts->comp_status); |
| */ |
| #endif |
| switch (sts->comp_status) { |
| case CS_COMPLETE: |
| host_status = DID_OK; |
| break; |
| |
| case CS_INCOMPLETE: |
| if (!(sts->state_flags & SF_GOT_BUS)) |
| host_status = DID_NO_CONNECT; |
| else if (!(sts->state_flags & SF_GOT_TARGET)) |
| host_status = DID_BAD_TARGET; |
| else if (!(sts->state_flags & SF_SENT_CDB)) |
| host_status = DID_ERROR; |
| else if (!(sts->state_flags & SF_TRANSFERRED_DATA)) |
| host_status = DID_ERROR; |
| else if (!(sts->state_flags & SF_GOT_STATUS)) |
| host_status = DID_ERROR; |
| else if (!(sts->state_flags & SF_GOT_SENSE)) |
| host_status = DID_ERROR; |
| break; |
| |
| case CS_RESET: |
| host_status = DID_RESET; |
| break; |
| |
| case CS_ABORTED: |
| host_status = DID_ABORT; |
| break; |
| |
| case CS_TIMEOUT: |
| host_status = DID_TIME_OUT; |
| break; |
| |
| case CS_DATA_OVERRUN: |
| dprintk(2, "Data overrun 0x%x\n", sts->residual_length); |
| dprintk(2, "qla1280_isr: response packet data\n"); |
| qla1280_dump_buffer(2, (char *)sts, RESPONSE_ENTRY_SIZE); |
| host_status = DID_ERROR; |
| break; |
| |
| case CS_DATA_UNDERRUN: |
| if ((cp->request_bufflen - sts->residual_length) < |
| cp->underflow) { |
| printk(KERN_WARNING |
| "scsi: Underflow detected - retrying " |
| "command.\n"); |
| host_status = DID_ERROR; |
| } else |
| host_status = DID_OK; |
| break; |
| |
| default: |
| host_status = DID_ERROR; |
| break; |
| } |
| |
| #if DEBUG_QLA1280_INTR |
| dprintk(1, "qla1280 ISP status: host status (%s) scsi status %x\n", |
| reason[host_status], sts->scsi_status); |
| #endif |
| |
| LEAVE("qla1280_return_status"); |
| |
| return (sts->scsi_status & 0xff) | (host_status << 16); |
| } |
| |
| /* |
| * qla1280_done_q_put |
| * Place SRB command on done queue. |
| * |
| * Input: |
| * sp = srb pointer. |
| * done_q_first = done queue first pointer. |
| * done_q_last = done queue last pointer. |
| */ |
| static void |
| qla1280_done_q_put(srb_t * sp, srb_t ** done_q_first, srb_t ** done_q_last) |
| { |
| ENTER("qla1280_put_done_q"); |
| |
| /* Place block on done queue */ |
| sp->s_next = NULL; |
| sp->s_prev = *done_q_last; |
| if (!*done_q_first) |
| *done_q_first = sp; |
| else |
| (*done_q_last)->s_next = sp; |
| *done_q_last = sp; |
| |
| LEAVE("qla1280_put_done_q"); |
| } |
| |
| /* |
| * qla1280_next |
| * Retrieve and process next job in the queue. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * q = SCSI LU pointer. |
| * bus = SCSI bus number. |
| * SCSI_LU_Qlock must be already obtained and no other locks. |
| * |
| * Output: |
| * Releases SCSI_LU_Qupon exit. |
| */ |
| static void |
| qla1280_next(struct scsi_qla_host *ha, scsi_lu_t * q, int bus) |
| { |
| srb_t *sp; |
| int cnt, status; |
| |
| ENTER("qla1280_next"); |
| |
| while (((sp = q->q_first) != NULL) && /* we have a queue pending */ |
| /* device not busy/suspended */ |
| !(q->q_flag & (QLA1280_QBUSY | QLA1280_QSUSP)) && !ha->flags.abort_isp_active) { /* not resetting the adapter */ |
| /* Remove srb from SCSI LU queue. */ |
| qla1280_removeq(q, sp); |
| |
| dprintk(1, "starting request 0x%p<-(0x%p)\n", q, sp); |
| { |
| /* Set busy flag if reached high water mark. */ |
| q->q_outcnt++; |
| if (q->q_outcnt >= ha->bus_settings[bus].hiwat) |
| q->q_flag |= QLA1280_QBUSY; |
| |
| #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18) |
| if (ha->flags.enable_64bit_addressing) |
| status = qla1280_64bit_start_scsi(ha, sp); |
| else |
| #endif |
| status = qla1280_32bit_start_scsi(ha, sp); |
| |
| if (status) { /* if couldn't start the request */ |
| if (q->q_outcnt == 1) { |
| /* Wait for 30 sec for command to be accepted. */ |
| for (cnt = 6000000; cnt; cnt--) { |
| #if QLA_64BIT_PTR |
| if (ha->flags.enable_64bit_addressing) |
| status = |
| qla1280_64bit_start_scsi(ha, sp); |
| else |
| #endif |
| status = |
| qla1280_32bit_start_scsi(ha, sp); |
| |
| if (!status) |
| break; |
| |
| /* Go check for pending interrupts. */ |
| qla1280_poll(ha); |
| |
| udelay(5); /* 10 */ |
| } |
| if (!cnt) { |
| /* Set timeout status */ |
| CMD_RESULT(sp->cmd) = |
| DID_TIME_OUT << 16; |
| |
| #if WATCHDOGTIMER |
| /* Remove command from watchdog queue. */ |
| if (sp->flags & SRB_WATCHDOG) |
| qla1280_timeout_remove |
| (ha, sp); |
| #endif |
| CMD_HANDLE(sp->cmd) = NULL; |
| |
| /* Call the mid-level driver interrupt handler */ |
| (*(sp->cmd)->scsi_done)(sp->cmd); |
| |
| if (q->q_outcnt) |
| q->q_outcnt--; |
| } |
| } else { /* Place request back on top of device queue. */ |
| qla1280_putq_t(q, sp); |
| |
| if (q->q_outcnt) |
| q->q_outcnt--; |
| if (q->q_outcnt < |
| ha->bus_settings[bus].hiwat) |
| q->q_flag &= ~QLA1280_QBUSY; |
| break; |
| } |
| } |
| } |
| } |
| |
| LEAVE("qla1280_next"); |
| } |
| |
| /* |
| * qla1280_putq_t |
| * Add the standard SCB job to the top of standard SCB commands. |
| * |
| * Input: |
| * q = SCSI LU pointer. |
| * sp = srb pointer. |
| * SCSI_LU_Qlock must be already obtained. |
| */ |
| static void |
| qla1280_putq_t(scsi_lu_t * q, srb_t * sp) |
| { |
| ENTER("qla1280_putq_t"); |
| |
| dprintk(1, "Adding to device q=0x%p<-(0x%p)sp\n", (void *) q, |
| (void *) sp); |
| |
| sp->s_next = NULL; |
| if (!q->q_first) { /* If queue empty */ |
| sp->s_prev = NULL; |
| q->q_first = sp; |
| q->q_last = sp; |
| } else { |
| sp->s_prev = q->q_last; |
| q->q_last->s_next = sp; |
| q->q_last = sp; |
| } |
| |
| LEAVE("qla1280_putq_t"); |
| } |
| |
| /* |
| * qla1280_removeq |
| * Function used to remove a command block from the |
| * LU queue. |
| * |
| * Input: |
| * q = SCSI LU pointer. |
| * sp = srb pointer. |
| * SCSI_LU_Qlock must be already obtained. |
| */ |
| static void |
| qla1280_removeq(scsi_lu_t * q, srb_t * sp) |
| { |
| dprintk(1, "Removing from device_q (0x%p)->(0x%p)\n", q, sp); |
| |
| if (sp->s_prev) { |
| if ((sp->s_prev->s_next = sp->s_next) != NULL) |
| sp->s_next->s_prev = sp->s_prev; |
| else |
| q->q_last = sp->s_prev; |
| } else if (!(q->q_first = sp->s_next)) |
| q->q_last = NULL; |
| else |
| q->q_first->s_prev = NULL; |
| } |
| |
| /* |
| * qla1280_mem_alloc |
| * Allocates adapter memory. |
| * |
| * Returns: |
| * 0 = success. |
| * 1 = failure. |
| */ |
| static int |
| qla1280_mem_alloc(struct scsi_qla_host *ha) |
| { |
| int status = 1; |
| dma_addr_t dma_handle; |
| |
| ENTER("qla1280_mem_alloc"); |
| |
| /* 3.13 */ |
| /* get consistent memory allocated for request and response rings */ |
| ha->request_ring = pci_alloc_consistent(ha->pdev, |
| ((REQUEST_ENTRY_CNT + 1) * |
| (sizeof(request_t))), |
| &dma_handle); |
| if (!ha->request_ring) |
| goto error; |
| ha->request_dma = dma_handle; |
| ha->response_ring = pci_alloc_consistent(ha->pdev, |
| ((RESPONSE_ENTRY_CNT + 1) * |
| (sizeof(response_t))), |
| &dma_handle); |
| if (!ha->request_ring) |
| goto error; |
| ha->response_dma = dma_handle; |
| status = 0; |
| |
| error: |
| if (status) |
| dprintk(2, "qla1280_mem_alloc: **** FAILED ****\n"); |
| |
| LEAVE("qla1280_mem_alloc"); |
| return status; |
| } |
| |
| /* |
| * qla1280_mem_free |
| * Frees adapter allocated memory. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| */ |
| static void |
| qla1280_mem_free(struct scsi_qla_host *ha) |
| { |
| scsi_lu_t *q; |
| int bus, target, lun; |
| |
| ENTER("qlc1280_mem_free"); |
| if (ha) { |
| /* Free device queues. */ |
| for (bus = 0; bus < MAX_BUSES; bus++) { |
| q = LU_Q(ha, bus, ha->bus_settings[bus].id, 0); |
| for (target = 0; target < MAX_TARGETS; target++) |
| for (lun = 0; lun < MAX_LUNS; lun++) |
| if (LU_Q(ha, bus, target, lun) != NULL |
| && LU_Q(ha, bus, target, lun) != q) |
| kfree(LU_Q(ha, bus, target, lun)); |
| kfree(q); |
| } |
| for (bus = 0; bus < MAX_EQ; bus++) |
| ha->dev[bus] = NULL; |
| } |
| |
| /* 3.13 */ |
| /* free consistent memory allocated for request and response rings */ |
| if (ha->request_ring) |
| pci_free_consistent(ha->pdev, |
| ((REQUEST_ENTRY_CNT + 1) * |
| (sizeof(request_t))), |
| ha->request_ring, ha->request_dma); |
| |
| if (ha->response_ring) |
| pci_free_consistent(ha->pdev, |
| ((RESPONSE_ENTRY_CNT + 1) * |
| (sizeof(response_t))), |
| ha->response_ring, ha->response_dma); |
| |
| if (qla1280_buffer) { |
| free_page((unsigned long) qla1280_buffer); |
| qla1280_buffer = NULL; |
| } |
| |
| LEAVE("qlc1280_mem_free"); |
| } |
| |
| /****************************************************************************/ |
| /* QLogic ISP1280 Hardware Support Functions. */ |
| /****************************************************************************/ |
| |
| /* |
| * qla2100_enable_intrs |
| * qla2100_disable_intrs |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * |
| * Returns: |
| * None |
| */ |
| static inline void |
| qla1280_enable_intrs(struct scsi_qla_host *ha) |
| { |
| struct device_reg *reg; |
| |
| reg = ha->iobase; |
| /* enable risc and host interrupts */ |
| WRT_REG_WORD(®->ictrl, (ISP_EN_INT | ISP_EN_RISC)); |
| ha->flags.ints_enabled = 1; |
| #if 0 |
| printk("Enabling ints\n"); |
| #endif |
| } |
| |
| static inline void |
| qla1280_disable_intrs(struct scsi_qla_host *ha) |
| { |
| struct device_reg *reg; |
| |
| reg = ha->iobase; |
| /* disable risc and host interrupts */ |
| WRT_REG_WORD(®->ictrl, 0); |
| ha->flags.ints_enabled = 0; |
| #if 0 |
| printk("Disabling ints\n"); |
| #endif |
| } |
| |
| /* |
| * qla1280_initialize_adapter |
| * Initialize board. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * |
| * Returns: |
| * 0 = success |
| */ |
| static int |
| qla1280_initialize_adapter(struct scsi_qla_host *ha) |
| { |
| struct device_reg *reg; |
| int status; |
| int bus; |
| |
| ENTER("qla1280_initialize_adapter"); |
| |
| /* Clear adapter flags. */ |
| ha->flags.online = FALSE; |
| ha->flags.isp_abort_needed = FALSE; |
| ha->flags.disable_host_adapter = FALSE; |
| ha->flags.reset_active = FALSE; |
| ha->flags.abort_isp_active = FALSE; |
| |
| ha->flags.ints_enabled = FALSE; |
| |
| dprintk(1, "Configure PCI space for adapter...\n"); |
| |
| reg = ha->iobase; |
| |
| /* Insure mailbox registers are free. */ |
| WRT_REG_WORD(®->semaphore, 0); |
| WRT_REG_WORD(®->host_cmd, HC_CLR_RISC_INT); |
| WRT_REG_WORD(®->host_cmd, HC_CLR_HOST_INT); |
| |
| /* If firmware needs to be loaded */ |
| if (qla1280_verbose) |
| printk(KERN_INFO "scsi(%li): Determining if RISC is " |
| "loaded...\n", ha->host_no); |
| if (qla1280_isp_firmware(ha)) { |
| if (qla1280_verbose) |
| printk(KERN_INFO "scsi(%ld): Verifying chip...\n", |
| ha->host_no); |
| if (!(status = qla1280_chip_diag (ha))) { |
| if (qla1280_verbose) |
| printk(KERN_INFO "scsi(%ld): Setup chip...\n", |
| ha->host_no); |
| status = qla1280_setup_chip(ha); |
| } |
| } else { |
| printk(KERN_ERR "initialize: isp_firmware() failed!\n"); |
| status = 1; |
| } |
| |
| if (!status) { |
| /* Setup adapter based on NVRAM parameters. */ |
| if (qla1280_verbose) |
| printk(KERN_INFO |
| "scsi(%ld): Configure NVRAM parameters...\n", |
| ha->host_no); |
| qla1280_nvram_config(ha); |
| |
| if (!ha->flags.disable_host_adapter |
| && !qla1280_init_rings(ha)) { |
| /* Issue SCSI reset. */ |
| /* dg 03/13 if we can't reset twice then bus is dead */ |
| for (bus = 0; bus < ha->ports; bus++) { |
| if (!ha->bus_settings[bus].disable_scsi_reset){ |
| if (qla1280_bus_reset(ha, bus)) { |
| if (qla1280_bus_reset(ha, bus)) { |
| ha->bus_settings[bus].scsi_bus_dead = TRUE; |
| } |
| } |
| } |
| } |
| do { |
| /* Issue marker command. */ |
| ha->flags.reset_marker = FALSE; |
| for (bus = 0; bus < ha->ports; bus++) { |
| ha->bus_settings[bus].reset_marker = FALSE; |
| qla1280_marker(ha, bus, 0, 0, |
| MK_SYNC_ALL); |
| } |
| } while (ha->flags.reset_marker); |
| |
| ha->flags.online = TRUE; |
| |
| /* Enable host adapter target mode. */ |
| for (bus = 0; bus < ha->ports; bus++) { |
| if (!(status = qla1280_enable_tgt(ha, bus))) { |
| #if 0 |
| int cnt; |
| for (cnt = 0; cnt < MAX_LUNS; cnt++) { |
| qla1280_enable_lun(ha, bus, |
| cnt); |
| qla1280_poll(ha); |
| } |
| #endif |
| } else |
| break; |
| } |
| } else |
| status = 1; |
| } else |
| printk(KERN_ERR "scsi(%li): initialize: pci probe failed!\n", |
| ha->host_no); |
| |
| if (status) |
| dprintk(2, "qla1280_initialize_adapter: **** FAILED ****\n"); |
| |
| LEAVE("qla1280_initialize_adapter"); |
| return status; |
| } |
| |
| /* |
| * qla1280_enable_tgt |
| * Enable target mode. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * bus = SCSI bus number. |
| * |
| * Returns: |
| * 0 = success. |
| */ |
| static int |
| qla1280_enable_tgt(struct scsi_qla_host *ha, int bus) |
| { |
| int status = 0; |
| /* uint16_t mb[MAILBOX_REGISTER_COUNT]; */ |
| |
| dprintk(3, "qla1280_enable_tgt: entered\n"); |
| |
| /* Enable target mode. */ |
| #if 0 |
| mb[0] = MBC_ENABLE_TARGET_MODE; |
| mb[1] = BIT_15; |
| mb[2] = (uint16_t) (bus << 15); |
| status = qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]); |
| #endif |
| if (status) |
| dprintk(2, "qla1280_enable_tgt: **** FAILED ****\n"); |
| else |
| dprintk(3, "qla1280_enable_tgt: exiting normally\n"); |
| |
| return status; |
| } |
| |
| /* |
| * ISP Firmware Test |
| * Checks if present version of RISC firmware is older than |
| * driver firmware. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * |
| * Returns: |
| * 0 = firmware does not need to be loaded. |
| */ |
| static int |
| qla1280_isp_firmware(struct scsi_qla_host *ha) |
| { |
| nvram_t *nv = (nvram_t *) ha->response_ring; |
| uint16_t *wptr; |
| int status = 0; /* dg 2/27 always loads RISC */ |
| int cnt; |
| uint8_t chksum; |
| uint16_t mb[MAILBOX_REGISTER_COUNT]; |
| |
| ENTER("qla1280_isp_firmware"); |
| |
| /* Verify valid NVRAM checksum. */ |
| wptr = (uint16_t *) ha->response_ring; |
| dprintk(1, "qla1280_isp_firmware: Reading NVRAM\n"); |
| |
| chksum = 0; |
| for (cnt = 0; cnt < sizeof(nvram_t) / 2; cnt++) { |
| *wptr = qla1280_get_nvram_word (ha, cnt); |
| chksum += (uint8_t) * wptr; |
| chksum += (uint8_t) (*wptr >> 8); |
| wptr++; |
| } |
| dprintk(1, "qla1280_isp_firmware: Completed Reading NVRAM\n"); |
| |
| dprintk(3, "qla1280_isp_firmware: NVRAM Magic ID= %c %c %c\n", |
| (char *)nv->id[0], nv->id[1], nv->id[2]); |
| |
| /* Bad NVRAM data, load RISC code. */ |
| if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || |
| nv->id[2] != 'P' || nv->id[3] != ' ' || nv->version < 1) { |
| printk(KERN_INFO "qla1280_isp_firmware: Bad checksum or magic " |
| "number or version in NVRAM.\n"); |
| ha->flags.disable_risc_code_load = FALSE; |
| } else |
| ha->flags.disable_risc_code_load = |
| nv->cntr_flags_1.disable_loading_risc_code; |
| |
| if (ha->flags.disable_risc_code_load) { |
| dprintk(3, |
| "qla1280_isp_firmware: Telling RISC to verify checksum " |
| "of loaded BIOS code.\n"); |
| |
| /* Verify checksum of loaded RISC code. */ |
| mb[0] = MBC_VERIFY_CHECKSUM; |
| /* mb[1] = ql12_risc_code_addr01; */ |
| mb[1] = *ql1280_board_tbl[ha->devnum].fwstart; |
| |
| if (! |
| (status = |
| qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]))) { |
| /* Start firmware execution. */ |
| dprintk(3, "qla1280_isp_firmware: Startng F/W " |
| "execution.\n"); |
| |
| mb[0] = MBC_EXECUTE_FIRMWARE; |
| /* mb[1] = ql12_risc_code_addr01; */ |
| mb[1] = *ql1280_board_tbl[ha->devnum].fwstart; |
| qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); |
| } else |
| printk(KERN_INFO "qla1280: RISC checksum failed.\n"); |
| } else { |
| dprintk(1, "qla1280: NVRAM configured to load RISC load.\n"); |
| status = 1; |
| } |
| |
| if (status) |
| dprintk(2, "qla1280_isp_firmware: **** Load RISC code ****\n"); |
| |
| LEAVE("qla1280_isp_firmware"); |
| return status; |
| } |
| |
| /* |
| * PCI configuration |
| * Setup device PCI configuration registers. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * |
| * Returns: |
| * 0 = success. |
| */ |
| static int |
| qla1280_pci_config(struct scsi_qla_host *ha) |
| { |
| #if MEMORY_MAPPED_IO |
| uint32_t page_offset, base; |
| uint32_t mmapbase; |
| #endif |
| uint16_t buf_wd; |
| int status = 1; |
| |
| ENTER("qla1280_pci_config"); |
| |
| pci_set_master(ha->pdev); |
| /* |
| * Set Bus Master Enable, Memory Address Space Enable and |
| * reset any error bits, in the command register. |
| */ |
| pci_read_config_word (ha->pdev, PCI_COMMAND, &buf_wd); |
| #if MEMORY_MAPPED_IO |
| dprintk(1, "qla1280: MEMORY MAPPED IO is enabled.\n"); |
| buf_wd |= PCI_COMMAND_MEMORY + PCI_COMMAND_IO; |
| #else |
| buf_wd |= PCI_COMMAND_IO; |
| #endif |
| pci_write_config_word (ha->pdev, PCI_COMMAND, buf_wd); |
| /* |
| * Reset expansion ROM address decode enable. |
| */ |
| pci_read_config_word (ha->pdev, PCI_ROM_ADDRESS, &buf_wd); |
| buf_wd &= ~PCI_ROM_ADDRESS_ENABLE; |
| pci_write_config_word (ha->pdev, PCI_ROM_ADDRESS, buf_wd); |
| |
| ha->host->io_port = pci_resource_start(ha->pdev, 0); |
| ha->host->io_port &= PCI_BASE_ADDRESS_IO_MASK; |
| ha->iobase = (struct device_reg *) ha->host->io_port; |
| |
| #if MEMORY_MAPPED_IO |
| /* |
| * Get memory mapped I/O address. |
| */ |
| pci_read_config_word (ha->pdev, PCI_BASE_ADDRESS_1, &mmapbase); |
| mmapbase &= PCI_BASE_ADDRESS_MEM_MASK; |
| |
| /* |
| * Find proper memory chunk for memory map I/O reg. |
| */ |
| base = mmapbase & PAGE_MASK; |
| page_offset = mmapbase - base; |
| /* |
| * Get virtual address for I/O registers. |
| */ |
| ha->mmpbase = ioremap(base, page_offset + 256); |
| if (ha->mmpbase) { |
| ha->mmpbase += page_offset; |
| /* ha->iobase = ha->mmpbase; */ |
| status = 0; |
| } |
| #else /* MEMORY_MAPPED_IO */ |
| status = 0; |
| #endif /* MEMORY_MAPPED_IO */ |
| |
| LEAVE("qla1280_pci_config"); |
| return status; |
| } |
| |
| /* |
| * Chip diagnostics |
| * Test chip for proper operation. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * |
| * Returns: |
| * 0 = success. |
| */ |
| static int |
| qla1280_chip_diag(struct scsi_qla_host *ha) |
| { |
| uint16_t mb[MAILBOX_REGISTER_COUNT]; |
| struct device_reg *reg = ha->iobase; |
| int status = 0; |
| int cnt; |
| uint16_t data; |
| |
| dprintk(3, "qla1280_chip_diag: testing device at 0x%p \n", ®->id_l); |
| |
| /* Soft reset chip and wait for it to finish. */ |
| WRT_REG_WORD(®->ictrl, ISP_RESET); |
| data = qla1280_debounce_register(®->ictrl); |
| /* |
| * This is *AWESOME* |
| */ |
| for (cnt = 6000000; cnt && data & ISP_RESET; cnt--) { |
| udelay(5); |
| data = RD_REG_WORD(®->ictrl); |
| } |
| if (cnt) { |
| /* Reset register not cleared by chip reset. */ |
| dprintk(3, |
| "qla1280_chip_diag: reset register cleared by chip reset\n"); |
| |
| WRT_REG_WORD(®->cfg_1, 0); |
| |
| /* Reset RISC and disable BIOS which |
| allows RISC to execute out of RAM. */ |
| WRT_REG_WORD(®->host_cmd, HC_RESET_RISC); |
| WRT_REG_WORD(®->host_cmd, HC_RELEASE_RISC); |
| WRT_REG_WORD(®->host_cmd, HC_DISABLE_BIOS); |
| data = qla1280_debounce_register(®->mailbox0); |
| /* |
| * I *LOVE* this code! |
| */ |
| for (cnt = 6000000; cnt && data == MBS_BUSY; cnt--) { |
| udelay(5); |
| data = RD_REG_WORD(®->mailbox0); |
| } |
| |
| if (cnt) { |
| /* Check product ID of chip */ |
| dprintk(3, |
| "qla1280_chip_diag: Checking product ID of chip\n"); |
| |
| if (RD_REG_WORD(®->mailbox1) != PROD_ID_1 || |
| (RD_REG_WORD(®->mailbox2) != PROD_ID_2 && |
| RD_REG_WORD(®->mailbox2) != PROD_ID_2a) || |
| RD_REG_WORD(®->mailbox3) != PROD_ID_3 || |
| RD_REG_WORD(®->mailbox4) != PROD_ID_4) { |
| printk(KERN_INFO |
| "qla1280: Wrong product ID = 0x%x,0x%x,0x%x," |
| "0x%x\n", RD_REG_WORD(®->mailbox1), |
| RD_REG_WORD(®->mailbox2), |
| RD_REG_WORD(®->mailbox3), |
| RD_REG_WORD(®->mailbox4)); |
| status = 1; |
| } else { |
| /* |
| * Enable ints early!!! |
| */ |
| qla1280_enable_intrs(ha); |
| dprintk(1, |
| "qla1280_chip_diag: Checking mailboxes of chip\n"); |
| /* Wrap Incoming Mailboxes Test. */ |
| mb[0] = MBC_MAILBOX_REGISTER_TEST; |
| mb[1] = 0xAAAA; |
| mb[2] = 0x5555; |
| mb[3] = 0xAA55; |
| mb[4] = 0x55AA; |
| mb[5] = 0xA5A5; |
| mb[6] = 0x5A5A; |
| mb[7] = 0x2525; |
| if (!(status = qla1280_mailbox_command(ha, |
| BIT_7 | |
| BIT_6 | |
| BIT_5 | |
| BIT_4 | |
| BIT_3 | |
| BIT_2 | |
| BIT_1 | |
| BIT_0, |
| &mb |
| [0]))) { |
| if (mb[1] != 0xAAAA || |
| mb[2] != 0x5555 || |
| mb[3] != 0xAA55 || |
| mb[4] != 0x55AA || |
| mb[5] != 0xA5A5 || |
| mb[6] != 0x5A5A || |
| mb[7] != 0x2525) |
| status = 1; |
| if (status == 1) |
| printk(KERN_INFO |
| "qla1280: Failed mailbox check\n"); |
| } |
| } |
| } else |
| status = 1; |
| } else |
| status = 1; |
| |
| if (status) |
| dprintk(2, "qla1280_chip_diag: **** FAILED ****\n"); |
| else |
| dprintk(3, "qla1280_chip_diag: exiting normally\n"); |
| |
| return status; |
| } |
| |
| /* |
| * Setup chip |
| * Load and start RISC firmware. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * |
| * Returns: |
| * 0 = success. |
| */ |
| #define DUMP_IT_BACK 0 /* for debug of RISC loading */ |
| static int |
| qla1280_setup_chip(struct scsi_qla_host *ha) |
| { |
| int status = 0; |
| uint16_t risc_address; |
| uint16_t *risc_code_address; |
| int risc_code_size; |
| uint16_t mb[MAILBOX_REGISTER_COUNT]; |
| uint16_t cnt; |
| int num; |
| #if DUMP_IT_BACK |
| int i; |
| uint8_t *sp; |
| uint8_t *tbuf; |
| #ifdef QLA_64BIT_PTR |
| dma_addr_t p_tbuf; |
| #else |
| uint32_t p_tbuf; |
| #endif |
| #endif |
| |
| ENTER("qla1280_setup_chip"); |
| |
| /* 3.13 */ |
| #if DUMP_IT_BACK |
| /* get consistent memory allocated for setup_chip */ |
| tbuf = pci_alloc_consistent(ha->pdev, 8000, &p_tbuf); |
| #endif |
| |
| /* Load RISC code. */ |
| risc_address = *ql1280_board_tbl[ha->devnum].fwstart; |
| risc_code_address = ql1280_board_tbl[ha->devnum].fwcode; |
| risc_code_size = (int) *ql1280_board_tbl[ha->devnum].fwlen; |
| |
| dprintk(1, "qla1280_setup_chip: DMA RISC code (%i) words\n", |
| risc_code_size); |
| |
| num = 0; |
| while (risc_code_size > 0 && !status) { |
| cnt = 2000 >> 1; |
| |
| if (cnt > risc_code_size) |
| cnt = risc_code_size; |
| |
| dprintk(1, "qla1280_setup_chip: loading risc @ =(0x%p)," |
| "%d,%d(0x%x)\n", |
| risc_code_address, cnt, num, risc_address); |
| memcpy(ha->request_ring, risc_code_address, (cnt << 1)); |
| |
| flush_cache_all(); |
| |
| mb[0] = MBC_LOAD_RAM; |
| mb[1] = risc_address; |
| mb[4] = cnt; |
| mb[3] = ha->request_dma & 0xffff; |
| mb[2] = (ha->request_dma >> 16) & 0xffff; |
| mb[7] = pci_dma_hi32(ha->request_dma) & 0xffff; |
| mb[6] = pci_dma_hi32(ha->request_dma) >> 16; |
| dprintk(1, "qla1280_setup_chip: op=%d 0x%p = 0x%4x,0x%4x," |
| "0x%4x,0x%4x\n", |
| mb[0], ha->request_dma, mb[6], mb[7], mb[2], mb[3]); |
| if ((status = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | |
| BIT_2 | BIT_1 | BIT_0, |
| &mb[0]))) { |
| printk(KERN_ERR |
| "Failed to load partial segment of f/w\n"); |
| break; |
| } |
| #if DUMP_IT_BACK |
| mb[0] = MBC_READ_RAM_WORD; |
| mb[1] = risc_address; |
| mb[4] = cnt; |
| mb[3] = p_tbuf & 0xffff; |
| mb[2] = (p_tbuf >> 16) & 0xffff; |
| mb[7] = pci_dma_hi32(p_tbuf) & 0xffff; |
| mb[6] = pci_dma_hi32(p_tbuf) >> 16; |
| |
| if ((status = qla1280_mailbox_command(ha, |
| BIT_4 | BIT_3 | BIT_2 | |
| BIT_1 | BIT_0, |
| &mb[0]))) { |
| printk(KERN_ERR |
| "Failed to dump partial segment of f/w\n"); |
| break; |
| } |
| sp = (uint8_t *)ha->request_ring; |
| for (i = 0; i < (cnt << 1); i++) { |
| if (tbuf[i] != sp[i]) { |
| printk(KERN_ERR "qla1280_setup_chip: FW " |
| "compare error @ byte(0x%x) loop#=%x\n", |
| i, num); |
| printk(KERN_ERR "setup_chip: FWbyte=%x " |
| "FWfromChip=%x\n", sp[i], tbuf[i]); |
| /*break; */ |
| } |
| } |
| #endif |
| risc_address += cnt; |
| risc_code_size = risc_code_size - cnt; |
| risc_code_address = risc_code_address + cnt; |
| num++; |
| } |
| |
| /* Verify checksum of loaded RISC code. */ |
| if (!status) { |
| dprintk(1, "qla1280_setup_chip: Verifying checksum of " |
| "loaded RISC code.\n"); |
| mb[0] = MBC_VERIFY_CHECKSUM; |
| /* mb[1] = ql12_risc_code_addr01; */ |
| mb[1] = *ql1280_board_tbl[ha->devnum].fwstart; |
| |
| if (!(status = |
| qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]))) { |
| /* Start firmware execution. */ |
| dprintk(1, |
| "qla1280_setup_chip: start firmware running.\n"); |
| mb[0] = MBC_EXECUTE_FIRMWARE; |
| mb[1] = *ql1280_board_tbl[ha->devnum].fwstart; |
| qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); |
| } else |
| printk(KERN_ERR |
| "qla1280_setup_chip: Failed checksum.\n"); |
| } |
| |
| /* 3.13 */ |
| #if DUMP_IT_BACK |
| /* free consistent memory allocated for setup_chip */ |
| pci_free_consistent(ha->pdev, 8000, tbuf, p_tbuf); |
| #endif |
| |
| if (status) |
| dprintk(2, "qla1280_setup_chip: **** FAILED ****\n"); |
| |
| LEAVE("qla1280_setup_chip"); |
| return status; |
| } |
| |
| /* |
| * Initialize rings |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * ha->request_ring = request ring virtual address |
| * ha->response_ring = response ring virtual address |
| * ha->request_dma = request ring physical address |
| * ha->response_dma = response ring physical address |
| * |
| * Returns: |
| * 0 = success. |
| */ |
| static int |
| qla1280_init_rings(struct scsi_qla_host *ha) |
| { |
| uint16_t mb[MAILBOX_REGISTER_COUNT]; |
| int status = 0; |
| int cnt; |
| |
| ENTER("qla1280_init_rings"); |
| |
| /* Clear outstanding commands array. */ |
| for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) |
| ha->outstanding_cmds[cnt] = 0; |
| |
| /* Initialize request queue. */ |
| ha->request_ring_ptr = ha->request_ring; |
| ha->req_ring_index = 0; |
| ha->req_q_cnt = REQUEST_ENTRY_CNT; |
| /* mb[0] = MBC_INIT_REQUEST_QUEUE; */ |
| mb[0] = MBC_INIT_REQUEST_QUEUE_A64; |
| mb[1] = REQUEST_ENTRY_CNT; |
| mb[3] = ha->request_dma & 0xffff; |
| mb[2] = (ha->request_dma >> 16) & 0xffff; |
| mb[4] = 0; |
| mb[7] = pci_dma_hi32(ha->request_dma) & 0xffff; |
| mb[6] = pci_dma_hi32(ha->request_dma) >> 16; |
| if (!(status = qla1280_mailbox_command(ha, BIT_7 | BIT_6 | BIT_4 | |
| BIT_3 | BIT_2 | BIT_1 | BIT_0, |
| &mb[0]))) { |
| /* Initialize response queue. */ |
| ha->response_ring_ptr = ha->response_ring; |
| ha->rsp_ring_index = 0; |
| /* mb[0] = MBC_INIT_RESPONSE_QUEUE; */ |
| mb[0] = MBC_INIT_RESPONSE_QUEUE_A64; |
| mb[1] = RESPONSE_ENTRY_CNT; |
| mb[3] = ha->response_dma & 0xffff; |
| mb[2] = (ha->response_dma >> 16) & 0xffff; |
| mb[5] = 0; |
| mb[7] = pci_dma_hi32(ha->response_dma) & 0xffff; |
| mb[6] = pci_dma_hi32(ha->response_dma) >> 16; |
| status = qla1280_mailbox_command(ha, BIT_7 | BIT_6 | BIT_5 | |
| BIT_3 | BIT_2 | BIT_1 | BIT_0, |
| &mb[0]); |
| } |
| |
| if (status) |
| dprintk(2, "qla1280_init_rings: **** FAILED ****\n"); |
| |
| LEAVE("qla1280_init_rings"); |
| return status; |
| } |
| |
| /* |
| * NVRAM configuration. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * ha->request_ring = request ring virtual address |
| * |
| * Output: |
| * host adapters parameters in host adapter block |
| * |
| * Returns: |
| * 0 = success. |
| */ |
| static int |
| qla1280_nvram_config(struct scsi_qla_host *ha) |
| { |
| struct device_reg *reg = ha->iobase; |
| nvram_t *nv = (nvram_t *)ha->response_ring; |
| int status = 0; |
| int cnt; |
| int bus, target, lun; |
| uint16_t *wptr; |
| uint16_t mb[MAILBOX_REGISTER_COUNT]; |
| uint8_t chksum; |
| int nvsize; |
| |
| #if DEBUG_PRINT_NVRAM |
| int saved_print_status = ql_debug_print; |
| #endif |
| ENTER("qla1280_nvram_config"); |
| |
| /* Verify valid NVRAM checksum. */ |
| #if USE_NVRAM_DEFAULTS |
| chksum = 1; |
| #else |
| wptr = (uint16_t *) ha->response_ring; |
| chksum = 0; |
| if (ha->device_id == PCI_DEVICE_ID_QLOGIC_ISP12160 || |
| ha->device_id == PCI_DEVICE_ID_QLOGIC_ISP10160) |
| nvsize = sizeof(nvram160_t) / 2; |
| else |
| nvsize = sizeof(nvram_t) / 2; |
| for (cnt = 0; cnt < nvsize; cnt++) { |
| *wptr = qla1280_get_nvram_word(ha, cnt); |
| chksum += (uint8_t) * wptr; |
| chksum += (uint8_t) (*wptr >> 8); |
| wptr++; |
| } |
| #endif |
| |
| /* Bad NVRAM data, set defaults parameters. */ |
| if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || |
| nv->id[2] != 'P' || nv->id[3] != ' ' || nv->version < 1) { |
| #if USE_NVRAM_DEFAULTS |
| dprintk(1, "Using defaults for NVRAM\n"); |
| #else |
| dprintk(1, "Using defaults for NVRAM: \n"); |
| dprintk(1, "checksum=0x%x, Id=%c, version=0x%x\n", |
| chksum, nv->id[0], nv->version); |
| memset(ha->response_ring, 0, sizeof(nvram_t)); |
| #endif |
| |
| /* nv->cntr_flags_1.disable_loading_risc_code = 1; */ |
| nv->firmware_feature.w = BIT_0; |
| nv->termination.f.scsi_bus_0_control = 3; |
| nv->termination.f.scsi_bus_1_control = 3; |
| nv->termination.f.auto_term_support = 1; |
| |
| for (bus = 0; bus < MAX_BUSES; bus++) { |
| nv->bus[bus].config_1.initiator_id = 7; |
| nv->bus[bus].bus_reset_delay = 5; |
| nv->bus[bus].config_2.async_data_setup_time = 9; |
| nv->bus[bus].config_2.req_ack_active_negation = 1; |
| nv->bus[bus].config_2.data_line_active_negation = 1; |
| nv->bus[bus].selection_timeout = 250; |
| nv->bus[bus].max_queue_depth = 256; |
| |
| for (target = 0; target < MAX_TARGETS; target++) { |
| nv->bus[bus].target[target].parameter.f. |
| auto_request_sense = 1; |
| nv->bus[bus].target[target].parameter.f. |
| disconnect_allowed = 1; |
| nv->bus[bus].target[target].parameter.f. |
| tag_queuing = 1; |
| nv->bus[bus].target[target].flags. |
| device_enable = 1; |
| } |
| } |
| |
| #if USE_NVRAM_DEFAULTS |
| status = 0; |
| #else |
| status = 1; |
| #endif |
| } else { |
| /* Always force AUTO sense for LINUX SCSI */ |
| for (bus = 0; bus < MAX_BUSES; bus++) |
| for (target = 0; target < MAX_TARGETS; target++) { |
| nv->bus[bus].target[target].parameter.f. |
| auto_request_sense = 1; |
| } |
| } |
| #if DEBUG_PRINT_NVRAM |
| ql_debug_print = 1; |
| #endif |
| dprintk(1, "qla1280 : initiator scsi id bus[0]=%d\n", |
| nv->bus[0].config_1.initiator_id); |
| dprintk(1, "qla1280 : initiator scsi id bus[1]=%d\n", |
| nv->bus[1].config_1.initiator_id); |
| |
| dprintk(1, "qla1280 : bus reset delay[0]=%d\n", |
| nv->bus[0].bus_reset_delay); |
| dprintk(1, "qla1280 : bus reset delay[1]=%d\n", |
| nv->bus[1].bus_reset_delay); |
| |
| dprintk(1, "qla1280 : retry count[0]=%d\n", nv->bus[0].retry_count); |
| dprintk(1, "qla1280 : retry delay[0]=%d\n", nv->bus[0].retry_delay); |
| dprintk(1, "qla1280 : retry count[1]=%d\n", nv->bus[1].retry_count); |
| dprintk(1, "qla1280 : retry delay[1]=%d\n", nv->bus[1].retry_delay); |
| |
| dprintk(1, "qla1280 : async data setup time[0]=%d\n", |
| nv->bus[0].config_2.async_data_setup_time); |
| dprintk(1, "qla1280 : async data setup time[1]=%d\n", |
| nv->bus[1].config_2.async_data_setup_time); |
| |
| dprintk(1, "qla1280 : req/ack active negation[0]=%d\n", |
| nv->bus[0].config_2.req_ack_active_negation); |
| dprintk(1, "qla1280 : req/ack active negation[1]=%d\n", |
| nv->bus[1].config_2.req_ack_active_negation); |
| |
| dprintk(1, "qla1280 : data line active negation[0]=%d\n", |
| nv->bus[0].config_2.data_line_active_negation); |
| dprintk(1, "qla1280 : data line active negation[1]=%d\n", |
| nv->bus[1].config_2.data_line_active_negation); |
| |
| dprintk(1, "qla1280 : disable loading risc code=%d\n", |
| nv->cntr_flags_1.disable_loading_risc_code); |
| |
| dprintk(1, "qla1280 : enable 64bit addressing=%d\n", |
| nv->cntr_flags_1.enable_64bit_addressing); |
| |
| dprintk(1, "qla1280 : selection timeout limit[0]=%d\n", |
| nv->bus[0].selection_timeout); |
| dprintk(1, "qla1280 : selection timeout limit[1]=%d\n", |
| nv->bus[1].selection_timeout); |
| |
| dprintk(1, "qla1280 : max queue depth[0]=%d\n", |
| nv->bus[0].max_queue_depth); |
| dprintk(1, "qla1280 : max queue depth[1]=%d\n", |
| nv->bus[1].max_queue_depth); |
| |
| /* Disable RISC load of firmware. */ |
| ha->flags.disable_risc_code_load = |
| nv->cntr_flags_1.disable_loading_risc_code; |
| |
| #ifdef QLA_64BIT_PTR |
| /* Enable 64bit addressing for OS/System combination supporting it */ |
| /* actual NVRAM bit is: nv->cntr_flags_1.enable_64bit_addressing */ |
| /* but we will ignore it and use BITS_PER_LONG macro to setup for */ |
| /* 64 or 32 bit access of host memory in all x86/ia-64/Alpha systems */ |
| ha->flags.enable_64bit_addressing = 1; |
| #else |
| ha->flags.enable_64bit_addressing = 0; |
| #endif |
| |
| #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18) |
| if (ha->flags.enable_64bit_addressing) { |
| printk(KERN_INFO "scsi(%li): 64 Bit PCI Addressing Enabled\n", |
| ha->host_no); |
| |
| pci_set_dma_mask(ha->pdev, (dma_addr_t) ~ 0ULL); |
| } |
| #endif |
| |
| /* Set ISP hardware DMA burst */ |
| mb[0] = nv->isp_config.c; |
| WRT_REG_WORD(®->cfg_1, mb[0]); |
| |
| /* Set SCSI termination. */ |
| WRT_REG_WORD(®->gpio_enable, (BIT_3 + BIT_2 + BIT_1 + BIT_0)); |
| mb[0] = nv->termination.c & (BIT_3 + BIT_2 + BIT_1 + BIT_0); |
| WRT_REG_WORD(®->gpio_data, mb[0]); |
| |
| /* ISP parameter word. */ |
| mb[0] = MBC_SET_SYSTEM_PARAMETER; |
| mb[1] = nv->isp_parameter; |
| status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); |
| |
| /* Firmware feature word. */ |
| mb[0] = MBC_SET_FIRMWARE_FEATURES; |
| mb[1] = nv->firmware_feature.w & (BIT_1 | BIT_0); |
| status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); |
| |
| /* Retry count and delay. */ |
| mb[0] = MBC_SET_RETRY_COUNT; |
| mb[1] = nv->bus[0].retry_count; |
| mb[2] = nv->bus[0].retry_delay; |
| mb[6] = nv->bus[1].retry_count; |
| mb[7] = nv->bus[1].retry_delay; |
| status |= |
| qla1280_mailbox_command(ha, BIT_7 | BIT_6 | BIT_2 | BIT_1 | BIT_0, |
| &mb[0]); |
| |
| /* ASYNC data setup time. */ |
| mb[0] = MBC_SET_ASYNC_DATA_SETUP; |
| mb[1] = nv->bus[0].config_2.async_data_setup_time; |
| mb[2] = nv->bus[1].config_2.async_data_setup_time; |
| status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]); |
| |
| /* Active negation states. */ |
| mb[0] = MBC_SET_ACTIVE_NEGATION; |
| mb[1] = 0; |
| if (nv->bus[0].config_2.req_ack_active_negation) |
| mb[1] |= BIT_5; |
| if (nv->bus[0].config_2.data_line_active_negation) |
| mb[1] |= BIT_4; |
| mb[2] = 0; |
| if (nv->bus[1].config_2.req_ack_active_negation) |
| mb[2] |= BIT_5; |
| if (nv->bus[1].config_2.data_line_active_negation) |
| mb[2] |= BIT_4; |
| status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]); |
| |
| /* Selection timeout. */ |
| mb[0] = MBC_SET_SELECTION_TIMEOUT; |
| mb[1] = nv->bus[0].selection_timeout; |
| mb[2] = nv->bus[1].selection_timeout; |
| status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]); |
| |
| for (bus = 0; bus < ha->ports; bus++) { |
| /* SCSI Reset Disable. */ |
| ha->bus_settings[bus].disable_scsi_reset = |
| nv->bus[bus].config_1.scsi_reset_disable; |
| |
| /* Initiator ID. */ |
| ha->bus_settings[bus].id = nv->bus[bus].config_1.initiator_id; |
| mb[0] = MBC_SET_INITIATOR_ID; |
| mb[1] = bus ? ha->bus_settings[bus].id | BIT_7 : |
| ha->bus_settings[bus].id; |
| status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); |
| |
| /* Reset Delay. */ |
| ha->bus_settings[bus].bus_reset_delay = |
| nv->bus[bus].bus_reset_delay; |
| |
| /* Command queue depth per device. */ |
| ha->bus_settings[bus].hiwat = nv->bus[bus].max_queue_depth - 1; |
| |
| /* Set target parameters. */ |
| for (target = 0; target < MAX_TARGETS; target++) { |
| uint8_t mr = BIT_3 | BIT_2 | BIT_1 | BIT_0; |
| |
| /* Set Target Parameters. */ |
| mb[0] = MBC_SET_TARGET_PARAMETERS; |
| mb[1] = (uint16_t) (bus ? target | BIT_7 : target); |
| mb[1] <<= 8; |
| |
| mb[2] = nv->bus[bus].target[target].parameter.c << 8; |
| mb[2] |= TP_AUTO_REQUEST_SENSE; |
| mb[2] &= ~TP_STOP_QUEUE; |
| |
| mb[3] = |
| nv->bus[bus].target[target].flags.sync_offset << 8; |
| mb[3] |= nv->bus[bus].target[target].sync_period; |
| |
| if (ha->device_id == PCI_DEVICE_ID_QLOGIC_ISP12160 || |
| ha->device_id == PCI_DEVICE_ID_QLOGIC_ISP10160) { |
| nvram160_t *nv2 = (nvram160_t *) nv; |
| mb[2] |= |
| nv2->bus[bus].target[target].flags. |
| enable_ppr << 5; |
| |
| mb[6] = |
| nv2->bus[bus].target[target].flags. |
| ppr_options << 8; |
| mb[6] |= |
| nv2->bus[bus].target[target].flags. |
| ppr_bus_width; |
| mr |= BIT_6; |
| } |
| status = qla1280_mailbox_command(ha, mr, &mb[0]); |
| |
| /* Save Tag queuing enable flag. */ |
| mb[0] = BIT_0 << target; |
| if (nv->bus[bus].target[target].parameter.f.tag_queuing) |
| ha->bus_settings[bus].qtag_enables |= mb[0]; |
| |
| /* Save Device enable flag. */ |
| if (nv->bus[bus].target[target].flags.device_enable) |
| ha->bus_settings[bus].device_enables |= mb[0]; |
| |
| /* Save LUN disable flag. */ |
| if (nv->bus[bus].target[target].flags.lun_disable) |
| ha->bus_settings[bus].lun_disables |= mb[0]; |
| |
| /* Set Device Queue Parameters. */ |
| for (lun = 0; lun < MAX_LUNS; lun++) { |
| mb[0] = MBC_SET_DEVICE_QUEUE; |
| mb[1] = (uint16_t)(bus ? target | BIT_7 : target); |
| mb[1] = mb[1] << 8 | lun; |
| mb[2] = nv->bus[bus].max_queue_depth; |
| mb[3] = nv->bus[bus].target[target].execution_throttle; |
| status |= |
| qla1280_mailbox_command(ha, |
| BIT_3 | BIT_2 | |
| BIT_1 | BIT_0, |
| &mb[0]); |
| } |
| } |
| } |
| |
| #if DEBUG_PRINT_NVRAM |
| ql_debug_print = saved_print_status; |
| #endif |
| |
| if (status) |
| dprintk(2, "qla1280_nvram_config: **** FAILED ****\n"); |
| |
| LEAVE("qla1280_nvram_config"); |
| return status; |
| } |
| |
| /* |
| * Get NVRAM data word |
| * Calculates word position in NVRAM and calls request routine to |
| * get the word from NVRAM. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * address = NVRAM word address. |
| * |
| * Returns: |
| * data word. |
| */ |
| static uint16_t |
| qla1280_get_nvram_word(struct scsi_qla_host *ha, uint32_t address) |
| { |
| uint32_t nv_cmd; |
| uint16_t data; |
| |
| #ifdef QL_DEBUG_ROUTINES |
| int saved_print_status = ql_debug_print; |
| #endif |
| |
| nv_cmd = address << 16; |
| nv_cmd |= NV_READ_OP; |
| |
| #ifdef QL_DEBUG_ROUTINES |
| ql_debug_print = FALSE; |
| #endif |
| data = qla1280_nvram_request(ha, nv_cmd); |
| #ifdef QL_DEBUG_ROUTINES |
| ql_debug_print = saved_print_status; |
| #endif |
| |
| dprintk(4, |
| "qla1280_get_nvram_word: exiting normally NVRAM data = 0x%x", |
| data); |
| |
| return data; |
| } |
| |
| /* |
| * NVRAM request |
| * Sends read command to NVRAM and gets data from NVRAM. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * nv_cmd = Bit 26 = start bit |
| * Bit 25, 24 = opcode |
| * Bit 23-16 = address |
| * Bit 15-0 = write data |
| * |
| * Returns: |
| * data word. |
| */ |
| static uint16_t |
| qla1280_nvram_request(struct scsi_qla_host *ha, uint32_t nv_cmd) |
| { |
| struct device_reg *reg = ha->iobase; |
| int cnt; |
| uint16_t data = 0; |
| uint16_t reg_data; |
| |
| /* Send command to NVRAM. */ |
| |
| nv_cmd <<= 5; |
| for (cnt = 0; cnt < 11; cnt++) { |
| if (nv_cmd & BIT_31) |
| qla1280_nv_write(ha, NV_DATA_OUT); |
| else |
| qla1280_nv_write(ha, 0); |
| nv_cmd <<= 1; |
| } |
| |
| /* Read data from NVRAM. */ |
| |
| for (cnt = 0; cnt < 16; cnt++) { |
| WRT_REG_WORD(®->nvram, (NV_SELECT | NV_CLOCK)); |
| NVRAM_DELAY(); |
| data <<= 1; |
| reg_data = RD_REG_WORD(®->nvram); |
| if (reg_data & NV_DATA_IN) |
| data |= BIT_0; |
| WRT_REG_WORD(®->nvram, NV_SELECT); |
| NVRAM_DELAY(); |
| } |
| |
| /* Deselect chip. */ |
| |
| WRT_REG_WORD(®->nvram, NV_DESELECT); |
| NVRAM_DELAY(); |
| |
| return data; |
| } |
| |
| static void |
| qla1280_nv_write(struct scsi_qla_host *ha, uint16_t data) |
| { |
| struct device_reg *reg = ha->iobase; |
| |
| WRT_REG_WORD(®->nvram, data | NV_SELECT); |
| NVRAM_DELAY(); |
| WRT_REG_WORD(®->nvram, data | NV_SELECT | NV_CLOCK); |
| NVRAM_DELAY(); |
| WRT_REG_WORD(®->nvram, data | NV_SELECT); |
| NVRAM_DELAY(); |
| } |
| |
| /* |
| * Mailbox Command |
| * Issue mailbox command and waits for completion. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * mr = mailbox registers to load. |
| * mb = data pointer for mailbox registers. |
| * |
| * Output: |
| * mb[MAILBOX_REGISTER_COUNT] = returned mailbox data. |
| * |
| * Returns: |
| * 0 = success |
| */ |
| static int |
| qla1280_mailbox_command(struct scsi_qla_host *ha, uint8_t mr, uint16_t * mb) |
| { |
| struct device_reg *reg = ha->iobase; |
| #if 0 |
| srb_t *done_q_first = 0; |
| srb_t *done_q_last = 0; |
| #endif |
| int status = 0; |
| int cnt; |
| uint16_t *optr, *iptr; |
| uint16_t data; |
| |
| ENTER("qla1280_mailbox_command"); |
| |
| ha->flags.mbox_busy = TRUE; |
| |
| if (!ha->flags.ints_enabled) |
| printk(KERN_DEBUG |
| "Running qla1280_mailbox_command() with interrupts " |
| "disabled!\n"); |
| /* |
| * We really should start out by verifying that the mailbox is available |
| * before starting sending the command data |
| */ |
| /* Load mailbox registers. */ |
| optr = (uint16_t *) ®->mailbox0; |
| iptr = mb; |
| for (cnt = 0; cnt < MAILBOX_REGISTER_COUNT; cnt++) { |
| if (mr & BIT_0) { |
| WRT_REG_WORD(optr, (*iptr)); |
| } |
| |
| mr >>= 1; |
| optr++; |
| iptr++; |
| } |
| |
| /* Issue set host interrupt command. */ |
| ha->flags.mbox_int = FALSE; |
| ha->flags.mbox_busy = FALSE; |
| WRT_REG_WORD(®->host_cmd, HC_SET_HOST_INT); |
| data = qla1280_debounce_register(®->istatus); |
| |
| /* |
| * This is insane - instead of looping to wait for the interrupt |
| * to appear and run the handler (this is insane!!), use a waitqueue |
| * and go to sleep. |
| * |
| * We are never called here from interrupt context anyway! /Jes |
| */ |
| /* Wait for 30 seconds for command to finish. */ |
| for (cnt = 30000000; cnt > 0 && !ha->flags.mbox_int; cnt--) { |
| /* Check for pending interrupts. */ |
| #if 0 |
| if (data & RISC_INT) { |
| qla1280_isr(ha, &done_q_first, &done_q_last); |
| } else |
| #endif |
| udelay(1); |
| |
| data = RD_REG_WORD(®->istatus); |
| } |
| |
| /* Check for mailbox command timeout. */ |
| if (!cnt) { |
| printk(KERN_WARNING |
| "qla1280_mailbox_command: **** Command Timeout, " |
| "mailbox0 = 0x%x****\n", mb[0]); |
| |
| ha->flags.isp_abort_needed = TRUE; |
| status = 1; |
| } else if (ha->mailbox_out[0] != MBS_CMD_CMP) |
| status = 1; |
| |
| /* Load return mailbox registers. */ |
| optr = mb; |
| iptr = (uint16_t *) &ha->mailbox_out[0]; |
| mr = MAILBOX_REGISTER_COUNT; |
| memcpy(optr, iptr, MAILBOX_REGISTER_COUNT * sizeof(uint16_t)); |
| |
| #if 0 |
| /* Go check for any response interrupts pending. */ |
| qla1280_isr(ha, &done_q_first, &done_q_last); |
| #endif |
| |
| if (ha->flags.isp_abort_needed) |
| qla1280_abort_isp(ha); |
| |
| if (ha->flags.reset_marker) |
| qla1280_rst_aen(ha); |
| |
| #if 0 |
| if (done_q_first) |
| qla1280_done (ha, &done_q_first, &done_q_last); |
| #endif |
| |
| if (status) |
| dprintk(2, |
| "qla1280_mailbox_command: **** FAILED, mailbox0 = 0x%x " |
| "****n", mb[0]); |
| |
| LEAVE("qla1280_mailbox_command"); |
| return status; |
| } |
| |
| /* |
| * qla1280_poll |
| * Polls ISP for interrupts. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| */ |
| static void |
| qla1280_poll(struct scsi_qla_host *ha) |
| { |
| struct device_reg *reg = ha->iobase; |
| uint16_t data; |
| srb_t *done_q_first = 0; |
| srb_t *done_q_last = 0; |
| |
| /* ENTER("qla1280_poll"); */ |
| |
| /* Check for pending interrupts. */ |
| data = RD_REG_WORD(®->istatus); |
| if (data & RISC_INT) |
| qla1280_isr(ha, &done_q_first, &done_q_last); |
| |
| if (!ha->flags.mbox_busy) { |
| if (ha->flags.isp_abort_needed) |
| qla1280_abort_isp(ha); |
| if (ha->flags.reset_marker) |
| qla1280_rst_aen(ha); |
| } |
| |
| if (done_q_first) |
| qla1280_done(ha, &done_q_first, &done_q_last); |
| |
| /* LEAVE("qla1280_poll"); */ |
| } |
| |
| /* |
| * qla1280_bus_reset |
| * Issue SCSI bus reset. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * bus = SCSI bus number. |
| * |
| * Returns: |
| * 0 = success |
| */ |
| static int |
| qla1280_bus_reset(struct scsi_qla_host *ha, int bus) |
| { |
| uint16_t mb[MAILBOX_REGISTER_COUNT]; |
| int status; |
| |
| dprintk(3, "qla1280_bus_reset: entered\n"); |
| |
| if (qla1280_verbose) |
| printk(KERN_INFO "scsi(%li): Resetting SCSI BUS (%i)\n", |
| ha->host_no, bus); |
| |
| mb[0] = MBC_BUS_RESET; |
| mb[1] = ha->bus_settings[bus].bus_reset_delay; |
| mb[2] = (uint16_t) bus; |
| status = qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]); |
| |
| if (status) { |
| if (ha->bus_settings[bus].failed_reset_count > 2) /* dg - 03/13/99 */ |
| ha->bus_settings[bus].scsi_bus_dead = TRUE; |
| ha->bus_settings[bus].failed_reset_count++; |
| } else { |
| /* |
| * Eeeeep! This is evil! /Jes |
| */ |
| #if 0 |
| mdelay(4000); |
| #else |
| schedule_timeout(4 * HZ); |
| #endif |
| ha->bus_settings[bus].scsi_bus_dead = FALSE; /* dg - 03/13/99 */ |
| ha->bus_settings[bus].failed_reset_count = 0; |
| /* Issue marker command. */ |
| qla1280_marker(ha, bus, 0, 0, MK_SYNC_ALL); |
| } |
| |
| if (status) |
| dprintk(2, "qla1280_bus_reset: **** FAILED ****\n"); |
| else |
| dprintk(3, "qla1280_bus_reset: exiting normally\n"); |
| |
| return status; |
| } |
| |
| /* |
| * qla1280_device_reset |
| * Issue bus device reset message to the target. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * bus = SCSI BUS number. |
| * target = SCSI ID. |
| * |
| * Returns: |
| * 0 = success |
| */ |
| static int |
| qla1280_device_reset(struct scsi_qla_host *ha, int bus, int target) |
| { |
| uint16_t mb[MAILBOX_REGISTER_COUNT]; |
| int status; |
| |
| ENTER("qla1280_device_reset"); |
| |
| mb[0] = MBC_ABORT_TARGET; |
| mb[1] = (bus ? (target | BIT_7) : target) << 8; |
| mb[2] = 1; |
| status = qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]); |
| |
| /* Issue marker command. */ |
| qla1280_marker(ha, bus, target, 0, MK_SYNC_ID); |
| |
| if (status) |
| dprintk(2, "qla1280_device_reset: **** FAILED ****\n"); |
| |
| LEAVE("qla1280_device_reset"); |
| return status; |
| } |
| |
| /* |
| * qla1280_abort_device |
| * Issue an abort message to the device |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * bus = SCSI BUS. |
| * target = SCSI ID. |
| * lun = SCSI LUN. |
| * |
| * Returns: |
| * 0 = success |
| */ |
| static int |
| qla1280_abort_device(struct scsi_qla_host *ha, int bus, int target, int lun) |
| { |
| uint16_t mb[MAILBOX_REGISTER_COUNT]; |
| int status; |
| |
| ENTER("qla1280_abort_device"); |
| |
| mb[0] = MBC_ABORT_DEVICE; |
| mb[1] = (bus ? target | BIT_7 : target) << 8 | lun; |
| status = qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); |
| |
| /* Issue marker command. */ |
| qla1280_marker(ha, bus, target, lun, MK_SYNC_ID_LUN); |
| |
| if (status) |
| dprintk(2, "qla1280_abort_device: **** FAILED ****\n"); |
| |
| LEAVE("qla1280_abort_device"); |
| return status; |
| } |
| |
| /* |
| * qla1280_abort_command |
| * Abort command aborts a specified IOCB. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * sp = SB structure pointer. |
| * |
| * Returns: |
| * 0 = success |
| */ |
| static int |
| qla1280_abort_command(struct scsi_qla_host *ha, srb_t * sp) |
| { |
| uint16_t mb[MAILBOX_REGISTER_COUNT]; |
| unsigned int bus, target, lun; |
| uint32_t handle; |
| int status; |
| |
| ENTER("qla1280_abort_command"); |
| |
| /* Locate handle number. */ |
| for (handle = 0; handle < MAX_OUTSTANDING_COMMANDS; handle++) |
| if (ha->outstanding_cmds[handle] == sp) |
| break; |
| |
| bus = SCSI_BUS_32(sp->cmd); |
| target = SCSI_TCN_32(sp->cmd); |
| lun = SCSI_LUN_32(sp->cmd); |
| |
| mb[0] = MBC_ABORT_COMMAND; |
| mb[1] = (bus ? target | BIT_7 : target) << 8 | lun; |
| mb[2] = handle >> 16; |
| mb[3] = handle & 0xffff; |
| status = |
| qla1280_mailbox_command(ha, BIT_3 | BIT_2 | BIT_1 | BIT_0, &mb[0]); |
| |
| if (status) |
| dprintk(2, "qla1280_abort_command: **** FAILED ****\n"); |
| |
| sp->flags |= SRB_ABORT_PENDING; |
| |
| LEAVE("qla1280_abort_command"); |
| return status; |
| } |
| |
| /* |
| * qla1280_reset_adapter |
| * Reset adapter. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| */ |
| static void |
| qla1280_reset_adapter(struct scsi_qla_host *ha) |
| { |
| struct device_reg *reg = ha->iobase; |
| |
| ENTER("qla1280_reset_adapter"); |
| |
| /* Disable ISP chip */ |
| ha->flags.online = FALSE; |
| WRT_REG_WORD(®->ictrl, ISP_RESET); |
| WRT_REG_WORD(®->host_cmd, HC_RESET_RISC); |
| WRT_REG_WORD(®->host_cmd, HC_RELEASE_RISC); |
| WRT_REG_WORD(®->host_cmd, HC_DISABLE_BIOS); |
| |
| LEAVE("qla1280_reset_adapter"); |
| } |
| |
| /* |
| * Issue marker command. |
| * Function issues marker IOCB. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * bus = SCSI BUS number |
| * id = SCSI ID |
| * lun = SCSI LUN |
| * type = marker modifier |
| */ |
| static void |
| qla1280_marker(struct scsi_qla_host *ha, int bus, int id, int lun, u8 type) |
| { |
| mrk_entry_t *pkt; |
| |
| ENTER("qla1280_marker"); |
| |
| /* Get request packet. */ |
| if ((pkt = (mrk_entry_t *) qla1280_req_pkt(ha))) { |
| pkt->entry_type = MARKER_TYPE; |
| pkt->lun = (uint8_t) lun; |
| pkt->target = (uint8_t) (bus ? (id | BIT_7) : id); |
| pkt->modifier = type; |
| |
| /* Issue command to ISP */ |
| qla1280_isp_cmd(ha); |
| } |
| |
| LEAVE("qla1280_marker"); |
| } |
| |
| #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,18) |
| /* |
| * qla1280_64bit_start_scsi |
| * The start SCSI is responsible for building request packets on |
| * request ring and modifying ISP input pointer. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * sp = SB structure pointer. |
| * |
| * Returns: |
| * 0 = success, was able to issue command. |
| */ |
| static int |
| qla1280_64bit_start_scsi(struct scsi_qla_host *ha, srb_t * sp) |
| { |
| struct device_reg *reg = ha->iobase; |
| Scsi_Cmnd *cmd = sp->cmd; |
| cmd_a64_entry_t *pkt; |
| struct scatterlist *sg = NULL; |
| u32 *dword_ptr; |
| dma_addr_t dma_handle; |
| int status = 0; |
| int cnt; |
| int req_cnt; |
| u16 seg_cnt; |
| |
| ENTER("qla1280_64bit_start_scsi:"); |
| |
| dprintk(1, "64bit_start: cmd=%p sp=%p CDB=%x\n", cmd, sp, |
| cmd->cmnd[0]); |
| |
| /* Calculate number of entries and segments required. */ |
| req_cnt = 1; |
| if (cmd->use_sg) { /* 3.13 64 bit */ |
| sg = (struct scatterlist *) cmd->request_buffer; |
| seg_cnt = pci_map_sg (ha->pdev, sg, cmd->use_sg, |
| scsi_to_pci_dma_dir(cmd->sc_data_direction)); |
| |
| if (seg_cnt > 2) { |
| req_cnt += (seg_cnt - 2) / 5; |
| if ((seg_cnt - 2) % 5) |
| req_cnt++; |
| } |
| } else if (cmd->request_bufflen) { /* If data transfer. */ |
| seg_cnt = 1; |
| } else { |
| seg_cnt = 0; |
| } |
| |
| if ((req_cnt + 2) >= ha->req_q_cnt) { |
| /* Calculate number of free request entries. */ |
| cnt = RD_REG_WORD(®->mailbox4); |
| if (ha->req_ring_index < cnt) |
| ha->req_q_cnt = cnt - ha->req_ring_index; |
| else |
| ha->req_q_cnt = |
| REQUEST_ENTRY_CNT - (ha->req_ring_index - cnt); |
| } |
| |
| /* If room for request in request ring. */ |
| if ((req_cnt + 2) < ha->req_q_cnt) { |
| /* Check for room in outstanding command list. */ |
| for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS && |
| ha->outstanding_cmds[cnt] != 0; cnt++) ; |
| |
| if (cnt < MAX_OUTSTANDING_COMMANDS) { |
| ha->outstanding_cmds[cnt] = sp; |
| ha->req_q_cnt -= req_cnt; |
| CMD_HANDLE(sp->cmd) = |
| (unsigned char *)(unsigned long)cnt; |
| |
| /* |
| * Build command packet. |
| */ |
| pkt = (cmd_a64_entry_t *) ha->request_ring_ptr; |
| |
| pkt->entry_type = COMMAND_A64_TYPE; |
| pkt->entry_count = (uint8_t) req_cnt; |
| pkt->sys_define = (uint8_t) ha->req_ring_index; |
| pkt->handle = (uint32_t) cnt; |
| |
| /* Zero out remaining portion of packet. */ |
| memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8)); |
| |
| /* Set ISP command timeout. */ |
| pkt->timeout = 30; |
| |
| /* Set device target ID and LUN */ |
| pkt->lun = SCSI_LUN_32(cmd); |
| pkt->target = SCSI_BUS_32(cmd) ? |
| (SCSI_TCN_32(cmd) | BIT_7) : SCSI_TCN_32(cmd); |
| |
| /* Enable simple tag queuing if device supports it. */ |
| if (cmd->device->tagged_queue) |
| pkt->control_flags |= BIT_3; |
| |
| /* Load SCSI command packet. */ |
| pkt->cdb_len = (uint16_t)CMD_CDBLEN(cmd); |
| memcpy(pkt->scsi_cdb, &(CMD_CDBP(cmd)), pkt->cdb_len); |
| /* dprintk(1, "Build packet for command[0]=0x%x\n",pkt->scsi_cdb[0]); */ |
| |
| /* |
| * Load data segments. |
| */ |
| if (seg_cnt) { /* If data transfer. */ |
| /* Set transfer direction. */ |
| if ((cmd->data_cmnd[0] == WRITE_6)) |
| pkt->control_flags |= BIT_6; |
| else |
| pkt->control_flags |= (BIT_5 | BIT_6); |
| |
| sp->dir = pkt->control_flags & (BIT_5 | BIT_6); |
| |
| /* Set total data segment count. */ |
| pkt->dseg_count = seg_cnt; |
| |
| /* Setup packet address segment pointer. */ |
| dword_ptr = (u32 *)&pkt->dseg_0_address; |
| |
| if (cmd->use_sg) { /* If scatter gather */ |
| /* Load command entry data segments. */ |
| for (cnt = 0; cnt < 2 && seg_cnt; |
| cnt++, seg_cnt--) { |
| /* 3.13 64 bit */ |
| *dword_ptr++ = |
| cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))); |
| *dword_ptr++ = |
| cpu_to_le32(pci_dma_hi32(sg_dma_address(sg))); |
| *dword_ptr++ = |
| cpu_to_le32(sg_dma_len(sg)); |
| sg++; |
| dprintk(1, |
| "S/G Segment phys_addr=%x %x, len=0x%x\n", |
| cpu_to_le32(pci_dma_hi32(sg_dma_address(sg))), |
| cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))), |
| cpu_to_le32(sg_dma_len(sg))); |
| } |
| dprintk(5, |
| "qla1280_64bit_start_scsi: Scatter/gather " |
| "command packet data - b %i, t %i, l %i \n", |
| SCSI_BUS_32(cmd), |
| SCSI_TCN_32(cmd), |
| SCSI_LUN_32(cmd)); |
| qla1280_dump_buffer(5, (char *)pkt, |
| REQUEST_ENTRY_SIZE); |
| |
| /* |
| * Build continuation packets. |
| */ |
| dprintk(1, |
| "S/G Building Continuation...seg_cnt=0x%x " |
| "remains\n", seg_cnt); |
| |
| while (seg_cnt > 0) { |
| /* Adjust ring index. */ |
| ha->req_ring_index++; |
| if (ha->req_ring_index == |
| REQUEST_ENTRY_CNT) { |
| ha->req_ring_index = 0; |
| ha->request_ring_ptr = |
| ha->request_ring; |
| } else |
| ha->request_ring_ptr++; |
| |
| pkt = (cmd_a64_entry_t *)ha->request_ring_ptr; |
| |
| /* Zero out packet. */ |
| memset(pkt, 0, |
| REQUEST_ENTRY_SIZE); |
| |
| /* Load packet defaults. */ |
| ((cont_a64_entry_t *) pkt)->entry_type = |
| CONTINUE_A64_TYPE; |
| ((cont_a64_entry_t *) pkt)->entry_count = 1; |
| ((cont_a64_entry_t *) pkt)->sys_define = |
| (uint8_t)ha->req_ring_index; |
| /* Setup packet address segment pointer. */ |
| dword_ptr = |
| (u32 *)&((cont_a64_entry_t *) pkt)->dseg_0_address; |
| |
| /* Load continuation entry data segments. */ |
| for (cnt = 0; |
| cnt < 5 && seg_cnt; |
| cnt++, seg_cnt--) { |
| /* 3.13 64 bit */ |
| *dword_ptr++ = |
| cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))); |
| *dword_ptr++ = |
| cpu_to_le32(pci_dma_hi32(sg_dma_address(sg))); |
| *dword_ptr++ = |
| cpu_to_le32(sg_dma_len(sg)); |
| dprintk(1, |
| "S/G Segment Cont. phys_addr=%x %x, len=0x%x\n", |
| cpu_to_le32(pci_dma_hi32(sg_dma_address(sg))), |
| cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))), |
| cpu_to_le32(sg_dma_len(sg))); |
| sg++; |
| } |
| dprintk(5, |
| "qla1280_64bit_start_scsi: continuation " |
| "packet data - b %i, t %i, l %i \n", |
| SCSI_BUS_32(cmd), |
| SCSI_TCN_32(cmd), |
| SCSI_LUN_32(cmd)); |
| qla1280_dump_buffer(5, |
| (char *)pkt, |
| REQUEST_ENTRY_SIZE); |
| } |
| } else { /* No scatter gather data transfer */ |
| /* 3.13 64 bit */ |
| dma_handle = pci_map_single(ha->pdev, |
| cmd->request_buffer, |
| cmd->request_bufflen, |
| scsi_to_pci_dma_dir(cmd->sc_data_direction)); |
| /* save dma_handle for pci_unmap_single */ |
| sp->saved_dma_handle = dma_handle; |
| |
| *dword_ptr++ = |
| cpu_to_le32(pci_dma_lo32(dma_handle)); |
| *dword_ptr++ = |
| cpu_to_le32(pci_dma_hi32(dma_handle)); |
| *dword_ptr = |
| (uint32_t)cmd->request_bufflen; |
| /* dprintk(1, |
| "No S/G map_single saved_dma_handle=%lx\n",dma_handle); |
| */ |
| dprintk(5, |
| "qla1280_64bit_start_scsi: No scatter/gather " |
| "command packet data - b %i, t %i, l %i \n", |
| SCSI_BUS_32(cmd), |
| SCSI_TCN_32(cmd), |
| SCSI_LUN_32(cmd)); |
| qla1280_dump_buffer(5, (char *)pkt, |
| REQUEST_ENTRY_SIZE); |
| } |
| } else { /* No data transfer */ |
| |
| dword_ptr = (uint32_t *)(pkt + 1); |
| *dword_ptr++ = 0; |
| *dword_ptr++ = 0; |
| *dword_ptr = 0; |
| dprintk(5, |
| "qla1280_64bit_start_scsi: No data, command " |
| "packet data - b %i, t %i, l %i \n", |
| SCSI_BUS_32(cmd), SCSI_TCN_32(cmd), |
| SCSI_LUN_32(cmd)); |
| qla1280_dump_buffer(5, (char *)pkt, |
| REQUEST_ENTRY_SIZE); |
| } |
| /* Adjust ring index. */ |
| ha->req_ring_index++; |
| if (ha->req_ring_index == REQUEST_ENTRY_CNT) { |
| ha->req_ring_index = 0; |
| ha->request_ring_ptr = ha->request_ring; |
| } else |
| ha->request_ring_ptr++; |
| |
| /* Set chip new ring index. */ |
| dprintk(1, |
| "qla1280_64bit_start_scsi: Wakeup RISC for pending command\n"); |
| ha->qthreads--; |
| sp->flags |= SRB_SENT; |
| ha->actthreads++; |
| WRT_REG_WORD(®->mailbox4, ha->req_ring_index); |
| } else { |
| status = 1; |
| dprintk(2, "qla1280_64bit_start_scsi: NO ROOM IN " |
| "OUTSTANDING ARRAY, req_q_cnt=0x%x", |
| ha->req_q_cnt); |
| } |
| } else { |
| status = 1; |
| dprintk(2, |
| "qla1280_64bit_start_scsi: in-ptr=0x%x req_q_cnt=0x%x" |
| "req_cnt=0x%x", ha->req_ring_index, ha->req_q_cnt, |
| req_cnt); |
| } |
| |
| if (status) |
| dprintk(2, "qla1280_64bit_start_scsi: **** FAILED ****\n"); |
| else |
| dprintk(3, "qla1280_64bit_start_scsi: exiting normally\n"); |
| |
| return status; |
| } |
| #endif |
| |
| /* |
| * qla1280_32bit_start_scsi |
| * The start SCSI is responsible for building request packets on |
| * request ring and modifying ISP input pointer. |
| * |
| * The Qlogic firmware interface allows every queue slot to have a SCSI |
| * command and up to 4 scatter/gather (SG) entries. If we need more |
| * than 4 SG entries, then continuation entries are used that can |
| * hold another 7 entries each. The start routine determines if there |
| * is eought empty slots then build the combination of requests to |
| * fulfill the OS request. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * sp = SCSI Request Block structure pointer. |
| * |
| * Returns: |
| * 0 = success, was able to issue command. |
| */ |
| static int |
| qla1280_32bit_start_scsi(struct scsi_qla_host *ha, srb_t * sp) |
| { |
| struct device_reg *reg = ha->iobase; |
| Scsi_Cmnd *cmd = sp->cmd; |
| cmd_entry_t *pkt; |
| struct scatterlist *sg = NULL; |
| uint32_t *dword_ptr; |
| int status = 0; |
| int cnt; |
| int req_cnt; |
| uint16_t seg_cnt; |
| dma_addr_t dma_handle; |
| |
| ENTER("qla1280_32bit_start_scsi"); |
| |
| dprintk(1, "32bit_start: cmd=%p sp=%p CDB=%x\n", cmd, sp, |
| cmd->cmnd[0]); |
| |
| /* Calculate number of entries and segments required. */ |
| req_cnt = 1; |
| if (cmd->use_sg) { |
| /* |
| * We must build an SG list in adapter format, as the kernel's SG list |
| * cannot be used directly because of data field size (__alpha__) |
| * differences and the kernel SG list uses virtual addresses where |
| * we need physical addresses. |
| */ |
| sg = (struct scatterlist *) cmd->request_buffer; |
| /* 3.13 32 bit */ |
| seg_cnt = pci_map_sg (ha->pdev, sg, cmd->use_sg, |
| scsi_to_pci_dma_dir(cmd->sc_data_direction)); |
| |
| /* |
| * if greater than four sg entries then we need to allocate |
| * continuation entries |
| */ |
| if (seg_cnt > 4) { |
| req_cnt += (seg_cnt - 4) / 7; |
| if ((seg_cnt - 4) % 7) |
| req_cnt++; |
| } |
| dprintk(1, "S/G Transfer cmd=%p seg_cnt=0x%x, req_cnt=%x\n", |
| cmd, seg_cnt, req_cnt); |
| } else if (cmd->request_bufflen) { /* If data transfer. */ |
| dprintk(1, "No S/G transfer t=%x cmd=%p len=%x CDB=%x\n", |
| SCSI_TCN_32(cmd), cmd, cmd->request_bufflen, |
| cmd->cmnd[0]); |
| seg_cnt = 1; |
| } else { |
| /* dprintk(1, "No data transfer \n"); */ |
| seg_cnt = 0; |
| } |
| |
| if ((req_cnt + 2) >= ha->req_q_cnt) { |
| /* Calculate number of free request entries. */ |
| cnt = RD_REG_WORD(®->mailbox4); |
| if (ha->req_ring_index < cnt) |
| ha->req_q_cnt = cnt - ha->req_ring_index; |
| else |
| ha->req_q_cnt = |
| REQUEST_ENTRY_CNT - (ha->req_ring_index - cnt); |
| } |
| |
| dprintk(1, "Number of free entries=(%d) seg_cnt=0x%x\n", |
| ha->req_q_cnt, seg_cnt); |
| /* If room for request in request ring. */ |
| if ((req_cnt + 2) < ha->req_q_cnt) { |
| /* Check for empty slot in outstanding command list. */ |
| for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS && |
| (ha->outstanding_cmds[cnt] != 0); cnt++) ; |
| |
| if (cnt < MAX_OUTSTANDING_COMMANDS) { |
| CMD_HANDLE(sp->cmd) = |
| (unsigned char *) (unsigned long) cnt; |
| ha->outstanding_cmds[cnt] = sp; |
| ha->req_q_cnt -= req_cnt; |
| |
| /* |
| * Build command packet. |
| */ |
| pkt = (cmd_entry_t *) ha->request_ring_ptr; |
| |
| pkt->entry_type = COMMAND_TYPE; |
| pkt->entry_count = (uint8_t) req_cnt; |
| pkt->sys_define = (uint8_t) ha->req_ring_index; |
| pkt->handle = (uint32_t) cnt; |
| |
| /* Zero out remaining portion of packet. */ |
| memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8)); |
| |
| /* Set ISP command timeout. */ |
| pkt->timeout = 30; |
| |
| /* Set device target ID and LUN */ |
| pkt->lun = SCSI_LUN_32(cmd); |
| pkt->target = SCSI_BUS_32(cmd) ? |
| (SCSI_TCN_32(cmd) | BIT_7) : SCSI_TCN_32(cmd); |
| |
| /* Enable simple tag queuing if device supports it. */ |
| if (cmd->device->tagged_queue) |
| pkt->control_flags |= BIT_3; |
| |
| /* Load SCSI command packet. */ |
| pkt->cdb_len = (uint16_t) CMD_CDBLEN(cmd); |
| memcpy(pkt->scsi_cdb, &(CMD_CDBP(cmd)), pkt->cdb_len); |
| |
| /*dprintk(1, "Build packet for command[0]=0x%x\n",pkt->scsi_cdb[0]); */ |
| /* |
| * Load data segments. |
| */ |
| if (seg_cnt) { |
| /* Set transfer direction (READ and WRITE) */ |
| /* Linux doesn't tell us */ |
| /* |
| * For block devices, cmd->request->cmd has the operation |
| * For character devices, this isn't always set properly, so |
| * we need to check data_cmnd[0]. This catches the conditions |
| * for st.c, but not sg. Generic commands are pass down to us. |
| */ |
| if ((cmd->data_cmnd[0] == WRITE_6)) |
| pkt->control_flags |= BIT_6; |
| else |
| pkt->control_flags |= (BIT_5 | BIT_6); |
| |
| sp->dir = pkt->control_flags & (BIT_5 | BIT_6); |
| |
| /* Set total data segment count. */ |
| pkt->dseg_count = seg_cnt; |
| |
| /* Setup packet address segment pointer. */ |
| dword_ptr = &pkt->dseg_0_address; |
| |
| if (cmd->use_sg) { /* If scatter gather */ |
| dprintk(1, "Building S/G data " |
| "segments..\n"); |
| qla1280_dump_buffer(1, (char *)sg, |
| 4 * 16); |
| |
| /* Load command entry data segments. */ |
| for (cnt = 0; cnt < 4 && seg_cnt; |
| cnt++, seg_cnt--) { |
| /* 3.13 32 bit */ |
| #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) |
| *dword_ptr++ = |
| cpu_to_le32(virt_to_bus(sg->address)); |
| *dword_ptr++ = sg->length; |
| dprintk(1, |
| "S/G Segment phys_addr=0x%x, len=0x%x\n", |
| cpu_to_le32(virt_to_bus(sg->address)), |
| sg->length); |
| #else |
| *dword_ptr++ = |
| cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))); |
| *dword_ptr++ = |
| cpu_to_le32(sg_dma_len(sg)); |
| dprintk(1, "S/G Segment phys_addr=0x%x, len=0x%x\n", |
| cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))), |
| cpu_to_le32(sg_dma_len(sg))); |
| #endif |
| sg++; |
| } |
| /* |
| * Build continuation packets. |
| */ |
| dprintk(1, "S/G Building Continuation" |
| "...seg_cnt=0x%x remains\n", |
| seg_cnt); |
| while (seg_cnt > 0) { |
| /* Adjust ring index. */ |
| ha->req_ring_index++; |
| if (ha->req_ring_index == |
| REQUEST_ENTRY_CNT) { |
| ha->req_ring_index = 0; |
| ha->request_ring_ptr = |
| ha->request_ring; |
| } else |
| ha->request_ring_ptr++; |
| |
| pkt = (cmd_entry_t *) |
| ha->request_ring_ptr; |
| |
| /* Zero out packet. */ |
| memset(pkt, 0, |
| REQUEST_ENTRY_SIZE); |
| |
| /* Load packet defaults. */ |
| ((cont_entry_t *) pkt)-> |
| entry_type = CONTINUE_TYPE; |
| ((cont_entry_t *) pkt)-> |
| entry_count = 1; |
| |
| ((cont_entry_t *) pkt)-> |
| sys_define = |
| (uint8_t) ha-> |
| req_ring_index; |
| |
| /* Setup packet address segment pointer. */ |
| dword_ptr = |
| &((cont_entry_t *) pkt)->dseg_0_address; |
| |
| /* Load continuation entry data segments. */ |
| for (cnt = 0; |
| cnt < 7 && seg_cnt; |
| cnt++, seg_cnt--) { |
| /* 3.13 32 bit */ |
| #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) |
| *dword_ptr++ = |
| cpu_to_le32(virt_to_bus(sg->address)); |
| *dword_ptr++ = sg->length; |
| dprintk(1, |
| "S/G Segment Cont. phys_addr=0x%x, len=0x%x\n", |
| cpu_to_le32(pci_dma_lo32(virt_to_bus(sg->address))), sg->length); |
| #else |
| *dword_ptr++ = |
| cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))); |
| *dword_ptr++ = |
| cpu_to_le32(sg_dma_len(sg)); |
| dprintk(1, |
| "S/G Segment Cont. phys_addr=0x%x, " |
| "len=0x%x\n", |
| cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))), |
| cpu_to_le32(sg_dma_len(sg))); |
| #endif |
| sg++; |
| } |
| dprintk(5, |
| "qla1280_32bit_start_scsi: continuation " |
| "packet data - scsi(%i:%i:%i)\n", |
| SCSI_BUS_32(cmd), |
| SCSI_TCN_32(cmd), |
| SCSI_LUN_32(cmd)); |
| qla1280_dump_buffer(5, |
| (char *)pkt, |
| REQUEST_ENTRY_SIZE); |
| } |
| } else { /* No S/G data transfer */ |
| |
| /* 3.13 32 bit */ |
| #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) |
| *dword_ptr++ = |
| cpu_to_le32 (virt_to_bus |
| (cmd->request_buffer)); |
| #else |
| dma_handle = pci_map_single(ha->pdev, |
| cmd->request_buffer, |
| cmd->request_bufflen, |
| scsi_to_pci_dma_dir(cmd->sc_data_direction)); |
| sp->saved_dma_handle = dma_handle; |
| |
| *dword_ptr++ = |
| cpu_to_le32(pci_dma_lo32(dma_handle)); |
| #endif |
| *dword_ptr = |
| (uint32_t)cmd->request_bufflen; |
| } |
| } else { /* No data transfer at all */ |
| |
| dword_ptr = (uint32_t *)(pkt + 1); |
| *dword_ptr++ = 0; |
| *dword_ptr = 0; |
| dprintk(5, |
| "qla1280_32bit_start_scsi: No data, command " |
| "packet data - \n"); |
| qla1280_dump_buffer(5, (char *)pkt, |
| REQUEST_ENTRY_SIZE); |
| } |
| dprintk(5, |
| "qla1280_32bit_start_scsi: First IOCB block:\n"); |
| qla1280_dump_buffer(5, (char *)ha->request_ring_ptr, |
| REQUEST_ENTRY_SIZE); |
| |
| /* Adjust ring index. */ |
| ha->req_ring_index++; |
| if (ha->req_ring_index == REQUEST_ENTRY_CNT) { |
| ha->req_ring_index = 0; |
| ha->request_ring_ptr = ha->request_ring; |
| } else |
| ha->request_ring_ptr++; |
| |
| /* Set chip new ring index. */ |
| dprintk(1, "qla1280_32bit_start_scsi: Wakeup RISC " |
| "for pending command\n"); |
| ha->qthreads--; |
| sp->flags |= SRB_SENT; |
| ha->actthreads++; |
| WRT_REG_WORD(®->mailbox4, ha->req_ring_index); |
| } else { |
| status = 1; |
| dprintk(2, |
| "qla1280_32bit_start_scsi: NO ROOM IN OUTSTANDING " |
| "ARRAY, req_q_cnt=0x%x\n", ha->req_q_cnt); |
| } |
| } else { |
| status = 1; |
| dprintk(2, |
| "qla1280_32bit_start_scsi: in-ptr=0x%x, req_q_cnt=0x%x, " |
| "req_cnt=0x%x", ha->req_ring_index, ha->req_q_cnt, |
| req_cnt); |
| } |
| |
| if (status) |
| dprintk(2, "qla1280_32bit_start_scsi: **** FAILED ****\n"); |
| |
| LEAVE("qla1280_32bit_start_scsi"); |
| |
| return status; |
| } |
| |
| /* |
| * qla1280_req_pkt |
| * Function is responsible for locking ring and |
| * getting a zeroed out request packet. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * |
| * Returns: |
| * 0 = failed to get slot. |
| */ |
| static request_t * |
| qla1280_req_pkt(struct scsi_qla_host *ha) |
| { |
| struct device_reg *reg = ha->iobase; |
| request_t *pkt = 0; |
| int cnt; |
| uint32_t timer; |
| |
| ENTER("qla1280_req_pkt"); |
| |
| /* |
| * This can be called from interrupt context, damn it!!! |
| */ |
| /* Wait for 30 seconds for slot. */ |
| for (timer = 15000000; timer; timer--) { |
| if (ha->req_q_cnt > 0) { |
| /* Calculate number of free request entries. */ |
| cnt = RD_REG_WORD(®->mailbox4); |
| if (ha->req_ring_index < cnt) |
| ha->req_q_cnt = cnt - ha->req_ring_index; |
| else |
| ha->req_q_cnt = |
| REQUEST_ENTRY_CNT - (ha->req_ring_index - cnt); |
| } |
| |
| /* Found empty request ring slot? */ |
| if (ha->req_q_cnt > 0) { |
| ha->req_q_cnt--; |
| pkt = ha->request_ring_ptr; |
| |
| /* Zero out packet. */ |
| memset(pkt, 0, REQUEST_ENTRY_SIZE); |
| |
| /* Set system defined field. */ |
| pkt->sys_define = (uint8_t) ha->req_ring_index; |
| |
| /* Set entry count. */ |
| pkt->entry_count = 1; |
| |
| break; |
| } |
| |
| udelay(2); /* 10 */ |
| |
| /* Check for pending interrupts. */ |
| qla1280_poll(ha); |
| } |
| |
| if (!pkt) |
| dprintk(2, "qla1280_req_pkt: **** FAILED ****\n"); |
| else |
| dprintk(3, "qla1280_req_pkt: exiting normally\n"); |
| |
| return pkt; |
| } |
| |
| /* |
| * qla1280_isp_cmd |
| * Function is responsible for modifying ISP input pointer. |
| * Releases ring lock. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| */ |
| static void |
| qla1280_isp_cmd(struct scsi_qla_host *ha) |
| { |
| struct device_reg *reg = ha->iobase; |
| |
| ENTER("qla1280_isp_cmd"); |
| |
| dprintk(5, "qla1280_isp_cmd: IOCB data:\n"); |
| qla1280_dump_buffer(5, (char *)ha->request_ring_ptr, |
| REQUEST_ENTRY_SIZE); |
| |
| /* Adjust ring index. */ |
| ha->req_ring_index++; |
| if (ha->req_ring_index == REQUEST_ENTRY_CNT) { |
| ha->req_ring_index = 0; |
| ha->request_ring_ptr = ha->request_ring; |
| } else |
| ha->request_ring_ptr++; |
| |
| /* Set chip new ring index. */ |
| WRT_REG_WORD(®->mailbox4, ha->req_ring_index); |
| |
| LEAVE("qla1280_isp_cmd"); |
| } |
| |
| #if QL1280_LUN_SUPPORT |
| /* |
| * qla1280_enable_lun |
| * Issue enable LUN entry IOCB. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * bus = SCSI BUS number. |
| * lun = LUN number. |
| */ |
| static void |
| qla1280_enable_lun(struct scsi_qla_host *ha, int bus, int lun) |
| { |
| elun_entry_t *pkt; |
| |
| ENTER("qla1280_enable_lun"); |
| |
| /* Get request packet. */ |
| /* |
| if (pkt = (elun_entry_t *)qla1280_req_pkt(ha)) |
| { |
| pkt->entry_type = ENABLE_LUN_TYPE; |
| pkt->lun = (uint16_t)(bus ? lun | BIT_15 : lun); |
| pkt->command_count = 32; |
| pkt->immed_notify_count = 1; |
| pkt->group_6_length = MAX_CMDSZ; |
| pkt->group_7_length = MAX_CMDSZ; |
| pkt->timeout = 0x30; |
| |
| qla1280_isp_cmd(ha); |
| } |
| */ |
| pkt = (elun_entry_t *) 1; |
| |
| if (!pkt) |
| dprintk(2, "qla1280_enable_lun: **** FAILED ****\n"); |
| else |
| dprintk(3, "qla1280_enable_lun: exiting normally\n"); |
| } |
| #endif |
| |
| #if QL1280_TARGET_MODE_SUPPORT |
| /****************************************************************************/ |
| /* Target Mode Support Functions. */ |
| /****************************************************************************/ |
| |
| /* |
| * qla1280_notify_ack |
| * Issue notify acknowledge IOCB. |
| * If sequence ID is zero, acknowledgement of |
| * SCSI bus reset or bus device reset is assumed. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * inotify = immediate notify entry pointer. |
| */ |
| static void |
| qla1280_notify_ack(struct scsi_qla_host *ha, notify_entry_t * inotify) |
| { |
| nack_entry_t *pkt; |
| |
| dprintk(3, "qla1280_notify_ack: entered\n"); |
| |
| /* Get request packet. */ |
| if (pkt = (nack_entry_t *) qla1280_req_pkt(ha)) { |
| pkt->entry_type = NOTIFY_ACK_TYPE; |
| pkt->lun = inotify->lun; |
| pkt->initiator_id = inotify->initiator_id; |
| pkt->target_id = inotify->target_id; |
| if (inotify->seq_id == 0) |
| pkt->event = BIT_7; |
| else |
| pkt->seq_id = inotify->seq_id; |
| |
| /* Issue command to ISP */ |
| qla1280_isp_cmd(ha); |
| } |
| |
| if (!pkt) |
| dprintk(2, "qla1280_notify_ack: **** FAILED ****\n"); |
| else |
| dprintk(3, "qla1280_notify_ack: exiting normally\n"); |
| } |
| |
| /* |
| * qla1280_immed_notify |
| * Issue immediate notify IOCB for LUN 0. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * inotify = immediate notify entry pointer. |
| */ |
| static void |
| qla1280_immed_notify(struct scsi_qla_host *ha, notify_entry_t * inotify) |
| { |
| notify_entry_t *pkt; |
| |
| dprintk(3, "qla1280_immed_notify: entered\n"); |
| |
| /* Get request packet. */ |
| if (pkt = (notify_entry_t *) qla1280_req_pkt(ha)) { |
| pkt->entry_type = IMMED_NOTIFY_TYPE; |
| pkt->lun = inotify->lun; |
| pkt->initiator_id = inotify->initiator_id; |
| pkt->target_id = inotify->target_id; |
| pkt->status = 1; |
| |
| /* Issue command to ISP */ |
| qla1280_isp_cmd(ha); |
| } |
| |
| if (!pkt) |
| dprintk(2, "qla1280_immed_notify: **** FAILED ****\n"); |
| else |
| dprintk(3, "qla1280_immed_notify: exiting normally\n"); |
| } |
| |
| /* |
| * qla1280_accept_io |
| * Issue accept target I/O IOCB for LUN 0. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * ctio = ctio returned entry pointer. |
| */ |
| static void |
| qla1280_accept_io(struct scsi_qla_host *ha, ctio_ret_entry_t * ctio) |
| { |
| atio_entry_t *pkt; |
| |
| dprintk(3, "qla1280_accept_io: entered\n"); |
| |
| /* Get request packet. */ |
| if (pkt = (atio_entry_t *) qla1280_req_pkt(ha)) { |
| pkt->entry_type = ACCEPT_TGT_IO_TYPE; |
| pkt->lun = ctio->lun; |
| pkt->initiator_id = ctio->initiator_id; |
| pkt->target_id = ctio->target_id; |
| pkt->tag_value = ctio->tag_value; |
| pkt->status = 1; |
| |
| /* Issue command to ISP */ |
| qla1280_isp_cmd(ha); |
| } |
| |
| if (!pkt) |
| dprintk(2, "qla1280_accept_io: **** FAILED ****\n"); |
| else |
| dprintk(3, "qla1280_accept_io: exiting normally\n"); |
| } |
| |
| /* |
| * qla1280_64bit_continue_io |
| * Issue continue target I/O IOCB. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * atio = atio pointer. |
| * len = total bytecount. |
| * addr = physical address pointer. |
| */ |
| static void |
| qla1280_64bit_continue_io(struct scsi_qla_host *ha, atio_entry_t * atio, |
| uint32_t len, paddr32_t * addr) |
| { |
| ctio_a64_entry_t *pkt; |
| uint32_t *dword_ptr; |
| |
| dprintk(3, "qla1280_64bit_continue_io: entered\n"); |
| |
| /* Get request packet. */ |
| if (pkt = (ctio_a64_entry_t *) qla1280_req_pkt(ha)) { |
| pkt->entry_type = CTIO_A64_TYPE; |
| pkt->lun = atio->lun; |
| pkt->initiator_id = atio->initiator_id; |
| pkt->target_id = atio->target_id; |
| pkt->option_flags = atio->option_flags; |
| pkt->tag_value = atio->tag_value; |
| pkt->scsi_status = atio->scsi_status; |
| |
| if (len) { |
| pkt->dseg_count = 1; |
| pkt->transfer_length = len; |
| pkt->dseg_0_length = len; |
| dword_ptr = (uint32_t *) addr; |
| pkt->dseg_0_address[0] = *dword_ptr++; |
| pkt->dseg_0_address[1] = *dword_ptr; |
| } |
| |
| /* Issue command to ISP */ |
| qla1280_isp_cmd(ha); |
| } |
| |
| if (!pkt) |
| dprintk(2, "qla1280_64bit_continue_io: **** FAILED ****\n"); |
| else |
| dprintk(3, "qla1280_64bit_continue_io: exiting normally\n"); |
| } |
| |
| /* |
| * qla1280_32bit_continue_io |
| * Issue continue target I/O IOCB. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * atio = atio pointer. |
| * len = total bytecount. |
| * addr = physical address pointer. |
| */ |
| static void |
| qla1280_32bit_continue_io(struct scsi_qla_host *ha, atio_entry_t * atio, |
| uint32_t len, paddr32_t * addr) |
| { |
| ctio_entry_t *pkt; |
| uint32_t *dword_ptr; |
| |
| dprintk(3, "qla1280_32bit_continue_io: entered\n"); |
| |
| /* Get request packet. */ |
| if (pkt = (ctio_entry_t *) qla1280_req_pkt(ha)) { |
| pkt->entry_type = CONTINUE_TGT_IO_TYPE; |
| pkt->lun = atio->lun; |
| pkt->initiator_id = atio->initiator_id; |
| pkt->target_id = atio->target_id; |
| pkt->option_flags = atio->option_flags; |
| pkt->tag_value = atio->tag_value; |
| pkt->scsi_status = atio->scsi_status; |
| |
| if (len) { |
| pkt->dseg_count = 1; |
| pkt->transfer_length = len; |
| pkt->dseg_0_length = len; |
| dword_ptr = (uint32_t *) addr; |
| pkt->dseg_0_address = *dword_ptr; |
| } |
| |
| /* Issue command to ISP */ |
| qla1280_isp_cmd(ha); |
| } |
| |
| if (!pkt) |
| dprintk(2, "qla1280_32bit_continue_io: **** FAILED ****\n"); |
| else |
| dprintk(3, "qla1280_32bit_continue_io: exiting normally\n"); |
| } |
| #endif /* QL1280_TARGET_MODE_SUPPORT */ |
| |
| /****************************************************************************/ |
| /* Interrupt Service Routine. */ |
| /****************************************************************************/ |
| |
| /**************************************************************************** |
| * qla1280_isr |
| * Calls I/O done on command completion. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * done_q_first = done queue first pointer. |
| * done_q_last = done queue last pointer. |
| ****************************************************************************/ |
| static void |
| qla1280_isr(struct scsi_qla_host *ha, srb_t ** done_q_first, |
| srb_t ** done_q_last) |
| { |
| struct device_reg *reg = ha->iobase; |
| response_t *pkt; |
| srb_t *sp = 0; |
| uint16_t mailbox[MAILBOX_REGISTER_COUNT]; |
| uint16_t *wptr; |
| uint32_t index; |
| u16 istatus; |
| |
| ENTER("qla1280_isr"); |
| |
| istatus = RD_REG_WORD(®->istatus); |
| if (!(istatus & (RISC_INT | PCI_INT))) |
| return; |
| |
| /* Save mailbox register 5 */ |
| mailbox[5] = RD_REG_WORD(®->mailbox5); |
| |
| /* Check for mailbox interrupt. */ |
| |
| mailbox[0] = RD_REG_WORD(®->semaphore); |
| |
| if (mailbox[0] & BIT_0) { |
| /* Get mailbox data. */ |
| /* dprintk(1, "qla1280_isr: In Get mailbox data \n"); */ |
| |
| wptr = &mailbox[0]; |
| *wptr++ = RD_REG_WORD(®->mailbox0); |
| *wptr++ = RD_REG_WORD(®->mailbox1); |
| *wptr = RD_REG_WORD(®->mailbox2); |
| if (mailbox[0] != MBA_SCSI_COMPLETION) { |
| wptr++; |
| *wptr++ = RD_REG_WORD(®->mailbox3); |
| *wptr++ = RD_REG_WORD(®->mailbox4); |
| wptr++; |
| *wptr++ = RD_REG_WORD(®->mailbox6); |
| *wptr = RD_REG_WORD(®->mailbox7); |
| } |
| |
| /* Release mailbox registers. */ |
| |
| WRT_REG_WORD(®->semaphore, 0); |
| WRT_REG_WORD(®->host_cmd, HC_CLR_RISC_INT); |
| |
| dprintk(5, "qla1280_isr: mailbox interrupt mailbox[0] = 0x%x", |
| mailbox[0]); |
| |
| /* Handle asynchronous event */ |
| switch (mailbox[0]) { |
| case MBA_SCSI_COMPLETION: /* Response completion */ |
| dprintk(5, |
| "qla1280_isr: mailbox SCSI response completion\n"); |
| |
| if (ha->flags.online) { |
| /* Get outstanding command index. */ |
| index = mailbox[2] << 16 | mailbox[1]; |
| |
| /* Validate handle. */ |
| if (index < MAX_OUTSTANDING_COMMANDS) |
| sp = ha->outstanding_cmds[index]; |
| else |
| sp = 0; |
| |
| if (sp) { |
| /* Free outstanding command slot. */ |
| ha->outstanding_cmds[index] = 0; |
| |
| /* Save ISP completion status */ |
| CMD_RESULT(sp->cmd) = 0; |
| |
| /* Place block on done queue */ |
| sp->s_next = NULL; |
| sp->s_prev = *done_q_last; |
| if (!*done_q_first) |
| *done_q_first = sp; |
| else |
| (*done_q_last)->s_next = sp; |
| *done_q_last = sp; |
| } else { |
| /* |
| * If we get here we have a real problem! |
| */ |
| printk(KERN_WARNING |
| "qla1280: ISP invalid handle"); |
| ha->flags.isp_abort_needed = TRUE; |
| } |
| } |
| break; |
| |
| case MBA_BUS_RESET: /* SCSI Bus Reset */ |
| ha->flags.reset_marker = TRUE; |
| index = mailbox[6] & BIT_0; |
| ha->bus_settings[index].reset_marker = TRUE; |
| |
| printk(KERN_DEBUG |
| "qla1280_isr(): index %i asynchronous " |
| "BUS_RESET\n", index); |
| break; |
| |
| case MBA_SYSTEM_ERR: /* System Error */ |
| printk(KERN_WARNING |
| "qla1280: ISP System Error - mbx1=%xh, mbx2=%xh, " |
| "mbx3=%xh\n", mailbox[1], mailbox[2], |
| mailbox[3]); |
| ha->flags.isp_abort_needed = TRUE; |
| break; |
| |
| case MBA_REQ_TRANSFER_ERR: /* Request Transfer Error */ |
| printk(KERN_WARNING |
| "qla1280: ISP Request Transfer Error\n"); |
| ha->flags.isp_abort_needed = TRUE; |
| break; |
| |
| case MBA_RSP_TRANSFER_ERR: /* Response Transfer Error */ |
| printk(KERN_WARNING |
| "qla1280: ISP Response Transfer Error\n"); |
| ha->flags.isp_abort_needed = TRUE; |
| break; |
| |
| case MBA_WAKEUP_THRES: /* Request Queue Wake-up */ |
| dprintk(2, "qla1280_isr: asynchronous WAKEUP_THRES\n"); |
| break; |
| |
| case MBA_TIMEOUT_RESET: /* Execution Timeout Reset */ |
| dprintk(2, |
| "qla1280_isr: asynchronous TIMEOUT_RESET\n"); |
| break; |
| |
| case MBA_DEVICE_RESET: /* Bus Device Reset */ |
| dprintk(2, |
| "qla1280_isr: asynchronous BUS_DEVICE_RESET\n"); |
| printk(KERN_INFO "qla1280_isr(): asynchronous " |
| "BUS_DEVICE_RESET\n"); |
| |
| ha->flags.reset_marker = TRUE; |
| index = mailbox[6] & BIT_0; |
| ha->bus_settings[index].reset_marker = TRUE; |
| break; |
| |
| case MBA_BUS_MODE_CHANGE: |
| dprintk(2, |
| "qla1280_isr: asynchronous BUS_MODE_CHANGE\n"); |
| break; |
| |
| default: |
| /* dprintk(1, "qla1280_isr: default case of switch MB \n"); */ |
| if (mailbox[0] < MBA_ASYNC_EVENT) { |
| wptr = &mailbox[0]; |
| memcpy((uint16_t *) ha->mailbox_out, wptr, |
| MAILBOX_REGISTER_COUNT * |
| sizeof(uint16_t)); |
| ha->flags.mbox_int = TRUE; |
| } |
| break; |
| } |
| } else { |
| WRT_REG_WORD(®->host_cmd, HC_CLR_RISC_INT); |
| } |
| |
| /* |
| * Response ring - waiting for the mbox_busy flag here seems |
| * unnecessary as the mailbox data has been copied to ha->mailbox_out |
| * by the time we actually get here! |
| */ |
| if (ha->flags.online |
| #if 0 |
| && !ha->flags.mbox_busy |
| #endif |
| ) { |
| if (mailbox[5] < RESPONSE_ENTRY_CNT) { |
| while (ha->rsp_ring_index != mailbox[5]) { |
| pkt = ha->response_ring_ptr; |
| |
| dprintk(5, |
| "qla1280_isr: ha->rsp_ring_index = 0x%x, " |
| "mailbox[5] = 0x%x\n", |
| ha->rsp_ring_index, mailbox[5]); |
| dprintk(5, |
| "qla1280_isr: response packet data\n"); |
| qla1280_dump_buffer(5, (char *)pkt, |
| RESPONSE_ENTRY_SIZE); |
| |
| if (pkt->entry_type == STATUS_TYPE) { |
| if ((pkt->scsi_status & 0xff) |
| || pkt->comp_status |
| || pkt->entry_status) { |
| dprintk(2, |
| "qla1280_isr: ha->rsp_ring_index = 0x%x" |
| "mailbox[5] = 0x%x, comp_status = 0x%x, " |
| "scsi_status = 0x%x\n", |
| ha->rsp_ring_index, |
| mailbox[5], |
| pkt->comp_status, |
| pkt->scsi_status); |
| } |
| } else { |
| dprintk(2, |
| "qla1280_isr: ha->rsp_ring_index = 0x%x, " |
| "mailbox[5] = 0x%x\n", |
| ha->rsp_ring_index, |
| mailbox[5]); |
| dprintk(2, |
| "qla1280_isr: response packet data\n"); |
| qla1280_dump_buffer(2, (char *)pkt, |
| RESPONSE_ENTRY_SIZE); |
| } |
| |
| if (pkt->entry_type == STATUS_TYPE |
| || pkt->entry_status) { |
| if (pkt->entry_type == STATUS_TYPE) |
| qla1280_status_entry(ha, |
| (sts_entry_t *) pkt, |
| done_q_first, |
| done_q_last); |
| else |
| qla1280_error_entry(ha, pkt, |
| done_q_first, |
| done_q_last); |
| |
| /* Adjust ring index. */ |
| ha->rsp_ring_index++; |
| if (ha->rsp_ring_index == |
| RESPONSE_ENTRY_CNT) { |
| ha->rsp_ring_index = 0; |
| ha->response_ring_ptr = |
| ha->response_ring; |
| } else |
| ha->response_ring_ptr++; |
| WRT_REG_WORD(®->mailbox5, |
| ha->rsp_ring_index); |
| } |
| #if QLA1280_TARGET_MODE_SUPPORT |
| else { |
| pkt = &response_entry; |
| |
| /* Copy packet. */ |
| dptr1 = |
| (uint32_t *)ha->response_ring_ptr; |
| dptr2 = (uint32_t *) pkt; |
| for (index = 0; |
| index < RESPONSE_ENTRY_SIZE / 4; |
| index++) |
| *dptr2++ = *dptr1++; |
| |
| /* Adjust ring index. */ |
| ha->rsp_ring_index++; |
| if (ha->rsp_ring_index == |
| RESPONSE_ENTRY_CNT) { |
| ha->rsp_ring_index = 0; |
| ha->response_ring_ptr = |
| ha->response_ring; |
| } else |
| ha->response_ring_ptr++; |
| WRT_REG_WORD(®->mailbox5, |
| ha->rsp_ring_index); |
| |
| switch (pkt->entry_type) { |
| case ACCEPT_TGT_IO_TYPE: |
| qla1280_atio_entry(ha, |
| (atio_entry_t *) pkt); |
| break; |
| case IMMED_NOTIFY_TYPE: |
| qla1280_notify_entry(ha, |
| (notify_entry_t *) pkt); |
| break; |
| case CTIO_RET_TYPE: |
| qla1280_accept_io(ha, |
| (ctio_ret_entry_t *) pkt); |
| break; |
| default: |
| break; |
| } |
| } |
| #endif |
| } |
| } else { |
| ha->flags.isp_abort_needed = TRUE; |
| dprintk(2, "qla1280_isr: Response pointer Error\n"); |
| } |
| } |
| |
| LEAVE("qla1280_isr"); |
| } |
| |
| /* |
| * qla1280_rst_aen |
| * Processes asynchronous reset. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| */ |
| static void |
| qla1280_rst_aen(struct scsi_qla_host *ha) |
| { |
| #if QL1280_TARGET_MODE_SUPPORT |
| notify_entry_t nentry; |
| #endif |
| uint8_t bus; |
| |
| ENTER("qla1280_rst_aen"); |
| |
| if (ha->flags.online && !ha->flags.reset_active && |
| !ha->flags.abort_isp_active) { |
| ha->flags.reset_active = TRUE; |
| while (ha->flags.reset_marker) { |
| /* Issue marker command. */ |
| ha->flags.reset_marker = FALSE; |
| for (bus = 0; bus < ha->ports && |
| !ha->flags.reset_marker; bus++) { |
| if (ha->bus_settings[bus].reset_marker) { |
| ha->bus_settings[bus].reset_marker = |
| FALSE; |
| qla1280_marker(ha, bus, 0, 0, |
| MK_SYNC_ALL); |
| |
| if (!ha->flags.reset_marker) { |
| #if QL1280_TARGET_MODE_SUPPORT |
| /* Issue notify acknowledgement command. */ |
| memset(&nentry, 0, |
| sizeof(notify_entry_t)); |
| |
| nentry.initiator_id = |
| nentry.target_id = |
| bus ? ha->bus_settings[bus].id | BIT_7 : |
| ha->bus_settings[bus].id; |
| qla1280_notify_entry(ha, |
| &nentry); |
| #endif |
| /* Asynchronous event notification */ |
| } |
| } |
| } |
| } |
| } |
| |
| LEAVE("qla1280_rst_aen"); |
| } |
| |
| #if QL1280_TARGET_MODE_SUPPORT |
| /* |
| * qla1280_atio_entry |
| * Processes received ISP accept target I/O entry. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * pkt = entry pointer. |
| */ |
| static void |
| qla1280_atio_entry(struct scsi_qla_host *ha, atio_entry_t * pkt) |
| { |
| uint64_t *a64; |
| uint64_t *end_a64; |
| paddr32_t phy_addr[2]; |
| paddr32_t end_addr[2]; |
| uint32_t len; |
| uint32_t offset; |
| uint8_t t; |
| uint8_t *sense_ptr; |
| |
| dprintk(3, "qla1280_atio_entry: entered\n"); |
| |
| t = pkt->initiator_id; |
| sense_ptr = ha->tsense + t * TARGET_SENSE_SIZE; |
| a64 = (uint64_t *)&phy_addr[0]; |
| end_a64 = (uint64_t *)&end_addr[0]; |
| |
| switch (pkt->status & ~BIT_7) { |
| case 7: /* Path invalid */ |
| dprintk(2, "qla1280_atio_entry: Path invalid\n"); |
| break; |
| |
| case 0x14: /* Target Bus Phase Sequence Failure */ |
| dprintk(2, "qla1280_atio_entry: Target Bus Phase " |
| "Sequence Failure\n"); |
| |
| if (pkt->status & BIT_7) { |
| memcpy(sense_ptr, &pkt->sense_data, TARGET_SENSE_SIZE); |
| } else { |
| memset(sense_ptr, 0, TARGET_SENSE_SIZE); |
| *sense_ptr = 0x70; |
| *(sense_ptr + 2) = SD_HARDERR; |
| *(sense_ptr + 7) = TARGET_SENSE_SIZE - 8; |
| *(sense_ptr + 12) = SC_SELFAIL; |
| } |
| pkt->scsi_status = S_CKCON; |
| pkt->option_flags |= OF_SSTS | OF_NO_DATA; |
| |
| #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18) |
| if (ha->flags.enable_64bit_addressing) |
| qla1280_64bit_continue_io(ha, pkt, 0, 0); |
| else |
| #endif |
| qla1280_32bit_continue_io(ha, pkt, 0, 0); |
| break; |
| |
| case 0x16: /* Requested Capability Not Available */ |
| dprintk(2, "qla1280_atio_entry: Target Bus Phase " |
| "Sequence Failure\n"); |
| break; |
| |
| case 0x17: /* Bus Device Reset Message Received */ |
| dprintk(2, "qla1280_atio_entry: Target Bus Phase " |
| "Sequence Failure\n"); |
| break; |
| |
| case 0x3D: /* CDB Received */ |
| |
| /* Check for invalid LUN */ |
| if (pkt->lun && pkt->cdb[0] != SS_INQUIR && |
| pkt->cdb[0] != SS_REQSEN) |
| pkt->cdb[0] = SS_TEST; |
| |
| switch (pkt->cdb[0]) { |
| case SS_TEST: |
| dprintk(3, "qla1280_atio_entry: SS_TEST\n"); |
| |
| memset(sense_ptr, 0, TARGET_SENSE_SIZE); |
| len = 0; |
| if (pkt->lun == 0) |
| pkt->scsi_status = S_GOOD; |
| else { |
| *sense_ptr = 0x70; |
| *(sense_ptr + 2) = SD_ILLREQ; |
| *(sense_ptr + 7) = TARGET_SENSE_SIZE - 8; |
| *(sense_ptr + 12) = SC_INVLUN; |
| pkt->scsi_status = S_CKCON; |
| } |
| |
| pkt->option_flags |= (OF_SSTS | OF_NO_DATA); |
| break; |
| |
| case SS_REQSEN: |
| dprintk(3, "qla1280_atio_entry: SS_REQSEN\n"); |
| |
| phy_addr[0] = ha->tsense_dma; |
| phy_addr[1] = 0; |
| *a64 += t * TARGET_SENSE_SIZE; |
| if (pkt->cdb[4] > TARGET_SENSE_SIZE) |
| len = TARGET_SENSE_SIZE; |
| else |
| len = pkt->cdb[4]; |
| pkt->scsi_status = S_GOOD; |
| pkt->option_flags |= (OF_SSTS | OF_DATA_IN); |
| break; |
| |
| case SS_INQUIR: |
| dprintk(3, "qla1280_atio_entry: SS_INQUIR\n"); |
| |
| memset(sense_ptr, 0, TARGET_SENSE_SIZE); |
| phy_addr[0] = ha->tbuf_dma; |
| phy_addr[1] = 0; |
| *a64 += TARGET_INQ_OFFSET; |
| |
| if (pkt->lun == 0) { |
| ha->tbuf->inq.id_type = ID_PROCESOR; |
| ha->tbuf->inq.id_pqual = ID_QOK; |
| } else { |
| ha->tbuf->inq.id_type = ID_NODEV; |
| ha->tbuf->inq.id_pqual = ID_QNOLU; |
| } |
| |
| if (pkt->cdb[4] > sizeof(struct ident)) |
| len = sizeof(struct ident); |
| else |
| len = pkt->cdb[4]; |
| pkt->scsi_status = S_GOOD; |
| pkt->option_flags |= (OF_SSTS | OF_DATA_IN); |
| break; |
| |
| case SM_WRDB: |
| memset(sense_ptr, 0, TARGET_SENSE_SIZE); |
| offset = pkt->cdb[5]; |
| offset |= pkt->cdb[4] << 8; |
| offset |= pkt->cdb[3] << 16; |
| len = pkt->cdb[8]; |
| len |= pkt->cdb[7] << 8; |
| len |= pkt->cdb[6] << 16; |
| end_addr[0] = phy_addr[0] = ha->tbuf_dma; |
| end_addr[1] = phy_addr[1] = 0; |
| *end_a64 += TARGET_DATA_OFFSET + TARGET_DATA_SIZE; |
| switch (pkt->cdb[1] & 7) { |
| case RW_BUF_HDATA: |
| dprintk(3, "qla1280_atio_entry: SM_WRDB, " |
| "RW_BUF_HDATA\n"); |
| |
| if (len > TARGET_DATA_SIZE + 4) { |
| dprintk(2, |
| "qla1280_atio_entry: SM_WRDB, " |
| "length > buffer size\n"); |
| |
| *sense_ptr = 0x70; |
| *(sense_ptr + 2) = SD_ILLREQ; |
| *(sense_ptr + 7) = |
| TARGET_SENSE_SIZE - 8; |
| *(sense_ptr + 12) = SC_ILLCDB; |
| pkt->scsi_status = S_CKCON; |
| pkt->option_flags |= |
| (OF_SSTS | OF_NO_DATA); |
| len = 0; |
| } else if (len) { |
| pkt->scsi_status = S_GOOD; |
| pkt->option_flags |= |
| (OF_SSTS | OF_DATA_OUT); |
| dprintk(3, |
| "qla1280_atio_entry: Issuing " |
| "SDI_TARMOD_WRCOMP\n"); |
| |
| sdi_xaen(SDI_TARMOD_WRCOMP, ha->cntlr, |
| pkt->target_id, pkt->lun, 0, |
| offset); |
| } else { |
| dprintk(2, |
| "qla1280_atio_entry: SM_WRDB, " |
| "zero length\n"); |
| |
| pkt->scsi_status = S_GOOD; |
| pkt->option_flags |= |
| (OF_SSTS | OF_NO_DATA); |
| } |
| |
| break; |
| case RW_BUF_DATA: |
| dprintk(3, "qla1280_atio_entry: SM_WRDB, " |
| "RW_BUF_DATA\n"); |
| |
| *a64 += offset + TARGET_DATA_OFFSET; |
| if (pkt->cdb[2] != 0 || *a64 >= *end_a64 || |
| *a64 + len > *end_a64) { |
| dprintk(2, |
| "qla1280_atio_entry: SM_WRDB, " |
| "RW_BUF_DATA BAD\n"); |
| dprintk(2, "buf_id=0x%x, offset=0x%x, " |
| "length=0x%x\n", pkt->cdb[2], |
| offset, len); |
| |
| *sense_ptr = 0x70; |
| *(sense_ptr + 2) = SD_ILLREQ; |
| *(sense_ptr + 7) = |
| TARGET_SENSE_SIZE - 8; |
| *(sense_ptr + 12) = SC_ILLCDB; |
| len = 0; |
| pkt->scsi_status = S_CKCON; |
| pkt->option_flags |= |
| (OF_SSTS | OF_NO_DATA); |
| } else if (len) { |
| pkt->scsi_status = S_GOOD; |
| pkt->option_flags |= |
| (OF_SSTS | OF_DATA_OUT); |
| dprintk(3, |
| "qla1280_atio_entry: Issuing " |
| "SDI_TARMOD_WRCOMP\n"); |
| |
| sdi_xaen(SDI_TARMOD_WRCOMP, ha->cntlr, |
| pkt->target_id, pkt->lun, 0, |
| offset); |
| } else { |
| dprintk(2, |
| "qla1280_atio_entry: SM_WRDB, " |
| "zero length\n"); |
| |
| pkt->scsi_status = S_GOOD; |
| pkt->option_flags |= |
| (OF_SSTS | OF_NO_DATA); |
| } |
| break; |
| |
| default: |
| dprintk(2, "qla1280_atio_entry: SM_WRDB " |
| "unknown mode\n"); |
| |
| *sense_ptr = 0x70; |
| *(sense_ptr + 2) = SD_ILLREQ; |
| *(sense_ptr + 7) = TARGET_SENSE_SIZE - 8; |
| *(sense_ptr + 12) = SC_ILLCDB; |
| len = 0; |
| pkt->scsi_status = S_CKCON; |
| pkt->option_flags |= (OF_SSTS | OF_NO_DATA); |
| break; |
| } |
| break; |
| |
| case SM_RDDB: |
| memset(sense_ptr, 0, TARGET_SENSE_SIZE); |
| offset = pkt->cdb[5]; |
| offset |= pkt->cdb[4] << 8; |
| offset |= pkt->cdb[3] << 16; |
| len = pkt->cdb[8]; |
| len |= pkt->cdb[7] << 8; |
| len |= pkt->cdb[6] << 16; |
| end_addr[0] = phy_addr[0] = ha->tbuf_dma; |
| end_addr[1] = phy_addr[1] = 0; |
| *end_a64 += TARGET_DATA_OFFSET + TARGET_DATA_SIZE; |
| switch (pkt->cdb[1] & 7) { |
| case RW_BUF_HDATA: |
| dprintk(3, "qla1280_atio_entry: SM_RDDB, " |
| "RW_BUF_HDATA\n"); |
| |
| if (len) { |
| ha->tbuf->hdr[0] = 0; |
| ha->tbuf->hdr[1] = |
| (TARGET_DATA_SIZE >> 16) & 0xff; |
| ha->tbuf->hdr[2] = |
| (TARGET_DATA_SIZE >> 8) & 0xff; |
| ha->tbuf->hdr[3] = |
| TARGET_DATA_SIZE & 0xff; |
| if (len > TARGET_DATA_SIZE + 4) |
| len = TARGET_DATA_SIZE + 4; |
| pkt->scsi_status = S_GOOD; |
| pkt->option_flags |= |
| (OF_SSTS | OF_DATA_IN); |
| } else { |
| dprintk(2, |
| "qla1280_atio_entry: SM_RDDB, " |
| "zero length\n"); |
| |
| pkt->scsi_status = S_GOOD; |
| pkt->option_flags |= |
| (OF_SSTS | OF_NO_DATA); |
| } |
| break; |
| case RW_BUF_DATA: |
| dprintk(3, "qla1280_atio_entry: SM_RDDB, " |
| "RW_BUF_DATA\n"); |
| |
| *a64 += offset + TARGET_DATA_OFFSET; |
| if (pkt->cdb[2] != 0 || *a64 >= *end_a64) { |
| dprintk(2, |
| "qla1280_atio_entry: SM_RDDB, " |
| "RW_BUF_DATA BAD\n"); |
| dprintk(2, "buf_id=0x%x, offset=0x%x\n" |
| pkt->cdb[2], offset); |
| |
| *sense_ptr = 0x70; |
| *(sense_ptr + 2) = SD_ILLREQ; |
| *(sense_ptr + 7) = |
| TARGET_SENSE_SIZE - 8; |
| *(sense_ptr + 12) = SC_ILLCDB; |
| len = 0; |
| pkt->scsi_status = S_CKCON; |
| pkt->option_flags |= |
| (OF_SSTS | OF_NO_DATA); |
| } else { |
| if (*a64 + len > *end_a64) |
| len = *end_a64 - *a64; |
| if (len) { |
| pkt->scsi_status = S_GOOD; |
| pkt->option_flags |= |
| (OF_SSTS | OF_DATA_IN); |
| } else { |
| dprintk(2, |
| "qla1280_atio_entry: SM_RDDB, " |
| "zero length\n"); |
| |
| pkt->scsi_status = S_GOOD; |
| pkt->option_flags |= |
| (OF_SSTS | OF_NO_DATA); |
| } |
| } |
| break; |
| case RW_BUF_DESC: |
| dprintk(3, "qla1280_atio_entry: SM_RDDB, " |
| "RW_BUF_DESC\n"); |
| |
| if (len) { |
| if (len > 4) |
| len = 4; |
| |
| ha->tbuf->hdr[0] = 0; |
| if (pkt->cdb[2] != 0) { |
| ha->tbuf->hdr[1] = 0; |
| ha->tbuf->hdr[2] = 0; |
| ha->tbuf->hdr[3] = 0; |
| } else { |
| ha->tbuf->hdr[1] = |
| (TARGET_DATA_SIZE >> 16) & |
| 0xff; |
| ha->tbuf->hdr[2] = |
| (TARGET_DATA_SIZE >> 8) & |
| 0xff; |
| ha->tbuf->hdr[3] = |
| TARGET_DATA_SIZE & 0xff; |
| } |
| pkt->scsi_status = S_GOOD; |
| pkt->option_flags |= |
| (OF_SSTS | OF_DATA_IN); |
| } else { |
| dprintk(2, |
| "qla1280_atio_entry: SM_RDDB," |
| " zero length\n"); |
| |
| pkt->scsi_status = S_GOOD; |
| pkt->option_flags |= |
| (OF_SSTS | OF_NO_DATA); |
| } |
| break; |
| default: |
| dprintk(2, "qla1280_atio_entry: SM_RDDB " |
| "unknown mode\n"); |
| |
| *sense_ptr = 0x70; |
| *(sense_ptr + 2) = SD_ILLREQ; |
| *(sense_ptr + 7) = TARGET_SENSE_SIZE - 8; |
| *(sense_ptr + 12) = SC_ILLCDB; |
| len = 0; |
| pkt->scsi_status = S_CKCON; |
| pkt->option_flags |= (OF_SSTS | OF_NO_DATA); |
| break; |
| } |
| break; |
| |
| default: |
| dprintk(2, |
| "qla1280_atio_entry: Unknown SCSI command\n"); |
| qla1280_dump_buffer(2, &pkt->cdb[0], pkt->cdb_len); |
| |
| memset(sense_ptr, 0, TARGET_SENSE_SIZE); |
| *sense_ptr = 0x70; |
| *(sense_ptr + 2) = SD_ILLREQ; |
| *(sense_ptr + 7) = TARGET_SENSE_SIZE - 8; |
| *(sense_ptr + 12) = SC_INVOPCODE; |
| len = 0; |
| pkt->scsi_status = S_CKCON; |
| pkt->option_flags |= (OF_SSTS | OF_NO_DATA); |
| break; |
| } |
| #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18) |
| if (ha->flags.enable_64bit_addressing) |
| qla1280_64bit_continue_io(ha, pkt, len, |
| (paddr32_t *)&phy_addr); |
| else |
| #endif |
| qla1280_32bit_continue_io(ha, pkt, len, |
| (paddr32_t *)&phy_addr); |
| break; |
| |
| default: |
| break; |
| } |
| |
| dprintk(3, "qla1280_atio_entry: exiting normally\n"); |
| } |
| |
| /* |
| * qla1280_notify_entry |
| * Processes received ISP immediate notify entry. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * pkt = entry pointer. |
| */ |
| static void |
| qla1280_notify_entry(struct scsi_qla_host *ha, notify_entry_t * pkt) |
| { |
| dprintk(3, "qla1280_notify_entry: entered\n"); |
| |
| /* Acknowledge immediate notify */ |
| qla1280_notify_ack(ha, pkt); |
| |
| /* Issue notify entry to increment resource count */ |
| qla1280_immed_notify(ha, pkt); |
| |
| dprintk(3, "qla1280_notify_entry: exiting normally\n"); |
| } |
| #endif /* QLA1280_TARGET_MODE_SUPPORT */ |
| |
| /* |
| * qla1280_status_entry |
| * Processes received ISP status entry. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * pkt = entry pointer. |
| * done_q_first = done queue first pointer. |
| * done_q_last = done queue last pointer. |
| */ |
| static void |
| qla1280_status_entry(struct scsi_qla_host *ha, sts_entry_t * pkt, |
| srb_t ** done_q_first, srb_t ** done_q_last) |
| { |
| unsigned int bus, target, lun; |
| int sense_sz; |
| srb_t *sp; |
| scsi_lu_t *q; |
| Scsi_Cmnd *cmd; |
| |
| ENTER("qla1280_status_entry"); |
| |
| /* Validate handle. */ |
| if (pkt->handle < MAX_OUTSTANDING_COMMANDS) |
| sp = ha->outstanding_cmds[pkt->handle]; |
| else |
| sp = 0; |
| |
| if (sp) { |
| /* Free outstanding command slot. */ |
| ha->outstanding_cmds[pkt->handle] = 0; |
| |
| cmd = sp->cmd; |
| |
| /* Generate LU queue on cntrl, target, LUN */ |
| bus = SCSI_BUS_32(cmd); |
| target = SCSI_TCN_32(cmd); |
| lun = SCSI_LUN_32(cmd); |
| q = LU_Q(ha, bus, target, lun); |
| |
| if (pkt->comp_status || pkt->scsi_status) { |
| dprintk(1, "scsi: comp_status = 0x%x, scsi_status = " |
| "0x%x, handle = 0x%x\n", pkt->comp_status, |
| pkt->scsi_status, pkt->handle); |
| } |
| |
| /* Target busy */ |
| if (pkt->scsi_status & SS_BUSY_CONDITION && |
| pkt->scsi_status != SS_RESERVE_CONFLICT) { |
| CMD_RESULT(cmd) = |
| DID_BUS_BUSY << 16 | (pkt->scsi_status & 0xff); |
| } else { |
| |
| /* Save ISP completion status */ |
| CMD_RESULT(cmd) = qla1280_return_status(pkt, cmd); |
| |
| if (pkt->scsi_status & SS_CHECK_CONDITION) { |
| if (pkt->comp_status != CS_ARS_FAILED) { |
| if (pkt->req_sense_length < |
| CMD_SNSLEN(cmd)) |
| sense_sz = pkt->req_sense_length; |
| else |
| /* |
| * Scsi_Cmnd->sense_buffer is |
| * 64 bytes, why only copy 63? |
| * This looks wrong! /Jes |
| */ |
| sense_sz = CMD_SNSLEN(cmd) - 1; |
| |
| memcpy(cmd->sense_buffer, |
| &pkt->req_sense_data, sense_sz); |
| } else |
| sense_sz = 0; |
| memset(cmd->sense_buffer + sense_sz, 0, |
| sizeof(cmd->sense_buffer) - sense_sz); |
| |
| dprintk(2, "qla1280_status_entry: Check " |
| "condition Sense data, b %i, t %i, " |
| "l %i\n", bus, target, lun); |
| if (sense_sz) |
| qla1280_dump_buffer(2, (char *)cmd->sense_buffer, |
| sense_sz); |
| } |
| } |
| /* Place command on done queue. */ |
| qla1280_done_q_put(sp, done_q_first, done_q_last); |
| } else { |
| printk(KERN_WARNING "qla1280: Status Entry invalid handle\n"); |
| ha->flags.isp_abort_needed = TRUE; |
| } |
| |
| LEAVE("qla1280_status_entry"); |
| } |
| |
| /* |
| * qla1280_error_entry |
| * Processes error entry. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * pkt = entry pointer. |
| * done_q_first = done queue first pointer. |
| * done_q_last = done queue last pointer. |
| */ |
| static void |
| qla1280_error_entry(struct scsi_qla_host *ha, response_t * pkt, |
| srb_t ** done_q_first, srb_t ** done_q_last) |
| { |
| srb_t *sp; |
| |
| ENTER("qla1280_error_entry"); |
| |
| if (pkt->entry_status & BIT_3) |
| dprintk(2, "qla1280_error_entry: BAD PAYLOAD flag error\n"); |
| else if (pkt->entry_status & BIT_2) |
| dprintk(2, "qla1280_error_entry: BAD HEADER flag error\n"); |
| else if (pkt->entry_status & BIT_1) |
| dprintk(2, "qla1280_error_entry: FULL flag error\n"); |
| else |
| dprintk(2, "qla1280_error_entry: UNKNOWN flag error\n"); |
| |
| /* Validate handle. */ |
| if (pkt->handle < MAX_OUTSTANDING_COMMANDS) |
| sp = ha->outstanding_cmds[pkt->handle]; |
| else |
| sp = 0; |
| |
| if (sp) { |
| /* Free outstanding command slot. */ |
| ha->outstanding_cmds[pkt->handle] = 0; |
| |
| /* Bad payload or header */ |
| if (pkt->entry_status & (BIT_3 + BIT_2)) { |
| /* Bad payload or header, set error status. */ |
| /* CMD_RESULT(sp->cmd) = CS_BAD_PAYLOAD; */ |
| CMD_RESULT(sp->cmd) = DID_ERROR << 16; |
| } else if (pkt->entry_status & BIT_1) { /* FULL flag */ |
| CMD_RESULT(sp->cmd) = DID_BUS_BUSY << 16; |
| } else { |
| /* Set error status. */ |
| CMD_RESULT(sp->cmd) = DID_ERROR << 16; |
| } |
| /* Place command on done queue. */ |
| qla1280_done_q_put(sp, done_q_first, done_q_last); |
| } |
| #ifdef QLA_64BIT_PTR |
| else if (pkt->entry_type == COMMAND_A64_TYPE) { |
| printk(KERN_WARNING "!qla1280: Error Entry invalid handle"); |
| ha->flags.isp_abort_needed = TRUE; |
| } |
| #endif |
| |
| LEAVE("qla1280_error_entry"); |
| } |
| |
| /* |
| * qla1280_abort_isp |
| * Resets ISP and aborts all outstanding commands. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| * |
| * Returns: |
| * 0 = success |
| */ |
| static int |
| qla1280_abort_isp(struct scsi_qla_host *ha) |
| { |
| #if 0 |
| struct device_reg *reg = ha->iobase; |
| #endif |
| srb_t *sp; |
| scsi_lu_t *q; |
| int status = 0; |
| int cnt; |
| int bus, target, lun; |
| |
| ENTER("qla1280_abort_isp"); |
| |
| ha->flags.isp_abort_needed = FALSE; |
| if (!ha->flags.abort_isp_active && ha->flags.online) { |
| ha->flags.abort_isp_active = TRUE; |
| |
| /* Disable ISP interrupts. */ |
| qla1280_disable_intrs(ha); |
| |
| /* Dequeue all commands in outstanding command list. */ |
| for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { |
| sp = ha->outstanding_cmds[cnt]; |
| if (sp) { |
| ha->outstanding_cmds[cnt] = 0; |
| |
| /* Generate LU queue on controller, target, LUN */ |
| bus = SCSI_BUS_32(sp->cmd); |
| target = SCSI_TCN_32(sp->cmd); |
| lun = SCSI_LUN_32(sp->cmd); |
| |
| q = LU_Q(ha, bus, target, lun); |
| |
| /* Reset outstanding command count. */ |
| q->q_outcnt = 0; |
| q->q_flag &= ~QLA1280_QBUSY; |
| q->q_flag = 0; |
| |
| /* Adjust watchdog timer for command. */ |
| /* if (sp->flags & SRB_WATCHDOG) |
| sp->timeout += 2; */ |
| |
| /* Place request back on top of device queue. */ |
| sp->flags = 0; |
| qla1280_putq_t(q, sp); |
| } |
| } |
| |
| /* If firmware needs to be loaded */ |
| if (qla1280_isp_firmware (ha)) { |
| if (!(status = qla1280_chip_diag(ha))) |
| status = qla1280_setup_chip(ha); |
| } |
| |
| if (!status) { |
| /* Setup adapter based on NVRAM parameters. */ |
| qla1280_nvram_config (ha); |
| |
| if (!(status = qla1280_init_rings(ha))) { |
| /* Issue SCSI reset. */ |
| for (bus = 0; bus < ha->ports; bus++) { |
| qla1280_bus_reset(ha, bus); |
| } |
| do { |
| /* Issue marker command. */ |
| ha->flags.reset_marker = FALSE; |
| for (bus = 0; bus < ha->ports; bus++) { |
| ha->bus_settings[bus]. |
| reset_marker = FALSE; |
| qla1280_marker(ha, bus, 0, 0, |
| MK_SYNC_ALL); |
| } |
| } while (ha->flags.reset_marker); |
| |
| /* Enable host adapter target mode. */ |
| for (bus = 0; bus < ha->ports; bus++) { |
| if (! |
| (status = |
| qla1280_enable_tgt(ha, bus))) { |
| for (cnt = 0; cnt < MAX_LUNS; |
| cnt++) { |
| /* qla1280_enable_lun(ha, bus, cnt); */ |
| qla1280_poll(ha); |
| } |
| } else |
| break; |
| } |
| |
| if (!status) { |
| /* Enable ISP interrupts. */ |
| qla1280_enable_intrs(ha); |
| ha->flags.abort_isp_active = FALSE; |
| /* Restart queues that may have been stopped. */ |
| qla1280_restart_queues(ha); |
| } |
| } |
| } |
| } |
| |
| if (status) { |
| printk(KERN_WARNING |
| "qla1280: ISP error recovery failed, board disabled"); |
| qla1280_reset_adapter(ha); |
| qla1280_abort_queues(ha); |
| |
| dprintk(2, "qla1280_abort_isp: **** FAILED ****\n"); |
| } |
| |
| LEAVE("qla1280_abort_isp"); |
| return status; |
| } |
| |
| /* |
| * qla1280_restart_queues |
| * Restart all device queues. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| */ |
| static void |
| qla1280_restart_queues(struct scsi_qla_host *ha) |
| { |
| scsi_lu_t *q; |
| int bus, target, lun; |
| |
| ENTER("qla1280_restart_queues"); |
| |
| for (bus = 0; bus < ha->ports; bus++) |
| for (target = 0; target < MAX_TARGETS; target++) |
| for (lun = 0; lun < MAX_LUNS; lun++) { |
| q = LU_Q(ha, bus, target, lun); |
| if (q != NULL) { |
| if (q->q_first) |
| qla1280_next(ha, q, bus); |
| } |
| } |
| dprintk(3, "qla1280_restart_queues: exiting normally\n"); |
| } |
| |
| /* |
| * qla1280_abort_queue_single |
| * Abort all commands on a device queues. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| */ |
| static void |
| qla1280_abort_queue_single(struct scsi_qla_host *ha, int bus, |
| int target, int lun, uint32_t stat) |
| { |
| scsi_lu_t *q; |
| srb_t *sp, *sp_next; |
| |
| ENTER("qla1280_abort_queue_single"); |
| q = LU_Q(ha, bus, target, lun); |
| if (q != NULL) { |
| sp = q->q_first; |
| q->q_first = q->q_last = NULL; |
| |
| while (sp) { |
| sp_next = sp->s_next; |
| CMD_RESULT(sp->cmd) = stat; |
| qla1280_done_q_put(sp, &ha->done_q_first, |
| &ha->done_q_last); |
| sp = sp_next; |
| } |
| } |
| LEAVE("qla1280_abort_queue_single"); |
| } |
| |
| /* |
| * qla1280_abort_queues |
| * Abort all commands on device queues. |
| * |
| * Input: |
| * ha = adapter block pointer. |
| */ |
| static void |
| qla1280_abort_queues(struct scsi_qla_host *ha) |
| { |
| uint32_t bus, target, lun; |
| |
| ENTER("qla1280_abort_queues"); |
| |
| for (bus = 0; bus < ha->ports; bus++) |
| for (target = 0; target < MAX_TARGETS; target++) |
| for (lun = 0; lun < MAX_LUNS; lun++) |
| qla1280_abort_queue_single(ha, bus, target, |
| lun, DID_RESET); |
| |
| LEAVE("qla1280_abort_queues"); |
| } |
| |
| /* |
| * qla1280_debounce_register |
| * Debounce register. |
| * |
| * Input: |
| * port = register address. |
| * |
| * Returns: |
| * register value. |
| */ |
| static u16 |
| qla1280_debounce_register(volatile u16 * addr) |
| { |
| volatile u16 ret; |
| volatile u16 ret2; |
| |
| ret = RD_REG_WORD(addr); |
| ret2 = RD_REG_WORD(addr); |
| |
| if (ret == ret2) |
| return ret; |
| |
| do { |
| cpu_relax(); |
| ret = RD_REG_WORD(addr); |
| ret2 = RD_REG_WORD(addr); |
| } while (ret != ret2); |
| |
| return ret; |
| } |
| |
| #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) |
| #ifdef MODULE |
| Scsi_Host_Template driver_template = QLA1280_LINUX_TEMPLATE; |
| #include "scsi_module.c" |
| #endif |
| #else /* new kernel scsi initialization scheme */ |
| static Scsi_Host_Template driver_template = QLA1280_LINUX_TEMPLATE; |
| #include "scsi_module.c" |
| #endif |
| |
| /************************************************************************ |
| * qla1280_check_for_dead_scsi_bus * |
| * * |
| * This routine checks for a dead SCSI bus * |
| ************************************************************************/ |
| #define SET_SXP_BANK 0x0100 |
| #define SCSI_PHASE_INVALID 0x87FF |
| static int |
| qla1280_check_for_dead_scsi_bus(struct scsi_qla_host *ha, unsigned int bus) |
| { |
| uint16_t config_reg, scsi_control; |
| struct device_reg *reg = ha->iobase; |
| #if 0 |
| unsigned int bus; |
| Scsi_Cmnd *cp; |
| |
| /* |
| * If SCSI Bus is Dead because of bad termination, |
| * we will return a status of Selection timeout. |
| */ |
| |
| cp = sp->cmd; |
| bus = SCSI_BUS_32(cp); |
| #endif |
| if (ha->bus_settings[bus].scsi_bus_dead) { |
| WRT_REG_WORD(®->host_cmd, HC_PAUSE_RISC); |
| config_reg = RD_REG_WORD(®->cfg_1); |
| WRT_REG_WORD(®->cfg_1, SET_SXP_BANK); |
| scsi_control = RD_REG_WORD(®->scsiControlPins); |
| WRT_REG_WORD(®->cfg_1, config_reg); |
| WRT_REG_WORD(®->host_cmd, HC_RELEASE_RISC); |
| |
| if (scsi_control == SCSI_PHASE_INVALID) { |
| ha->bus_settings[bus].scsi_bus_dead = TRUE; |
| #if 0 |
| CMD_RESULT(cp) = DID_NO_CONNECT << 16; |
| CMD_HANDLE(cp) = NULL; |
| /* ha->actthreads--; */ |
| |
| (*(cp)->scsi_done)(cp); |
| #endif |
| return TRUE; /* bus is dead */ |
| } else { |
| ha->bus_settings[bus].scsi_bus_dead = FALSE; |
| ha->bus_settings[bus].failed_reset_count = 0; |
| } |
| } |
| return FALSE; /* bus is not dead */ |
| } |
| |
| static void |
| qla12160_get_target_parameters(struct scsi_qla_host *ha, uint32_t bus, |
| uint32_t target, uint32_t lun) |
| { |
| uint16_t mb[MAILBOX_REGISTER_COUNT]; |
| |
| mb[0] = MBC_GET_TARGET_PARAMETERS; |
| mb[1] = (uint16_t) (bus ? target | BIT_7 : target); |
| mb[1] <<= 8; |
| qla1280_mailbox_command(ha, BIT_6 | BIT_3 | BIT_2 | BIT_1 | BIT_0, |
| &mb[0]); |
| if (mb[3] != 0) { |
| printk(KERN_INFO |
| "scsi(%ld:%d:%d:%d): Synchronous transfer at period " |
| "%d, offset %d. \n", ha->host_no, bus, target, lun, |
| (mb[3] & 0xff), (mb[3] >> 8)); |
| } |
| |
| if ((mb[2] & BIT_5) && ((mb[6] >> 8) & 0xff) >= 2) { |
| printk(KERN_INFO |
| "scsi(%ld:%d:%d:%d): Dual Transition enabled.\n", |
| ha->host_no, bus, target, lun); |
| } |
| } |
| |
| #ifdef QL_DEBUG_ROUTINES |
| /****************************************************************************/ |
| /* Driver Debug Functions. */ |
| /****************************************************************************/ |
| |
| /* |
| * Get byte from I/O port |
| */ |
| static u8 |
| qla1280_getbyte (u8 * port) |
| { |
| u8 ret; |
| |
| #if MEMORY_MAPPED_IO |
| ret = readb((unsigned long) port); |
| #else |
| ret = inb((unsigned long) port); |
| #endif |
| |
| if (ql_debug_print) |
| printk(KERN_DEBUG |
| "qla1280_getbyte: address = 0x%p, data = 0x%x", port, |
| ret); |
| |
| return ret; |
| } |
| |
| /* |
| * Get word from I/O port |
| */ |
| static u16 |
| qla1280_getword (u16 * port) |
| { |
| u16 ret; |
| |
| #if MEMORY_MAPPED_IO |
| ret = readw(unsigned long) port; |
| #else |
| ret = inw((unsigned long) port); |
| #endif |
| |
| if (ql_debug_print) |
| printk(KERN_DEBUG |
| "qla1280_getbyte: address = 0x%p, data = 0x%x", port, |
| ret); |
| |
| return ret; |
| } |
| |
| /* |
| * Get double word from I/O port |
| */ |
| static u32 |
| qla1280_getdword (u32 * port) |
| { |
| u32 ret; |
| |
| #if MEMORY_MAPPED_IO |
| ret = readl((unsigned long) port); |
| #else |
| ret = inl((unsigned long) port); |
| #endif |
| |
| if (ql_debug_print) |
| printk(KERN_DEBUG |
| "qla1280_getbyte: address = 0x%p, data = 0x%x", port, |
| ret); |
| |
| return ret; |
| } |
| |
| /* |
| * Send byte to I/O port |
| */ |
| static void |
| qla1280_putbyte(u8 * port, u8 data) |
| { |
| #if MEMORY_MAPPED_IO |
| writeb(data, (unsigned long) port); |
| #else |
| outb(data, (unsigned long) port); |
| #endif |
| |
| if (ql_debug_print) |
| printk(KERN_DEBUG |
| "qla1280_getbyte: address = 0x%p, data = 0x%x", port, |
| data); |
| } |
| |
| /* |
| * Send word to I/O port |
| */ |
| static void |
| qla1280_putword(u16 * port, u16 data) |
| { |
| #if MEMORY_MAPPED_IO |
| writew(data, (unsigned long) port); |
| #else |
| outw(data, (unsigned long) port); |
| #endif |
| |
| if (ql_debug_print) |
| printk(KERN_DEBUG |
| "qla1280_getbyte: address = 0x%p, data = 0x%x", port, |
| data); |
| } |
| |
| /* |
| * Send double word to I/O port |
| */ |
| static void |
| qla1280_putdword(u32 * port, u32 data) |
| { |
| #if MEMORY_MAPPED_IO |
| writel(data, (unsigned long) port); |
| #else |
| outl(data, (unsigned long) port); |
| #endif |
| |
| if (ql_debug_print) |
| printk(KERN_DEBUG |
| "qla1280_getbyte: address = 0x%p, data = 0x%x", port, |
| data); |
| } |
| |
| /* |
| * Dummy function to prevent warnings for |
| * declared and unused debug functions |
| */ |
| static void |
| qla1280_debug(void) |
| { |
| qla1280_getbyte(0); |
| qla1280_getword(0); |
| qla1280_getdword(0); |
| qla1280_putbyte(0, 0); |
| qla1280_putword(0, 0); |
| qla1280_putdword(0, 0); |
| } |
| |
| static void |
| __qla1280_dump_buffer(char *b, int size) |
| { |
| int cnt; |
| u8 c; |
| |
| if (ql_debug_print) { |
| printk(KERN_DEBUG |
| " 0 1 2 3 4 5 6 7 8 9 Ah " |
| "Bh Ch Dh Eh Fh\n"); |
| printk(KERN_DEBUG |
| "---------------------------------------------" |
| "------------------\n"); |
| |
| for (cnt = 0; cnt < size;) { |
| c = *b++; |
| if (c < 16) |
| printk(' '); |
| printk("0x%x", c); |
| cnt++; |
| if (!(cnt % 16)) |
| printk("\n"); |
| else if (c < 10) |
| printk(" "); |
| else |
| printk(' '); |
| } |
| if (cnt % 16) |
| printk("\n"); |
| } |
| } |
| |
| /************************************************************************** |
| * ql1280_print_scsi_cmd |
| * |
| **************************************************************************/ |
| static void |
| qla1280_print_scsi_cmd(Scsi_Cmnd * cmd) |
| { |
| struct scsi_qla_host *ha; |
| struct Scsi_Host *host = cmd->host; |
| srb_t *sp; |
| /* struct scatterlist *sg; */ |
| |
| int i; |
| ha = (struct scsi_qla_host *)host->hostdata; |
| |
| sp = (srb_t *)CMD_SP(cmd); |
| printk("SCSI Command @= 0x%p, Handle=0x%p\n", cmd, CMD_HANDLE(cmd)); |
| printk(" chan=%d, target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n", |
| cmd->channel, cmd->target, cmd->lun, cmd->cmd_len); |
| printk(" CDB = "); |
| for (i = 0; i < cmd->cmd_len; i++) { |
| printk("0x%02x ", cmd->cmnd[i]); |
| } |
| printk(" seg_cnt =%d\n", cmd->use_sg); |
| printk(" request buffer=0x%p, request buffer len=0x%x\n", |
| cmd->request_buffer, cmd->request_bufflen); |
| /* if (cmd->use_sg) |
| { |
| sg = (struct scatterlist *) cmd->request_buffer; |
| printk(" SG buffer: \n"); |
| qla1280_dump_buffer(1, (char *)sg, (cmd->use_sg*sizeof(struct scatterlist))); |
| } */ |
| printk(" tag=%d, flags=0x%x, transfersize=0x%x \n", |
| cmd->tag, cmd->flags, cmd->transfersize); |
| printk(" Pid=%li, SP=0x%p\n", cmd->pid, CMD_SP(cmd)); |
| printk(" underflow size = 0x%x, direction=0x%x, req.cmd=0x%x \n", |
| cmd->underflow, sp->dir, cmd->request->cmd); |
| } |
| |
| /************************************************************************** |
| * ql1280_dump_device |
| * |
| **************************************************************************/ |
| void |
| ql1280_dump_device(struct scsi_qla_host *ha) |
| { |
| |
| Scsi_Cmnd *cp; |
| srb_t *sp; |
| int i; |
| if (ql_debug_print) { |
| printk(KERN_DEBUG "Outstanding Commands on controller:\n"); |
| |
| for (i = 0; i < MAX_OUTSTANDING_COMMANDS; i++) { |
| if ((sp = ha->outstanding_cmds[i]) == NULL) |
| continue; |
| if ((cp = sp->cmd) == NULL) |
| continue; |
| qla1280_print_scsi_cmd(1, cp); |
| } |
| } |
| } |
| #endif |
| |
| #if STOP_ON_ERROR |
| /************************************************************************** |
| * ql1280_panic |
| * |
| **************************************************************************/ |
| static void |
| qla1280_panic(char *cp, struct Scsi_Host *host) |
| { |
| struct scsi_qla_host *ha; |
| long *fp; |
| |
| ha = (struct scsi_qla_host *)host->hostdata; |
| printk(KERN_ERR "qla1280 - PANIC: %s\n", cp); |
| printk(KERN_ERR "Current time=0x%lx\n", jiffies); |
| printk(KERN_ERR "Number of pending commands =0x%lx\n", ha->actthreads); |
| printk(KERN_ERR "Number of SCSI queued commands =0x%lx\n", |
| ha->qthreads); |
| printk(KERN_ERR "Number of free entries = (%d)\n", ha->req_q_cnt); |
| printk(KERN_ERR "Request Queue @ 0x%lx, Response Queue @ 0x%lx\n", |
| ha->request_dma, ha->response_dma); |
| printk(KERN_ERR "Request In Ptr %d\n", ha->req_ring_index); |
| fp = (long *) &ha->flags; |
| printk(KERN_ERR "HA flags =0x%lx\n", *fp); |
| if (ql_debug_level >= 2) { |
| ql_debug_print = 1; |
| #if 0 |
| ql1280_dump_device((struct scsi_qla_host *)host->hostdata); |
| #endif |
| } |
| sti(); |
| panic("Ooops"); |
| /* cli(); |
| for(;;) |
| { |
| barrier(); |
| sti(); |
| } |
| */ |
| } |
| #endif |
| |
| #ifdef MODULE |
| /************************************************************************** |
| * qla1280_setup |
| * |
| * Handle Linux boot parameters. This routine allows for assigning a value |
| * to a parameter with a ':' between the parameter and the value. |
| * ie. qla1280=max_reqs:0x0A,verbose |
| **************************************************************************/ |
| void |
| qla1280_setup(char *s, int *dummy) |
| { |
| char *end, *str, *cp; |
| |
| printk(KERN_INFO "scsi: Processing Option str = %s\n", s); |
| end = strchr (s, '\0'); |
| /* locate command */ |
| str = s; |
| for (cp = s; *cp && cp != end; cp++) { |
| cp = qla1280_get_token(cp, str); |
| printk(KERN_INFO "scsi: token str = %s\n", str); |
| /* if found execute routine */ |
| } |
| } |
| |
| static char * |
| qla1280_get_token(char *cmdline, char *str) |
| { |
| register char *cp = cmdline; |
| |
| /* skip preceeding spaces */ |
| while (strchr (cp, ' ')) |
| ++cp; |
| /* symbol starts here */ |
| str = cp; |
| /* skip char if not a space or : */ |
| while (*cp && !(strchr (cp, ' ') || strchr (cp, ':'))) |
| cp++; |
| *cp = '\0'; |
| return cp; |
| } |
| #endif |
| |
| /* |
| * Overrides for Emacs so that we almost follow Linus's tabbing style. |
| * Emacs will notice this stuff at the end of the file and automatically |
| * adjust the settings for this buffer only. This must remain at the end |
| * of the file. |
| * --------------------------------------------------------------------------- |
| * Local variables: |
| * c-basic-offset: 8 |
| * tab-width: 8 |
| * End: |
| */ |