diff options
Diffstat (limited to 'drivers/scsi/qlogicfc.c')
-rw-r--r-- | drivers/scsi/qlogicfc.c | 2228 |
1 files changed, 0 insertions, 2228 deletions
diff --git a/drivers/scsi/qlogicfc.c b/drivers/scsi/qlogicfc.c deleted file mode 100644 index 52b224a5d6f..00000000000 --- a/drivers/scsi/qlogicfc.c +++ /dev/null @@ -1,2228 +0,0 @@ -/* - * QLogic ISP2x00 SCSI-FCP - * Written by Erik H. Moe, ehm@cris.com - * Copyright 1995, Erik H. Moe - * - * 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. - */ - -/* Renamed and updated to 1.3.x by Michael Griffith <grif@cs.ucr.edu> */ - -/* This is a version of the isp1020 driver which was modified by - * Chris Loveland <cwl@iol.unh.edu> to support the isp2100 and isp2200 - * - * Big endian support and dynamic DMA mapping added - * by Jakub Jelinek <jakub@redhat.com>. - * - * Conversion to final pci64 DMA interfaces - * by David S. Miller <davem@redhat.com>. - */ - -/* - * $Date: 1995/09/22 02:23:15 $ - * $Revision: 0.5 $ - * - * $Log: isp1020.c,v $ - * Revision 0.5 1995/09/22 02:23:15 root - * do auto request sense - * - * Revision 0.4 1995/08/07 04:44:33 root - * supply firmware with driver. - * numerous bug fixes/general cleanup of code. - * - * Revision 0.3 1995/07/16 16:15:39 root - * added reset/abort code. - * - * Revision 0.2 1995/06/29 03:14:19 root - * fixed biosparam. - * added queue protocol. - * - * Revision 0.1 1995/06/25 01:55:45 root - * Initial release. - * - */ - -#include <linux/blkdev.h> -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/ioport.h> -#include <linux/sched.h> -#include <linux/types.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/unistd.h> -#include <linux/spinlock.h> -#include <linux/interrupt.h> -#include <linux/dma-mapping.h> -#include <linux/jiffies.h> -#include <asm/io.h> -#include <asm/irq.h> -#include "scsi.h" -#include <scsi/scsi_host.h> - -#define pci64_dma_hi32(a) ((u32) (0xffffffff & (((u64)(a))>>32))) -#define pci64_dma_lo32(a) ((u32) (0xffffffff & (((u64)(a))))) -#define pci64_dma_build(hi,lo) \ - ((dma_addr_t)(((u64)(lo))|(((u64)(hi))<<32))) - -/* - * With the qlogic interface, every queue slot can hold a SCSI - * command with up to 2 scatter/gather entries. If we need more - * than 2 entries, continuation entries can be used that hold - * another 5 entries each. Unlike for other drivers, this means - * that the maximum number of scatter/gather entries we can - * support at any given time is a function of the number of queue - * slots available. That is, host->can_queue and host->sg_tablesize - * are dynamic and _not_ independent. This all works fine because - * requests are queued serially and the scatter/gather limit is - * determined for each queue request anew. - */ - -#define DATASEGS_PER_COMMAND 2 -#define DATASEGS_PER_CONT 5 - -#define QLOGICFC_REQ_QUEUE_LEN 255 /* must be power of two - 1 */ -#define QLOGICFC_MAX_SG(ql) (DATASEGS_PER_COMMAND + (((ql) > 0) ? DATASEGS_PER_CONT*((ql) - 1) : 0)) -#define QLOGICFC_CMD_PER_LUN 8 - -/* Configuration section **************************************************** */ - -/* Set the following macro to 1 to reload the ISP2x00's firmware. This is - version 1.17.30 of the isp2100's firmware and version 2.00.40 of the - isp2200's firmware. -*/ - -#define USE_NVRAM_DEFAULTS 1 - -#define ISP2x00_PORTDB 1 - -/* Set the following to 1 to include fabric support, fabric support is - * currently not as well tested as the other aspects of the driver */ - -#define ISP2x00_FABRIC 1 - -/* Macros used for debugging */ -#define DEBUG_ISP2x00 0 -#define DEBUG_ISP2x00_INT 0 -#define DEBUG_ISP2x00_INTR 0 -#define DEBUG_ISP2x00_SETUP 0 -#define DEBUG_ISP2x00_FABRIC 0 -#define TRACE_ISP 0 - - -#define DEFAULT_LOOP_COUNT 1000000000 - -#define ISP_TIMEOUT (2*HZ) -/* End Configuration section ************************************************ */ - -#include <linux/module.h> - -#if TRACE_ISP - -#define TRACE_BUF_LEN (32*1024) - -struct { - u_long next; - struct { - u_long time; - u_int index; - u_int addr; - u_char *name; - } buf[TRACE_BUF_LEN]; -} trace; - -#define TRACE(w, i, a) \ -{ \ - unsigned long flags; \ - \ - save_flags(flags); \ - cli(); \ - trace.buf[trace.next].name = (w); \ - trace.buf[trace.next].time = jiffies; \ - trace.buf[trace.next].index = (i); \ - trace.buf[trace.next].addr = (long) (a); \ - trace.next = (trace.next + 1) & (TRACE_BUF_LEN - 1); \ - restore_flags(flags); \ -} - -#else -#define TRACE(w, i, a) -#endif - -#if DEBUG_ISP2x00_FABRIC -#define DEBUG_FABRIC(x) x -#else -#define DEBUG_FABRIC(x) -#endif /* DEBUG_ISP2x00_FABRIC */ - - -#if DEBUG_ISP2x00 -#define ENTER(x) printk("isp2x00 : entering %s()\n", x); -#define LEAVE(x) printk("isp2x00 : leaving %s()\n", x); -#define DEBUG(x) x -#else -#define ENTER(x) -#define LEAVE(x) -#define DEBUG(x) -#endif /* DEBUG_ISP2x00 */ - -#if DEBUG_ISP2x00_INTR -#define ENTER_INTR(x) printk("isp2x00 : entering %s()\n", x); -#define LEAVE_INTR(x) printk("isp2x00 : leaving %s()\n", x); -#define DEBUG_INTR(x) x -#else -#define ENTER_INTR(x) -#define LEAVE_INTR(x) -#define DEBUG_INTR(x) -#endif /* DEBUG ISP2x00_INTR */ - - -#define ISP2100_REV_ID1 1 -#define ISP2100_REV_ID3 3 -#define ISP2200_REV_ID5 5 - -/* host configuration and control registers */ -#define HOST_HCCR 0xc0 /* host command and control */ - -/* pci bus interface registers */ -#define FLASH_BIOS_ADDR 0x00 -#define FLASH_BIOS_DATA 0x02 -#define ISP_CTRL_STATUS 0x06 /* configuration register #1 */ -#define PCI_INTER_CTL 0x08 /* pci interrupt control */ -#define PCI_INTER_STS 0x0a /* pci interrupt status */ -#define PCI_SEMAPHORE 0x0c /* pci semaphore */ -#define PCI_NVRAM 0x0e /* pci nvram interface */ - -/* mailbox registers */ -#define MBOX0 0x10 /* mailbox 0 */ -#define MBOX1 0x12 /* mailbox 1 */ -#define MBOX2 0x14 /* mailbox 2 */ -#define MBOX3 0x16 /* mailbox 3 */ -#define MBOX4 0x18 /* mailbox 4 */ -#define MBOX5 0x1a /* mailbox 5 */ -#define MBOX6 0x1c /* mailbox 6 */ -#define MBOX7 0x1e /* mailbox 7 */ - -/* mailbox command complete status codes */ -#define MBOX_COMMAND_COMPLETE 0x4000 -#define INVALID_COMMAND 0x4001 -#define HOST_INTERFACE_ERROR 0x4002 -#define TEST_FAILED 0x4003 -#define COMMAND_ERROR 0x4005 -#define COMMAND_PARAM_ERROR 0x4006 -#define PORT_ID_USED 0x4007 -#define LOOP_ID_USED 0x4008 -#define ALL_IDS_USED 0x4009 - -/* async event status codes */ -#define RESET_DETECTED 0x8001 -#define SYSTEM_ERROR 0x8002 -#define REQUEST_TRANSFER_ERROR 0x8003 -#define RESPONSE_TRANSFER_ERROR 0x8004 -#define REQUEST_QUEUE_WAKEUP 0x8005 -#define LIP_OCCURRED 0x8010 -#define LOOP_UP 0x8011 -#define LOOP_DOWN 0x8012 -#define LIP_RECEIVED 0x8013 -#define PORT_DB_CHANGED 0x8014 -#define CHANGE_NOTIFICATION 0x8015 -#define SCSI_COMMAND_COMPLETE 0x8020 -#define POINT_TO_POINT_UP 0x8030 -#define CONNECTION_MODE 0x8036 - -struct Entry_header { - u_char entry_type; - u_char entry_cnt; - u_char sys_def_1; - u_char flags; -}; - -/* entry header type commands */ -#define ENTRY_COMMAND 0x19 -#define ENTRY_CONTINUATION 0x0a - -#define ENTRY_STATUS 0x03 -#define ENTRY_MARKER 0x04 - - -/* entry header flag definitions */ -#define EFLAG_BUSY 2 -#define EFLAG_BAD_HEADER 4 -#define EFLAG_BAD_PAYLOAD 8 - -struct dataseg { - u_int d_base; - u_int d_base_hi; - u_int d_count; -}; - -struct Command_Entry { - struct Entry_header hdr; - u_int handle; - u_char target_lun; - u_char target_id; - u_short expanded_lun; - u_short control_flags; - u_short rsvd2; - u_short time_out; - u_short segment_cnt; - u_char cdb[16]; - u_int total_byte_cnt; - struct dataseg dataseg[DATASEGS_PER_COMMAND]; -}; - -/* command entry control flag definitions */ -#define CFLAG_NODISC 0x01 -#define CFLAG_HEAD_TAG 0x02 -#define CFLAG_ORDERED_TAG 0x04 -#define CFLAG_SIMPLE_TAG 0x08 -#define CFLAG_TAR_RTN 0x10 -#define CFLAG_READ 0x20 -#define CFLAG_WRITE 0x40 - -struct Continuation_Entry { - struct Entry_header hdr; - struct dataseg dataseg[DATASEGS_PER_CONT]; -}; - -struct Marker_Entry { - struct Entry_header hdr; - u_int reserved; - u_char target_lun; - u_char target_id; - u_char modifier; - u_char expanded_lun; - u_char rsvds[52]; -}; - -/* marker entry modifier definitions */ -#define SYNC_DEVICE 0 -#define SYNC_TARGET 1 -#define SYNC_ALL 2 - -struct Status_Entry { - struct Entry_header hdr; - u_int handle; - u_short scsi_status; - u_short completion_status; - u_short state_flags; - u_short status_flags; - u_short res_info_len; - u_short req_sense_len; - u_int residual; - u_char res_info[8]; - u_char req_sense_data[32]; -}; - -/* status entry completion status definitions */ -#define CS_COMPLETE 0x0000 -#define CS_DMA_ERROR 0x0002 -#define CS_RESET_OCCURRED 0x0004 -#define CS_ABORTED 0x0005 -#define CS_TIMEOUT 0x0006 -#define CS_DATA_OVERRUN 0x0007 -#define CS_DATA_UNDERRUN 0x0015 -#define CS_QUEUE_FULL 0x001c -#define CS_PORT_UNAVAILABLE 0x0028 -#define CS_PORT_LOGGED_OUT 0x0029 -#define CS_PORT_CONFIG_CHANGED 0x002a - -/* status entry state flag definitions */ -#define SF_SENT_CDB 0x0400 -#define SF_TRANSFERRED_DATA 0x0800 -#define SF_GOT_STATUS 0x1000 - -/* status entry status flag definitions */ -#define STF_BUS_RESET 0x0008 -#define STF_DEVICE_RESET 0x0010 -#define STF_ABORTED 0x0020 -#define STF_TIMEOUT 0x0040 - -/* interrupt control commands */ -#define ISP_EN_INT 0x8000 -#define ISP_EN_RISC 0x0008 - -/* host control commands */ -#define HCCR_NOP 0x0000 -#define HCCR_RESET 0x1000 -#define HCCR_PAUSE 0x2000 -#define HCCR_RELEASE 0x3000 -#define HCCR_SINGLE_STEP 0x4000 -#define HCCR_SET_HOST_INTR 0x5000 -#define HCCR_CLEAR_HOST_INTR 0x6000 -#define HCCR_CLEAR_RISC_INTR 0x7000 -#define HCCR_BP_ENABLE 0x8000 -#define HCCR_BIOS_DISABLE 0x9000 -#define HCCR_TEST_MODE 0xf000 - -#define RISC_BUSY 0x0004 - -/* mailbox commands */ -#define MBOX_NO_OP 0x0000 -#define MBOX_LOAD_RAM 0x0001 -#define MBOX_EXEC_FIRMWARE 0x0002 -#define MBOX_DUMP_RAM 0x0003 -#define MBOX_WRITE_RAM_WORD 0x0004 -#define MBOX_READ_RAM_WORD 0x0005 -#define MBOX_MAILBOX_REG_TEST 0x0006 -#define MBOX_VERIFY_CHECKSUM 0x0007 -#define MBOX_ABOUT_FIRMWARE 0x0008 -#define MBOX_LOAD_RISC_RAM 0x0009 -#define MBOX_DUMP_RISC_RAM 0x000a -#define MBOX_CHECK_FIRMWARE 0x000e -#define MBOX_INIT_REQ_QUEUE 0x0010 -#define MBOX_INIT_RES_QUEUE 0x0011 -#define MBOX_EXECUTE_IOCB 0x0012 -#define MBOX_WAKE_UP 0x0013 -#define MBOX_STOP_FIRMWARE 0x0014 -#define MBOX_ABORT_IOCB 0x0015 -#define MBOX_ABORT_DEVICE 0x0016 -#define MBOX_ABORT_TARGET 0x0017 -#define MBOX_BUS_RESET 0x0018 -#define MBOX_STOP_QUEUE 0x0019 -#define MBOX_START_QUEUE 0x001a -#define MBOX_SINGLE_STEP_QUEUE 0x001b -#define MBOX_ABORT_QUEUE 0x001c -#define MBOX_GET_DEV_QUEUE_STATUS 0x001d -#define MBOX_GET_FIRMWARE_STATUS 0x001f -#define MBOX_GET_INIT_SCSI_ID 0x0020 -#define MBOX_GET_RETRY_COUNT 0x0022 -#define MBOX_GET_TARGET_PARAMS 0x0028 -#define MBOX_GET_DEV_QUEUE_PARAMS 0x0029 -#define MBOX_SET_RETRY_COUNT 0x0032 -#define MBOX_SET_TARGET_PARAMS 0x0038 -#define MBOX_SET_DEV_QUEUE_PARAMS 0x0039 -#define MBOX_EXECUTE_IOCB64 0x0054 -#define MBOX_INIT_FIRMWARE 0x0060 -#define MBOX_GET_INIT_CB 0x0061 -#define MBOX_INIT_LIP 0x0062 -#define MBOX_GET_POS_MAP 0x0063 -#define MBOX_GET_PORT_DB 0x0064 -#define MBOX_CLEAR_ACA 0x0065 -#define MBOX_TARGET_RESET 0x0066 -#define MBOX_CLEAR_TASK_SET 0x0067 -#define MBOX_ABORT_TASK_SET 0x0068 -#define MBOX_GET_FIRMWARE_STATE 0x0069 -#define MBOX_GET_PORT_NAME 0x006a -#define MBOX_SEND_SNS 0x006e -#define MBOX_PORT_LOGIN 0x006f -#define MBOX_SEND_CHANGE_REQUEST 0x0070 -#define MBOX_PORT_LOGOUT 0x0071 - -/* - * Firmware if needed (note this is a hack, it belongs in a separate - * module. - */ - -#ifdef CONFIG_SCSI_QLOGIC_FC_FIRMWARE -#include "qlogicfc_asm.c" -#else -static unsigned short risc_code_addr01 = 0x1000 ; -#endif - -/* Each element in mbox_param is an 8 bit bitmap where each bit indicates - if that mbox should be copied as input. For example 0x2 would mean - only copy mbox1. */ - -static const u_char mbox_param[] = -{ - 0x01, /* MBOX_NO_OP */ - 0x1f, /* MBOX_LOAD_RAM */ - 0x03, /* MBOX_EXEC_FIRMWARE */ - 0x1f, /* MBOX_DUMP_RAM */ - 0x07, /* MBOX_WRITE_RAM_WORD */ - 0x03, /* MBOX_READ_RAM_WORD */ - 0xff, /* MBOX_MAILBOX_REG_TEST */ - 0x03, /* MBOX_VERIFY_CHECKSUM */ - 0x01, /* MBOX_ABOUT_FIRMWARE */ - 0xff, /* MBOX_LOAD_RISC_RAM */ - 0xff, /* MBOX_DUMP_RISC_RAM */ - 0x00, /* 0x000b */ - 0x00, /* 0x000c */ - 0x00, /* 0x000d */ - 0x01, /* MBOX_CHECK_FIRMWARE */ - 0x00, /* 0x000f */ - 0x1f, /* MBOX_INIT_REQ_QUEUE */ - 0x2f, /* MBOX_INIT_RES_QUEUE */ - 0x0f, /* MBOX_EXECUTE_IOCB */ - 0x03, /* MBOX_WAKE_UP */ - 0x01, /* MBOX_STOP_FIRMWARE */ - 0x0f, /* MBOX_ABORT_IOCB */ - 0x03, /* MBOX_ABORT_DEVICE */ - 0x07, /* MBOX_ABORT_TARGET */ - 0x03, /* MBOX_BUS_RESET */ - 0x03, /* MBOX_STOP_QUEUE */ - 0x03, /* MBOX_START_QUEUE */ - 0x03, /* MBOX_SINGLE_STEP_QUEUE */ - 0x03, /* MBOX_ABORT_QUEUE */ - 0x03, /* MBOX_GET_DEV_QUEUE_STATUS */ - 0x00, /* 0x001e */ - 0x01, /* MBOX_GET_FIRMWARE_STATUS */ - 0x01, /* MBOX_GET_INIT_SCSI_ID */ - 0x00, /* 0x0021 */ - 0x01, /* MBOX_GET_RETRY_COUNT */ - 0x00, /* 0x0023 */ - 0x00, /* 0x0024 */ - 0x00, /* 0x0025 */ - 0x00, /* 0x0026 */ - 0x00, /* 0x0027 */ - 0x03, /* MBOX_GET_TARGET_PARAMS */ - 0x03, /* MBOX_GET_DEV_QUEUE_PARAMS */ - 0x00, /* 0x002a */ - 0x00, /* 0x002b */ - 0x00, /* 0x002c */ - 0x00, /* 0x002d */ - 0x00, /* 0x002e */ - 0x00, /* 0x002f */ - 0x00, /* 0x0030 */ - 0x00, /* 0x0031 */ - 0x07, /* MBOX_SET_RETRY_COUNT */ - 0x00, /* 0x0033 */ - 0x00, /* 0x0034 */ - 0x00, /* 0x0035 */ - 0x00, /* 0x0036 */ - 0x00, /* 0x0037 */ - 0x0f, /* MBOX_SET_TARGET_PARAMS */ - 0x0f, /* MBOX_SET_DEV_QUEUE_PARAMS */ - 0x00, /* 0x003a */ - 0x00, /* 0x003b */ - 0x00, /* 0x003c */ - 0x00, /* 0x003d */ - 0x00, /* 0x003e */ - 0x00, /* 0x003f */ - 0x00, /* 0x0040 */ - 0x00, /* 0x0041 */ - 0x00, /* 0x0042 */ - 0x00, /* 0x0043 */ - 0x00, /* 0x0044 */ - 0x00, /* 0x0045 */ - 0x00, /* 0x0046 */ - 0x00, /* 0x0047 */ - 0x00, /* 0x0048 */ - 0x00, /* 0x0049 */ - 0x00, /* 0x004a */ - 0x00, /* 0x004b */ - 0x00, /* 0x004c */ - 0x00, /* 0x004d */ - 0x00, /* 0x004e */ - 0x00, /* 0x004f */ - 0x00, /* 0x0050 */ - 0x00, /* 0x0051 */ - 0x00, /* 0x0052 */ - 0x00, /* 0x0053 */ - 0xcf, /* MBOX_EXECUTE_IOCB64 */ - 0x00, /* 0x0055 */ - 0x00, /* 0x0056 */ - 0x00, /* 0x0057 */ - 0x00, /* 0x0058 */ - 0x00, /* 0x0059 */ - 0x00, /* 0x005a */ - 0x00, /* 0x005b */ - 0x00, /* 0x005c */ - 0x00, /* 0x005d */ - 0x00, /* 0x005e */ - 0x00, /* 0x005f */ - 0xff, /* MBOX_INIT_FIRMWARE */ - 0xcd, /* MBOX_GET_INIT_CB */ - 0x01, /* MBOX_INIT_LIP */ - 0xcd, /* MBOX_GET_POS_MAP */ - 0xcf, /* MBOX_GET_PORT_DB */ - 0x03, /* MBOX_CLEAR_ACA */ - 0x03, /* MBOX_TARGET_RESET */ - 0x03, /* MBOX_CLEAR_TASK_SET */ - 0x03, /* MBOX_ABORT_TASK_SET */ - 0x01, /* MBOX_GET_FIRMWARE_STATE */ - 0x03, /* MBOX_GET_PORT_NAME */ - 0x00, /* 0x006b */ - 0x00, /* 0x006c */ - 0x00, /* 0x006d */ - 0xcf, /* MBOX_SEND_SNS */ - 0x0f, /* MBOX_PORT_LOGIN */ - 0x03, /* MBOX_SEND_CHANGE_REQUEST */ - 0x03, /* MBOX_PORT_LOGOUT */ -}; - -#define MAX_MBOX_COMMAND (sizeof(mbox_param)/sizeof(u_short)) - - -struct id_name_map { - u64 wwn; - u_char loop_id; -}; - -struct sns_cb { - u_short len; - u_short res1; - u_int response_low; - u_int response_high; - u_short sub_len; - u_short res2; - u_char data[44]; -}; - -/* address of instance of this struct is passed to adapter to initialize things - */ -struct init_cb { - u_char version; - u_char reseverd1[1]; - u_short firm_opts; - u_short max_frame_len; - u_short max_iocb; - u_short exec_throttle; - u_char retry_cnt; - u_char retry_delay; - u_short node_name[4]; - u_short hard_addr; - u_char reserved2[10]; - u_short req_queue_out; - u_short res_queue_in; - u_short req_queue_len; - u_short res_queue_len; - u_int req_queue_addr_lo; - u_int req_queue_addr_high; - u_int res_queue_addr_lo; - u_int res_queue_addr_high; - /* the rest of this structure only applies to the isp2200 */ - u_short lun_enables; - u_char cmd_resource_cnt; - u_char notify_resource_cnt; - u_short timeout; - u_short reserved3; - u_short add_firm_opts; - u_char res_accum_timer; - u_char irq_delay_timer; - u_short special_options; - u_short reserved4[13]; -}; - -/* - * The result queue can be quite a bit smaller since continuation entries - * do not show up there: - */ -#define RES_QUEUE_LEN ((QLOGICFC_REQ_QUEUE_LEN + 1) / 8 - 1) -#define QUEUE_ENTRY_LEN 64 - -#if ISP2x00_FABRIC -#define QLOGICFC_MAX_ID 0xff -#else -#define QLOGICFC_MAX_ID 0x7d -#endif - -#define QLOGICFC_MAX_LUN 128 -#define QLOGICFC_MAX_LOOP_ID 0x7d - -/* the following connection options only apply to the 2200. i have only - * had success with LOOP_ONLY and P2P_ONLY. - */ - -#define LOOP_ONLY 0 -#define P2P_ONLY 1 -#define LOOP_PREFERED 2 -#define P2P_PREFERED 3 - -#define CONNECTION_PREFERENCE LOOP_ONLY - -/* adapter_state values */ -#define AS_FIRMWARE_DEAD -1 -#define AS_LOOP_DOWN 0 -#define AS_LOOP_GOOD 1 -#define AS_REDO_FABRIC_PORTDB 2 -#define AS_REDO_LOOP_PORTDB 4 - -#define RES_SIZE ((RES_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN) -#define REQ_SIZE ((QLOGICFC_REQ_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN) - -struct isp2x00_hostdata { - u_char revision; - struct pci_dev *pci_dev; - /* result and request queues (shared with isp2x00): */ - u_int req_in_ptr; /* index of next request slot */ - u_int res_out_ptr; /* index of next result slot */ - - /* this is here so the queues are nicely aligned */ - long send_marker; /* do we need to send a marker? */ - - char * res; - char * req; - struct init_cb control_block; - int adapter_state; - unsigned long int tag_ages[QLOGICFC_MAX_ID + 1]; - Scsi_Cmnd *handle_ptrs[QLOGICFC_REQ_QUEUE_LEN + 1]; - unsigned long handle_serials[QLOGICFC_REQ_QUEUE_LEN + 1]; - struct id_name_map port_db[QLOGICFC_MAX_ID + 1]; - u_char mbox_done; - u64 wwn; - u_int port_id; - u_char queued; - u_char host_id; - struct timer_list explore_timer; - struct id_name_map tempmap[QLOGICFC_MAX_ID + 1]; -}; - - -/* queue length's _must_ be power of two: */ -#define QUEUE_DEPTH(in, out, ql) ((in - out) & (ql)) -#define REQ_QUEUE_DEPTH(in, out) QUEUE_DEPTH(in, out, \ - QLOGICFC_REQ_QUEUE_LEN) -#define RES_QUEUE_DEPTH(in, out) QUEUE_DEPTH(in, out, RES_QUEUE_LEN) - -static void isp2x00_enable_irqs(struct Scsi_Host *); -static void isp2x00_disable_irqs(struct Scsi_Host *); -static int isp2x00_init(struct Scsi_Host *); -static int isp2x00_reset_hardware(struct Scsi_Host *); -static int isp2x00_mbox_command(struct Scsi_Host *, u_short[]); -static int isp2x00_return_status(Scsi_Cmnd *, struct Status_Entry *); -static void isp2x00_intr_handler(int, void *, struct pt_regs *); -static irqreturn_t do_isp2x00_intr_handler(int, void *, struct pt_regs *); -static int isp2x00_make_portdb(struct Scsi_Host *); - -#if ISP2x00_FABRIC -static int isp2x00_init_fabric(struct Scsi_Host *, struct id_name_map *, int); -#endif - -#if USE_NVRAM_DEFAULTS -static int isp2x00_get_nvram_defaults(struct Scsi_Host *, struct init_cb *); -static u_short isp2x00_read_nvram_word(struct Scsi_Host *, u_short); -#endif - -#if DEBUG_ISP2x00 -static void isp2x00_print_scsi_cmd(Scsi_Cmnd *); -#endif - -#if DEBUG_ISP2x00_INTR -static void isp2x00_print_status_entry(struct Status_Entry *); -#endif - -static inline void isp2x00_enable_irqs(struct Scsi_Host *host) -{ - outw(ISP_EN_INT | ISP_EN_RISC, host->io_port + PCI_INTER_CTL); -} - - -static inline void isp2x00_disable_irqs(struct Scsi_Host *host) -{ - outw(0x0, host->io_port + PCI_INTER_CTL); -} - - -static int isp2x00_detect(struct scsi_host_template * tmpt) -{ - int hosts = 0; - unsigned long wait_time; - struct Scsi_Host *host = NULL; - struct isp2x00_hostdata *hostdata; - struct pci_dev *pdev; - unsigned short device_ids[2]; - dma_addr_t busaddr; - int i; - - - ENTER("isp2x00_detect"); - - device_ids[0] = PCI_DEVICE_ID_QLOGIC_ISP2100; - device_ids[1] = PCI_DEVICE_ID_QLOGIC_ISP2200; - - tmpt->proc_name = "isp2x00"; - - for (i=0; i<2; i++){ - pdev = NULL; - while ((pdev = pci_find_device(PCI_VENDOR_ID_QLOGIC, device_ids[i], pdev))) { - if (pci_enable_device(pdev)) - continue; - - /* Try to configure DMA attributes. */ - if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) && - pci_set_dma_mask(pdev, DMA_32BIT_MASK)) - continue; - - host = scsi_register(tmpt, sizeof(struct isp2x00_hostdata)); - if (!host) { - printk("qlogicfc%d : could not register host.\n", hosts); - continue; - } - host->max_id = QLOGICFC_MAX_ID + 1; - host->max_lun = QLOGICFC_MAX_LUN; - hostdata = (struct isp2x00_hostdata *) host->hostdata; - - memset(hostdata, 0, sizeof(struct isp2x00_hostdata)); - hostdata->pci_dev = pdev; - hostdata->res = pci_alloc_consistent(pdev, RES_SIZE + REQ_SIZE, &busaddr); - - if (!hostdata->res){ - printk("qlogicfc%d : could not allocate memory for request and response queue.\n", hosts); - scsi_unregister(host); - continue; - } - hostdata->req = hostdata->res + (RES_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN; - hostdata->queued = 0; - /* set up the control block */ - hostdata->control_block.version = 0x1; - hostdata->control_block.firm_opts = cpu_to_le16(0x800e); - hostdata->control_block.max_frame_len = cpu_to_le16(2048); - hostdata->control_block.max_iocb = cpu_to_le16(QLOGICFC_REQ_QUEUE_LEN); - hostdata->control_block.exec_throttle = cpu_to_le16(QLOGICFC_CMD_PER_LUN); - hostdata->control_block.retry_delay = 5; - hostdata->control_block.retry_cnt = 1; - hostdata->control_block.node_name[0] = cpu_to_le16(0x0020); - hostdata->control_block.node_name[1] = cpu_to_le16(0xE000); - hostdata->control_block.node_name[2] = cpu_to_le16(0x008B); - hostdata->control_block.node_name[3] = cpu_to_le16(0x0000); - hostdata->control_block.hard_addr = cpu_to_le16(0x0003); - hostdata->control_block.req_queue_len = cpu_to_le16(QLOGICFC_REQ_QUEUE_LEN + 1); - hostdata->control_block.res_queue_len = cpu_to_le16(RES_QUEUE_LEN + 1); - hostdata->control_block.res_queue_addr_lo = cpu_to_le32(pci64_dma_lo32(busaddr)); - hostdata->control_block.res_queue_addr_high = cpu_to_le32(pci64_dma_hi32(busaddr)); - hostdata->control_block.req_queue_addr_lo = cpu_to_le32(pci64_dma_lo32(busaddr + RES_SIZE)); - hostdata->control_block.req_queue_addr_high = cpu_to_le32(pci64_dma_hi32(busaddr + RES_SIZE)); - - - hostdata->control_block.add_firm_opts |= cpu_to_le16(CONNECTION_PREFERENCE<<4); - hostdata->adapter_state = AS_LOOP_DOWN; - hostdata->explore_timer.data = 1; - hostdata->host_id = hosts; - - if (isp2x00_init(host) || isp2x00_reset_hardware(host)) { - pci_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); - scsi_unregister(host); - continue; - } - host->this_id = 0; - - if (request_irq(host->irq, do_isp2x00_intr_handler, SA_INTERRUPT | SA_SHIRQ, "qlogicfc", host)) { - printk("qlogicfc%d : interrupt %d already in use\n", - hostdata->host_id, host->irq); - pci_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); - scsi_unregister(host); - continue; - } - if (!request_region(host->io_port, 0xff, "qlogicfc")) { - printk("qlogicfc%d : i/o region 0x%lx-0x%lx already " - "in use\n", - hostdata->host_id, host->io_port, host->io_port + 0xff); - free_irq(host->irq, host); - pci_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); - scsi_unregister(host); - continue; - } - - outw(0x0, host->io_port + PCI_SEMAPHORE); - outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); - isp2x00_enable_irqs(host); - /* wait for the loop to come up */ - for (wait_time = jiffies + 10 * HZ; time_before(jiffies, wait_time) && hostdata->adapter_state == AS_LOOP_DOWN;) { - barrier(); - cpu_relax(); - } - if (hostdata->adapter_state == AS_LOOP_DOWN) { - printk("qlogicfc%d : link is not up\n", hostdata->host_id); - } - hosts++; - hostdata->explore_timer.data = 0; - } - } - - - /* this busy loop should not be needed but the isp2x00 seems to need - some time before recognizing it is attached to a fabric */ - -#if ISP2x00_FABRIC - if (hosts) { - for (wait_time = jiffies + 5 * HZ; time_before(jiffies, wait_time);) { - barrier(); - cpu_relax(); - } - } -#endif - - LEAVE("isp2x00_detect"); - - return hosts; -} - - -static int isp2x00_make_portdb(struct Scsi_Host *host) -{ - - short param[8]; - int i, j; - struct isp2x00_hostdata *hostdata; - - isp2x00_disable_irqs(host); - - hostdata = (struct isp2x00_hostdata *) host->hostdata; - memset(hostdata->tempmap, 0, sizeof(hostdata->tempmap)); - -#if ISP2x00_FABRIC - for (i = 0x81; i < QLOGICFC_MAX_ID; i++) { - param[0] = MBOX_PORT_LOGOUT; - param[1] = i << 8; - param[2] = 0; - param[3] = 0; - - isp2x00_mbox_command(host, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) { - - DEBUG_FABRIC(printk("qlogicfc%d : logout failed %x %x\n", hostdata->host_id, i, param[0])); - } - } -#endif - - - param[0] = MBOX_GET_INIT_SCSI_ID; - - isp2x00_mbox_command(host, param); - - if (param[0] == MBOX_COMMAND_COMPLETE) { - hostdata->port_id = ((u_int) param[3]) << 16; - hostdata->port_id |= param[2]; - hostdata->tempmap[0].loop_id = param[1]; - hostdata->tempmap[0].wwn = hostdata->wwn; - } - else { - printk("qlogicfc%d : error getting scsi id.\n", hostdata->host_id); - } - - for (i = 0; i <=QLOGICFC_MAX_ID; i++) - hostdata->tempmap[i].loop_id = hostdata->tempmap[0].loop_id; - - for (i = 0, j = 1; i <= QLOGICFC_MAX_LOOP_ID; i++) { - param[0] = MBOX_GET_PORT_NAME; - param[1] = (i << 8) & 0xff00; - - isp2x00_mbox_command(host, param); - - if (param[0] == MBOX_COMMAND_COMPLETE) { - hostdata->tempmap[j].loop_id = i; - hostdata->tempmap[j].wwn = ((u64) (param[2] & 0xff)) << 56; - hostdata->tempmap[j].wwn |= ((u64) ((param[2] >> 8) & 0xff)) << 48; - hostdata->tempmap[j].wwn |= ((u64) (param[3] & 0xff)) << 40; - hostdata->tempmap[j].wwn |= ((u64) ((param[3] >> 8) & 0xff)) << 32; - hostdata->tempmap[j].wwn |= ((u64) (param[6] & 0xff)) << 24; - hostdata->tempmap[j].wwn |= ((u64) ((param[6] >> 8) & 0xff)) << 16; - hostdata->tempmap[j].wwn |= ((u64) (param[7] & 0xff)) << 8; - hostdata->tempmap[j].wwn |= ((u64) ((param[7] >> 8) & 0xff)); - - j++; - - } - } - - -#if ISP2x00_FABRIC - isp2x00_init_fabric(host, hostdata->tempmap, j); -#endif - - for (i = 0; i <= QLOGICFC_MAX_ID; i++) { - if (hostdata->tempmap[i].wwn != hostdata->port_db[i].wwn) { - for (j = 0; j <= QLOGICFC_MAX_ID; j++) { - if (hostdata->tempmap[j].wwn == hostdata->port_db[i].wwn) { - hostdata->port_db[i].loop_id = hostdata->tempmap[j].loop_id; - break; - } - } - if (j == QLOGICFC_MAX_ID + 1) - hostdata->port_db[i].loop_id = hostdata->tempmap[0].loop_id; - - for (j = 0; j <= QLOGICFC_MAX_ID; j++) { - if (hostdata->port_db[j].wwn == hostdata->tempmap[i].wwn || !hostdata->port_db[j].wwn) { - break; - } - } - if (j == QLOGICFC_MAX_ID + 1) - printk("qlogicfc%d : Too many scsi devices, no more room in port map.\n", hostdata->host_id); - if (!hostdata->port_db[j].wwn) { - hostdata->port_db[j].loop_id = hostdata->tempmap[i].loop_id; - hostdata->port_db[j].wwn = hostdata->tempmap[i].wwn; - } - } else - hostdata->port_db[i].loop_id = hostdata->tempmap[i].loop_id; - - } - - isp2x00_enable_irqs(host); - - return 0; -} - - -#if ISP2x00_FABRIC - -#define FABRIC_PORT 0x7e -#define FABRIC_CONTROLLER 0x7f -#define FABRIC_SNS 0x80 - -int isp2x00_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int cur_scsi_id) -{ - - u_short param[8]; - u64 wwn; - int done = 0; - u_short loop_id = 0x81; - u_short scsi_id = cur_scsi_id; - u_int port_id; - struct sns_cb *req; - u_char *sns_response; - dma_addr_t busaddr; - struct isp2x00_hostdata *hostdata; - - hostdata = (struct isp2x00_hostdata *) host->hostdata; - - DEBUG_FABRIC(printk("qlogicfc%d : Checking for a fabric.\n", hostdata->host_id)); - param[0] = MBOX_GET_PORT_NAME; - param[1] = (u16)FABRIC_PORT << 8; - - isp2x00_mbox_command(host, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) { - DEBUG_FABRIC(printk("qlogicfc%d : fabric check result %x\n", hostdata->host_id, param[0])); - return 0; - } - printk("qlogicfc%d : Fabric found.\n", hostdata->host_id); - - req = (struct sns_cb *)pci_alloc_consistent(hostdata->pci_dev, sizeof(*req) + 608, &busaddr); - - if (!req){ - printk("qlogicfc%d : Could not allocate DMA resources for fabric initialization\n", hostdata->host_id); - return 0; - } - sns_response = (u_char *)(req + 1); - - if (hostdata->adapter_state & AS_REDO_LOOP_PORTDB){ - memset(req, 0, sizeof(*req)); - - req->len = cpu_to_le16(8); - req->response_low = cpu_to_le32(pci64_dma_lo32(busaddr + sizeof(*req))); - req->response_high = cpu_to_le32(pci64_dma_hi32(busaddr + sizeof(*req))); - req->sub_len = cpu_to_le16(22); - req->data[0] = 0x17; - req->data[1] = 0x02; - req->data[8] = (u_char) (hostdata->port_id & 0xff); - req->data[9] = (u_char) (hostdata->port_id >> 8 & 0xff); - req->data[10] = (u_char) (hostdata->port_id >> 16 & 0xff); - req->data[13] = 0x01; - param[0] = MBOX_SEND_SNS; - param[1] = 30; - param[2] = pci64_dma_lo32(busaddr) >> 16; - param[3] = pci64_dma_lo32(busaddr); - param[6] = pci64_dma_hi32(busaddr) >> 16; - param[7] = pci64_dma_hi32(busaddr); - - isp2x00_mbox_command(host, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) - printk("qlogicfc%d : error sending RFC-4\n", hostdata->host_id); - } - - port_id = hostdata->port_id; - while (!done) { - memset(req, 0, sizeof(*req)); - - req->len = cpu_to_le16(304); - req->response_low = cpu_to_le32(pci64_dma_lo32(busaddr + sizeof(*req))); - req->response_high = cpu_to_le32(pci64_dma_hi32(busaddr + sizeof(*req))); - req->sub_len = cpu_to_le16(6); - req->data[0] = 0x00; - req->data[1] = 0x01; - req->data[8] = (u_char) (port_id & 0xff); - req->data[9] = (u_char) (port_id >> 8 & 0xff); - req->data[10] = (u_char) (port_id >> 16 & 0xff); - - param[0] = MBOX_SEND_SNS; - param[1] = 14; - param[2] = pci64_dma_lo32(busaddr) >> 16; - param[3] = pci64_dma_lo32(busaddr); - param[6] = pci64_dma_hi32(busaddr) >> 16; - param[7] = pci64_dma_hi32(busaddr); - - isp2x00_mbox_command(host, param); - - if (param[0] == MBOX_COMMAND_COMPLETE) { - DEBUG_FABRIC(printk("qlogicfc%d : found node %02x%02x%02x%02x%02x%02x%02x%02x ", hostdata->host_id, sns_response[20], sns_response[21], sns_response[22], sns_response[23], sns_response[24], sns_response[25], sns_response[26], sns_response[27])); - DEBUG_FABRIC(printk(" port id: %02x%02x%02x\n", sns_response[17], sns_response[18], sns_response[19])); - port_id = ((u_int) sns_response[17]) << 16; - port_id |= ((u_int) sns_response[18]) << 8; - port_id |= ((u_int) sns_response[19]); - wwn = ((u64) sns_response[20]) << 56; - wwn |= ((u64) sns_response[21]) << 48; - wwn |= ((u64) sns_response[22]) << 40; - wwn |= ((u64) sns_response[23]) << 32; - wwn |= ((u64) sns_response[24]) << 24; - wwn |= ((u64) sns_response[25]) << 16; - wwn |= ((u64) sns_response[26]) << 8; - wwn |= ((u64) sns_response[27]); - if (hostdata->port_id >> 8 != port_id >> 8) { - DEBUG_FABRIC(printk("qlogicfc%d : adding a fabric port: %x\n", hostdata->host_id, port_id)); - param[0] = MBOX_PORT_LOGIN; - param[1] = loop_id << 8; - param[2] = (u_short) (port_id >> 16); - param[3] = (u_short) (port_id); - - isp2x00_mbox_command(host, param); - - if (param[0] == MBOX_COMMAND_COMPLETE) { - port_db[scsi_id].wwn = wwn; - port_db[scsi_id].loop_id = loop_id; - loop_id++; - scsi_id++; - } else { - printk("qlogicfc%d : Error performing port login %x\n", hostdata->host_id, param[0]); - DEBUG_FABRIC(printk("qlogicfc%d : loop_id: %x\n", hostdata->host_id, loop_id)); - param[0] = MBOX_PORT_LOGOUT; - param[1] = loop_id << 8; - param[2] = 0; - param[3] = 0; - - isp2x00_mbox_command(host, param); - - } - - } - if (hostdata->port_id == port_id) - done = 1; - } else { - printk("qlogicfc%d : Get All Next failed %x.\n", hostdata->host_id, param[0]); - pci_free_consistent(hostdata->pci_dev, sizeof(*req) + 608, req, busaddr); - return 0; - } - } - - pci_free_consistent(hostdata->pci_dev, sizeof(*req) + 608, req, busaddr); - return 1; -} - -#endif /* ISP2x00_FABRIC */ - - -static int isp2x00_release(struct Scsi_Host *host) -{ - struct isp2x00_hostdata *hostdata; - dma_addr_t busaddr; - - ENTER("isp2x00_release"); - - hostdata = (struct isp2x00_hostdata *) host->hostdata; - - outw(0x0, host->io_port + PCI_INTER_CTL); - free_irq(host->irq, host); - - release_region(host->io_port, 0xff); - - busaddr = pci64_dma_build(le32_to_cpu(hostdata->control_block.res_queue_addr_high), - le32_to_cpu(hostdata->control_block.res_queue_addr_lo)); - pci_free_consistent(hostdata->pci_dev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); - - LEAVE("isp2x00_release"); - - return 0; -} - - -static const char *isp2x00_info(struct Scsi_Host *host) |