patch-2.3.43 linux/drivers/scsi/qla1280.c
Next file: linux/drivers/scsi/qla1280.h
Previous file: linux/drivers/scsi/ql1280_fw.h
Back to the patch index
Back to the overall index
- Lines: 6851
- Date:
Tue Feb 8 12:01:59 2000
- Orig file:
v2.3.42/linux/drivers/scsi/qla1280.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/qla1280.c linux/drivers/scsi/qla1280.c
@@ -0,0 +1,6850 @@
+/********************************************************************************
+ * QLOGIC LINUX SOFTWARE
+ *
+ * QLogic ISP1x80/1x160 device driver for Linux 2.3.x (redhat 6.X).
+ *
+ * COPYRIGHT (C) 1999-2000 QLOGIC CORPORATION
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the Qlogic's Linux Software License. See below.
+ *
+ * This program is WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistribution's or source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ ********************************************************************************/
+
+/*****************************************************************************************
+ QLOGIC CORPORATION SOFTWARE
+ "GNU" GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION
+ AND MODIFICATION
+
+This GNU General Public License ("License") applies solely to QLogic Linux
+Software ("Software") and may be distributed under the terms of this License.
+
+1. You may copy and distribute verbatim copies of the Software's source code as
+you receive it, in any medium, provided that you conspicuously and appropriately
+publish on each copy an appropriate copyright notice and disclaimer of warranty;
+keep intact all the notices that refer to this License and to the absence of any
+warranty; and give any other recipients of the Software a copy of this License along
+with the Software.
+
+You may charge a fee for the physical act of transferring a copy, and you may at your
+option offer warranty protection in exchange for a fee.
+
+2. You may modify your copy or copies of the Software or any portion of it, thus forming
+a work based on the Software, and copy and distribute such modifications or work under
+the terms of Section 1 above, provided that you also meet all of these conditions:
+
+* a) You must cause the modified files to carry prominent notices stating that you
+changed the files and the date of any change.
+
+* b) You must cause any work that you distribute or publish that in whole or in part
+contains or is derived from the Software or any part thereof, to be licensed as a
+whole at no charge to all third parties under the terms of this License.
+
+* c) If the modified Software normally reads commands interactively when run, you
+must cause it, when started running for such interactive use in the most ordinary way,
+to print or display an announcement including an appropriate copyright notice and a
+notice that there is no warranty (or else, saying that you provide a warranty) and that
+users may redistribute the Software under these conditions, and telling the user how to
+view a copy of this License. (Exception:if the Software itself is interactive but does
+not normally print such an announcement, your work based on the Software is not required
+to print an announcement.)
+
+These requirements apply to the modified work as a whole. If identifiable sections of
+that work are not derived from the Software, and can be reasonably considered independent
+and separate works in themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you distribute the same
+sections as part of a whole which is a work based on the Software, the distribution of the
+whole must be on the terms of this License, whose permissions for other licensees extend
+to the entire whole, and thus to each and every part regardless of who wrote it.
+
+3. You may copy and distribute the Software (or a work based on it, under Section 2) in
+object code or executable form under the terms of Sections 1 and 2 above provided that
+you also do one of the following:
+
+* a) Accompany it with the complete corresponding machine-readable source code, which must
+be distributed under the terms of Sections 1 and 2 above on a medium customarily used for
+software interchange; or,
+
+* b) Accompany it with a written offer, valid for at least three years, to give any third
+party, for a charge no more than your cost of physically performing source distribution,
+a complete machine-readable copy of the corresponding source code, to be distributed under
+the terms of Sections 1 and 2 above on a medium customarily used for software interchange;
+or,
+
+* c) Accompany it with the information you received as to the offer to distribute
+corresponding source code. (This alternative is allowed only for noncommercial distribution
+and only if you received the Software in object code or executable form with such an offer,
+in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for making modifications
+to it. For an executable work, complete source code means all the source code for all
+modules it contains, plus any associated interface definition files, plus the scripts used
+to control compilation and installation of the executable.
+
+If distribution of executable or object code is made by offering access to copy from a
+designated place, then offering equivalent access to copy the source code from the same
+place counts as distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+4. You may not copy, modify, sublicense, or distribute the Software except as expressly
+provided under this License. Any attempt otherwise to copy, modify, sublicense or
+distribute the Software is void, and will automatically terminate your rights under this
+License. However, parties who have received copies, or rights, from you under this License
+will not have their licenses terminated so long as such parties remain in full compliance.
+
+5. This license grants you world wide, royalty free non-exclusive rights to modify or
+distribute the Software or its derivative works. These actions are prohibited by law
+if you do not accept this License. Therefore, by modifying or distributing the Software
+(or any work based on the Software), you indicate your acceptance of this License to do
+so, and all its terms and conditions for copying, distributing or modifying the Software
+or works based on it.
+
+6. Each time you redistribute the Software (or any work based on the Software), the
+recipient automatically receives a license from the original licensor to copy, distribute
+or modify the Software subject to these terms and conditions. You may not impose any
+further restrictions on the recipients' exercise of the rights granted herein. You are
+not responsible for enforcing compliance by third parties to this License.
+
+7. If, as a consequence of a court judgment or allegation of patent infringement or for
+any other reason (not limited to patent issues), conditions are imposed on you
+(whether by court order, agreement or otherwise) that contradict the conditions of this
+License, they do not excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this License
+and any other pertinent obligations, then as a consequence you may not distribute the
+Software at all.
+
+If any portion of this section is held invalid or unenforceable under any particular
+circumstance, the balance of the section is intended to apply and the section as a whole
+is intended to apply in other circumstances.
+NO WARRANTY
+
+11. THE SOFTWARE IS PROVIDED WITHOUT A WARRANTY OF ANY KIND. THERE IS NO
+WARRANTY FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND,
+EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU.
+SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
+NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE SOFTWARE AS PERMITTED ABOVE, BE LIABLE TO YOU FOR
+DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL
+DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE (INCLUDING
+BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR
+LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE SOFTWARE TO
+OPERATE WITH ANY OTHER SOFTWARES), EVEN IF SUCH HOLDER OR OTHER PARTY HAS
+BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+END OF TERMS AND CONDITIONS
+
+*******************************************************************************************/
+
+/****************************************************************************
+ Revision History:
+ Rev. 3.00 Jan 17, 1999 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.
+*****************************************************************************/
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
+#define QLA1280_VERSION " 3.00-Beta"
+
+#include <stdarg.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/segment.h>
+#include <asm/byteorder.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/blk.h>
+#include <linux/tqueue.h>
+/* MRS #include <linux/tasks.h> */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+# include <linux/bios32.h>
+#endif
+#include "sd.h"
+#include "scsi.h"
+#include "hosts.h"
+#define UNIQUE_FW_NAME
+#include "qla1280.h"
+#include "ql12160_fw.h" /* ISP RISC code */
+#include "ql1280_fw.h"
+
+#include <linux/stat.h>
+#include <linux/malloc.h> /* for kmalloc() */
+
+
+#ifndef KERNEL_VERSION
+# define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
+#endif
+
+
+/*
+ * Compile time Options:
+ * 0 - Disable and 1 - Enable
+ */
+#define QLA1280_64BIT_SUPPORT 1 /* 64-bit Support */
+#define QL1280_TARGET_MODE_SUPPORT 0 /* Target mode support */
+#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
+#undef DYNAMIC_MEM_ALLOC
+
+#define DEBUG_QLA1280 0 /* Debugging */
+/* #define CHECKSRBSIZE */
+
+/*
+ * These macros to assist programming
+ */
+
+#define BZERO(ptr, amt) memset(ptr, 0, amt)
+#define BCOPY(src, dst, amt) memcpy(dst, src, amt)
+#define KMALLOC(siz) kmalloc((siz), GFP_ATOMIC)
+#define KMFREE(ip,siz) kfree((ip))
+#define SYS_DELAY(x) udelay(x);barrier()
+#define QLA1280_DELAY(sec) mdelay(sec * 1000)
+#define VIRT_TO_BUS(a) virt_to_bus((a))
+#if QLA1280_64BIT_SUPPORT
+#if BITS_PER_LONG <= 32
+#define VIRT_TO_BUS_LOW(a) (uint32_t)virt_to_bus((a))
+#define VIRT_TO_BUS_HIGH(a) (uint32_t)(0x0)
+#else
+#define VIRT_TO_BUS_LOW(a) (uint32_t)(0xffffffff & virt_to_bus((a)))
+#define VIRT_TO_BUS_HIGH(a) (uint32_t)(0xffffffff & (virt_to_bus((a))>>32))
+#endif
+#endif /* QLA1280_64BIT_SUPPORT */
+
+#define STATIC
+
+#define NVRAM_DELAY() udelay(500) /* 2 microsecond delay */
+void qla1280_device_queue_depth(scsi_qla_host_t *, Scsi_Device *);
+
+#define CACHE_FLUSH(a) (RD_REG_WORD(a))
+#define INVALID_HANDLE (MAX_OUTSTANDING_COMMANDS+1)
+
+#define MSW(x) (uint16_t)((uint32_t)(x) >> 16)
+#define LSW(x) (uint16_t)(x)
+#define MSB(x) (uint8_t)((uint16_t)(x) >> 8)
+#define LSB(x) (uint8_t)(x)
+
+#if BITS_PER_LONG <= 32
+#define LS_64BITS(x) (uint32_t)(x)
+#define MS_64BITS(x) (uint32_t)(0x0)
+#else
+#define LS_64BITS(x) (uint32_t)(0xffffffff & (x))
+#define MS_64BITS(x) (uint32_t)(0xffffffff & ((x)>>32) )
+#endif
+
+/*
+ * QLogic Driver Support Function Prototypes.
+ */
+STATIC void qla1280_done(scsi_qla_host_t *, srb_t **, srb_t **);
+STATIC void qla1280_next(scsi_qla_host_t *, scsi_lu_t *, uint8_t);
+STATIC void qla1280_putq_t(scsi_lu_t *, srb_t *);
+STATIC void qla1280_done_q_put(srb_t *, srb_t **, srb_t **);
+STATIC void qla1280_select_queue_depth(struct Scsi_Host *, Scsi_Device *);
+#ifdef QLA1280_UNUSED
+static void qla1280_dump_regs(struct Scsi_Host *host);
+#endif
+#if STOP_ON_ERROR
+static void qla1280_panic(char *, struct Scsi_Host *host);
+#endif
+void qla1280_print_scsi_cmd(Scsi_Cmnd *cmd);
+STATIC void qla1280_abort_queue_single(scsi_qla_host_t *,uint32_t,uint32_t,uint32_t,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(scsi_qla_host_t *ha);
+void qla1280_do_dpc(void *p);
+#ifdef QLA1280_UNUSED
+static void qla1280_set_flags(char * s);
+#endif
+static char *qla1280_get_token(char *, char *);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
+STATIC inline void mdelay(int);
+#endif
+static inline void qla1280_enable_intrs(scsi_qla_host_t *);
+static inline void qla1280_disable_intrs(scsi_qla_host_t *);
+
+/*
+ * QLogic ISP1280 Hardware Support Function Prototypes.
+ */
+STATIC uint8_t qla1280_initialize_adapter(struct scsi_qla_host *ha);
+STATIC uint8_t qla1280_enable_tgt(scsi_qla_host_t *, uint8_t);
+STATIC uint8_t qla1280_isp_firmware(scsi_qla_host_t *);
+STATIC uint8_t qla1280_pci_config(scsi_qla_host_t *);
+STATIC uint8_t qla1280_chip_diag(scsi_qla_host_t *);
+STATIC uint8_t qla1280_setup_chip(scsi_qla_host_t *);
+STATIC uint8_t qla1280_init_rings(scsi_qla_host_t *);
+STATIC uint8_t qla1280_nvram_config(scsi_qla_host_t *);
+STATIC uint8_t qla1280_mailbox_command(scsi_qla_host_t *, uint8_t, uint16_t *);
+STATIC uint8_t qla1280_bus_reset(scsi_qla_host_t *, uint8_t);
+STATIC uint8_t qla1280_device_reset(scsi_qla_host_t *, uint8_t, uint32_t);
+STATIC uint8_t qla1280_abort_device(scsi_qla_host_t *, uint8_t, uint32_t, uint32_t);
+STATIC uint8_t qla1280_abort_command(scsi_qla_host_t *, srb_t *),
+#if QLA1280_64BIT_SUPPORT
+ qla1280_64bit_start_scsi(scsi_qla_host_t *, srb_t *),
+#endif
+ qla1280_32bit_start_scsi(scsi_qla_host_t *, srb_t *),
+ qla1280_abort_isp(scsi_qla_host_t *);
+STATIC void qla1280_nv_write(scsi_qla_host_t *, uint16_t),
+ qla1280_nv_delay(scsi_qla_host_t *),
+ qla1280_poll(scsi_qla_host_t *),
+ qla1280_reset_adapter(scsi_qla_host_t *),
+ qla1280_marker(scsi_qla_host_t *, uint8_t, uint32_t, uint32_t, uint8_t),
+ qla1280_isp_cmd(scsi_qla_host_t *),
+ qla1280_isr(scsi_qla_host_t *, srb_t **, srb_t **),
+ qla1280_rst_aen(scsi_qla_host_t *),
+ qla1280_status_entry(scsi_qla_host_t *, sts_entry_t *, srb_t **,
+ srb_t **),
+ qla1280_error_entry(scsi_qla_host_t *, response_t *, srb_t **,
+ srb_t **),
+ qla1280_restart_queues(scsi_qla_host_t *),
+ qla1280_abort_queues(scsi_qla_host_t *);
+STATIC uint16_t qla1280_get_nvram_word(scsi_qla_host_t *, uint32_t),
+ qla1280_nvram_request(scsi_qla_host_t *, uint32_t),
+ qla1280_debounce_register(volatile uint16_t *);
+STATIC request_t *qla1280_req_pkt(scsi_qla_host_t *);
+int qla1280_check_for_dead_scsi_bus(scsi_qla_host_t *ha, srb_t *sp);
+STATIC uint8_t qla1280_mem_alloc(scsi_qla_host_t *ha);
+STATIC uint8_t qla1280_register_with_Linux(scsi_qla_host_t *ha, uint8_t maxchannels);
+
+STATIC uint8_t qla12160_set_target_parameters(scsi_qla_host_t *, uint32_t, uint32_t, uint32_t, nvram160_t *);
+STATIC void qla12160_get_target_parameters(scsi_qla_host_t *, uint32_t, uint32_t, uint32_t);
+
+#if QL1280_TARGET_MODE_SUPPORT
+STATIC void qla1280_enable_lun(scsi_qla_host_t *, uint8_t, uint32_t),
+ qla1280_notify_ack(scsi_qla_host_t *, notify_entry_t *),
+ qla1280_immed_notify(scsi_qla_host_t *, notify_entry_t *),
+ qla1280_accept_io(scsi_qla_host_t *, ctio_ret_entry_t *),
+#if QLA1280_64BIT_SUPPORT
+ qla1280_64bit_continue_io(scsi_qla_host_t *, atio_entry_t *, uint32_t,
+ paddr32_t *),
+#endif
+ qla1280_32bit_continue_io(scsi_qla_host_t *, atio_entry_t *, uint32_t,
+ paddr32_t *),
+ qla1280_atio_entry(scsi_qla_host_t *, atio_entry_t *),
+ qla1280_notify_entry(scsi_qla_host_t *, notify_entry_t *);
+#endif /* QLA1280_TARGET_MODE_SUPPORT */
+
+#ifdef QL_DEBUG_ROUTINES
+/*
+ * Driver Debug Function Prototypes.
+ */
+STATIC uint8_t qla1280_getbyte(uint8_t *);
+STATIC uint16_t qla1280_getword(uint16_t *);
+STATIC uint32_t qla1280_getdword(uint32_t *);
+STATIC void qla1280_putbyte(uint8_t *, uint8_t),
+ qla1280_putword(uint16_t *, uint16_t),
+ qla1280_putdword(uint32_t *, uint32_t),
+ qla1280_print(caddr_t),
+ qla1280_output_number(uint32_t, uint8_t),
+ qla1280_putc(uint8_t),
+ qla1280_dump_buffer(caddr_t, uint32_t);
+
+char debug_buff[80];
+#if DEBUG_QLA1280
+STATIC uint8_t ql_debug_print = 1;
+#else
+STATIC uint8_t ql_debug_print = 0;
+#endif
+#endif
+
+/*
+ * insmod needs to find the variable and make it point to something
+ */
+#ifdef MODULE
+static char *options = NULL;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,18)
+
+/* insmod qla1280 options=verbose" */
+MODULE_PARM(options, "s");
+#endif
+/*
+ * Just in case someone uses commas to separate items on the insmod
+ * command line, we define a dummy buffer here to avoid having insmod
+ * write wild stuff into our code segment
+ */
+static char dummy_buffer[60] = "Please don't add commas in your insmod command!!\n";
+
+#endif
+
+
+/*
+ * Our directory Entry in /proc/scsi for the user to
+ * access the driver.
+ */
+
+#if 0
+
+/* 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_XFRLEN(Cmnd) (Cmnd)->request_bufflen
+#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 QLA1280_VENDOR_ID 0x1077
+#define QLA1080_DEVICE_ID 0x1080
+#define QLA1240_DEVICE_ID 0x1240
+#define QLA1280_DEVICE_ID 0x1280
+#define QLA12160_DEVICE_ID 0x1216
+#define QLA10160_DEVICE_ID 0x1016
+#define NUM_OF_ISP_DEVICES 6
+
+typedef struct _qlaboards
+{
+ 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 long *fwlen; /* number of words in array */
+ unsigned short *fwstart; /* start address for F/W */
+ unsigned char *fwver; /* Ptr to F/W version array */
+} qla_boards_t;
+
+struct _qlaboards QLBoardTbl[NUM_OF_ISP_DEVICES] =
+{
+ /* Name , Board PCI Device ID, Number of ports */
+ {"QLA1080 ", QLA1080_DEVICE_ID, 1,
+ &fw1280ei_code01[0], (unsigned long *)&fw1280ei_length01,&fw1280ei_addr01, &fw1280ei_version_str[0] },
+ {"QLA1240 ", QLA1240_DEVICE_ID, 2,
+ &fw1280ei_code01[0], (unsigned long *)&fw1280ei_length01,&fw1280ei_addr01, &fw1280ei_version_str[0] },
+ {"QLA1280 ", QLA1280_DEVICE_ID, 2,
+ &fw1280ei_code01[0], (unsigned long *)&fw1280ei_length01,&fw1280ei_addr01, &fw1280ei_version_str[0] },
+ {"QLA12160 ", QLA12160_DEVICE_ID, 2,
+ &fw12160i_code01[0], (unsigned long *)&fw12160i_length01,&fw12160i_addr01, &fw12160i_version_str[0] },
+ {"QLA10160 ", QLA10160_DEVICE_ID, 1,
+ &fw12160i_code01[0], (unsigned long *)&fw12160i_length01,&fw12160i_addr01, &fw12160i_version_str[0] },
+ {" ", 0, 0}
+};
+
+static unsigned long qla1280_verbose = 1L;
+static scsi_qla_host_t *qla1280_hostlist = NULL;
+#ifdef QLA1280_PROFILE
+static int qla1280_buffer_size = 0;
+static char *qla1280_buffer = NULL;
+#endif
+
+#ifdef QL_DEBUG_LEVEL_3
+#define ENTER(x) sprintf(debug_buff,"qla1280 : Entering %s()\n\r", x); \
+ qla1280_print(debug_buff);
+#define LEAVE(x) sprintf(debug_buff,"qla1280 : Leaving %s()\n\r", x); \
+ qla1280_print(debug_buff);
+#define ENTER_INTR(x) sprintf(debug_buff,"qla1280 : Entering %s()\n\r", x); \
+ qla1280_print(debug_buff);
+#define LEAVE_INTR(x) sprintf(debug_buff,"qla1280 : Leaving %s()\n\r", x); \
+ qla1280_print(debug_buff);
+#define DEBUG3(x) x
+#else
+#define ENTER(x)
+#define LEAVE(x)
+#define ENTER_INTR(x)
+#define LEAVE_INTR(x)
+#define DEBUG3(x)
+#endif
+
+#if DEBUG_QLA1280
+#define COMTRACE(x)
+/* #define COMTRACE(x) qla1280_putc(x); */
+#define DEBUG(x) x
+#else
+#define DEBUG(x)
+#define COMTRACE(x)
+#endif
+
+#ifdef QL_DEBUG_LEVEL_2
+#define DEBUG2(x) x
+#else
+#define DEBUG2(x)
+#endif
+#define DEBUG5(x)
+
+#if (BITS_PER_LONG==64)
+# define OFFSET(w) (((uint64_t) &w) & 0xFF) /* 256 byte offsets */
+#else
+# define OFFSET(w) (((uint32_t) &w) & 0xFF) /* 256 byte offsets */
+#endif
+
+#define SCSI_BUS_32(scp) ((scp)->channel)
+#define SCSI_TCN_32(scp) ((scp)->target)
+#define SCSI_LUN_32(scp) ((scp)->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:
+ *************************************************************************/
+#ifdef QLA1280_PROFILE
+#define PROC_BUF (&qla1280_buffer[size])
+#define LUN_ID (targ_lun>>(MAX_T_BITS+MAX_L_BITS)),((targ_lun>>MAX_L_BITS)&0xf), targ_lun&0x7
+#endif
+int
+qla1280_proc_info ( char *buffer, char **start, off_t offset, int length,
+ int hostno, int inout)
+{
+#ifdef QLA1280_PROFILE
+ struct Scsi_Host *host;
+ scsi_qla_host_t *ha;
+ int size = 0;
+ int targ_lun;
+ scsi_lu_t *up;
+ int no_devices;
+
+ printk("Entering proc_info 0x%p,0x%lx,0x%x,0x%x\n",buffer,offset,length,hostno);
+ host = NULL;
+ /* find the host they want to look at */
+ for(ha=qla1280_hostlist; (ha != NULL) && ha->host->host_no != hostno; ha=ha->next)
+ ;
+
+ if (!ha)
+ {
+ size += sprintf(buffer, "Can't find adapter for host number %d\n", hostno);
+ if (size > length)
+ {
+ return (size);
+ }
+ else
+ {
+ return (length);
+ }
+ }
+
+ host = ha->host;
+ if (inout == TRUE) /* Has data been written to the file? */
+ {
+ return (qla1280_set_info(buffer, length, host));
+ }
+
+ /* compute number of active devices */
+ no_devices = 0;
+ for (targ_lun = 0; targ_lun < MAX_EQ; targ_lun++)
+ {
+ if( (up = ha->dev[targ_lun]) == NULL )
+ continue;
+ no_devices++;
+ }
+ /* size = 112 * no_devices; */
+ size = 4096;
+ /* round up to the next page */
+
+ /*
+ * if our old buffer is the right size use it otherwise
+ * allocate a new one.
+ */
+ if (qla1280_buffer_size != size)
+ {
+ /* deallocate this buffer and get a new one */
+ if (qla1280_buffer != NULL)
+ {
+ kfree(qla1280_buffer);
+ qla1280_buffer_size = 0;
+ }
+ qla1280_buffer = kmalloc(size, GFP_KERNEL);
+ }
+ if (qla1280_buffer == NULL)
+ {
+ size = sprintf(buffer, "qla1280 - kmalloc error at line %d\n",
+ __LINE__);
+ return size;
+ }
+ qla1280_buffer_size = size;
+
+ size = 0;
+ size += sprintf(PROC_BUF, "Qlogic 1280/1080 SCSI driver version: "); /* 43 bytes */
+ size += sprintf(PROC_BUF, "%5s, ", QLA1280_VERSION); /* 5 */
+ size += sprintf(PROC_BUF, "Qlogic Firmware version: "); /* 25 */
+ size += sprintf(PROC_BUF, "%2d.%2d.%2d",_firmware_version[0], /* 8 */
+ ql12_firmware_version[1],
+ ql12_firmware_version[2]);
+ size += sprintf(PROC_BUF, "\n"); /* 1 */
+
+ size += sprintf(PROC_BUF, "SCSI Host Adapter Information: %s\n", QLBoardTbl[ha->devnum].bdName);
+ size += sprintf(PROC_BUF, "Request Queue = 0x%lx, Response Queue = 0x%lx\n",
+ ha->request_dma,
+ ha->response_dma);
+ size += sprintf(PROC_BUF, "Request Queue count= 0x%x, Response Queue count= 0x%x\n",
+ REQUEST_ENTRY_CNT,
+ RESPONSE_ENTRY_CNT);
+ size += sprintf(PROC_BUF,"Number of pending commands = 0x%lx\n", ha->actthreads);
+ size += sprintf(PROC_BUF,"Number of queued commands = 0x%lx\n", ha->qthreads);
+ size += sprintf(PROC_BUF,"Number of free request entries = %d\n",ha->req_q_cnt);
+ size += sprintf(PROC_BUF, "\n"); /* 1 */
+
+ size += sprintf(PROC_BUF, "Attached devices:\n");
+ /* scan for all equipment stats */
+ for (targ_lun = 0; targ_lun < MAX_EQ; targ_lun++)
+ {
+ if( (up = ha->dev[targ_lun]) == NULL )
+ continue;
+ if( up->io_cnt == 0 )
+ {
+ size += sprintf(PROC_BUF,"(%2d:%2d:%2d) No stats\n",LUN_ID);
+ continue;
+ }
+ /* total reads since boot */
+ /* total writes since boot */
+ /* total requests since boot */
+ size += sprintf(PROC_BUF, "Total requests %ld,",up->io_cnt);
+ /* current number of pending requests */
+ size += sprintf(PROC_BUF, "(%2d:%2d:%2d) pending requests %d,",LUN_ID,up->q_outcnt);
+ /* avg response time */
+ size += sprintf(PROC_BUF, "Avg response time %ld%%,",(up->resp_time/up->io_cnt)*100);
+
+ /* avg active time */
+ size += sprintf(PROC_BUF, "Avg active time %ld%%\n",(up->act_time/up->io_cnt)*100);
+ }
+
+ if (size >= qla1280_buffer_size)
+ {
+ printk(KERN_WARNING "qla1280: Overflow buffer in qla1280_proc.c\n");
+ }
+
+ if (offset > size - 1)
+ {
+ kfree(qla1280_buffer);
+ qla1280_buffer = NULL;
+ qla1280_buffer_size = length = 0;
+ *start = NULL;
+ }
+ else
+ {
+ *start = &qla1280_buffer[offset]; /* Start of wanted data */
+ if (size - offset < length)
+ {
+ length = size - offset;
+ }
+ }
+#endif
+
+ return (length);
+}
+
+
+/**************************************************************************
+ * 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)
+{
+ int num_hosts = 0;
+ struct Scsi_Host *host;
+ scsi_qla_host_t *ha, *cur_ha;
+ struct _qlaboards *bdp;
+ int i, j;
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,1,95)
+ unsigned int piobase;
+ unsigned char pci_bus, pci_devfn, pci_irq;
+ config_reg_t *cfgp = 0;
+#endif
+ device_reg_t *reg;
+ char *cp;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95)
+ struct pci_dev *pdev = NULL;
+#else
+ int index;
+#endif
+
+ ENTER("qla1280_detect");
+
+#ifdef CHECKSRBSIZE
+ if (sizeof(srb_t) > sizeof(Scsi_Pointer) )
+ {
+ printk("Redefine SRB - its too big");
+ return 0;
+ }
+#endif
+
+#ifdef MODULE
+ DEBUG(sprintf(debug_buff,"DEBUG: qla1280_detect starts at address = %p\n",qla1280_detect);)
+ DEBUG(qla1280_print(debug_buff);)
+ /*
+ * 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);
+ if(dummy_buffer[0] != 'P')
+ printk(KERN_WARNING "qla1280: Please read the file /usr/src/linux/drivers"
+ "/scsi/README.qla1280\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 ((int) !pcibios_present())
+ {
+ printk("scsi: PCI not present\n");
+ return 0;
+ } /* end of IF */
+ bdp = &QLBoardTbl[0];
+ qla1280_hostlist = NULL;
+#if 0
+ template->proc_dir = &proc_scsi_qla1280;
+#else
+ template->proc_name = "qla1280";
+#endif
+
+ /* Try and find each different type of adapter we support */
+ for( i=0; bdp->device_id != 0 && i < NUM_OF_ISP_DEVICES; i++, bdp++ ) {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95)
+ while ((pdev = pci_find_device(QLA1280_VENDOR_ID,
+ bdp->device_id, pdev ) ))
+#else
+ while (!(pcibios_find_device(QLA1280_VENDOR_ID,
+ bdp->device_id,
+ index++, &pci_bus, &pci_devfn)) )
+#endif
+ {
+ /* found a adapter */
+ host = scsi_register(template, sizeof(scsi_qla_host_t));
+ ha = (scsi_qla_host_t *) host->hostdata;
+ /* Clear our data area */
+ for( j =0, cp = (char *)ha; j < sizeof(scsi_qla_host_t); j++)
+ *cp = 0;
+ /* Sanitize the information from PCI BIOS. */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95)
+ host->irq = pdev->irq;
+/* this depends on release 2.3.18 */
+ host->io_port = pdev->resource[0].start;
+/* MRS host->io_port = (unsigned int) pdev->base_address[0]; */
+ ha->pci_bus = pdev->bus->number;
+ ha->pci_device_fn = pdev->devfn;
+ ha->pdev = pdev;
+#else
+ pcibios_read_config_byte(pci_bus, pci_devfn, OFFSET(cfgp->interrupt_line), &pci_irq);
+ pcibios_read_config_dword(pci_bus, pci_devfn, OFFSET(cfgp->base_port), &piobase);
+ host->irq = pci_irq;
+ host->io_port = (unsigned int) piobase;
+ ha->pci_bus = pci_bus;
+ ha->pci_device_fn = pci_devfn;
+#endif
+ ha->device_id = bdp->device_id;
+ host->io_port &= PCI_BASE_ADDRESS_IO_MASK;
+
+ ha->devnum = i;
+ host->io_port &= PCI_BASE_ADDRESS_IO_MASK;
+ if( qla1280_mem_alloc(ha) ) {
+ printk(KERN_INFO "qla1280: Failed to allocate memory for adapter\n");
+ }
+
+ ha->ports = bdp->numPorts;
+ ha->iobase = (device_reg_t *) host->io_port;
+ ha->host = host;
+ ha->host_no = host->host_no;
+
+ /* load the F/W, read paramaters, and init the H/W */
+ if (qla1280_initialize_adapter(ha))
+ {
+
+ printk(KERN_INFO "qla1280: Failed to initialized adapter\n");
+ qla1280_mem_free(ha);
+ scsi_unregister(host);
+ continue;
+ }
+
+ host->max_channel = bdp->numPorts-1;
+ ha->instance = num_hosts;
+ /* Register our resources with Linux */
+ if( qla1280_register_with_Linux(ha, bdp->numPorts-1) ) {
+ printk(KERN_INFO "qla1280: Failed to register our resources\n");
+ qla1280_mem_free(ha);
+ scsi_unregister(host);
+ continue;
+ }
+
+
+ reg = ha->iobase;
+ /* Disable ISP interrupts. */
+ qla1280_disable_intrs(ha);
+
+ /* 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);
+
+ /* Enable chip interrupts. */
+ qla1280_enable_intrs(ha);
+
+ /* Insert new entry into the list of adapters */
+ ha->next = NULL;
+ 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_register_with_Linux
+*
+* Description:
+* Free the passed in Scsi_Host memory structures prior to unloading the
+* module.
+*
+* Input:
+* ha - pointer to host adapter structure
+* maxchannels - MAX number of channels.
+*
+* Returns:
+* 0 - Sucessfully reserved resources.
+* 1 - Failed to reserved a resource.
+**************************************************************************/
+STATIC uint8_t qla1280_register_with_Linux(scsi_qla_host_t *ha, uint8_t maxchannels)
+{
+
+ struct Scsi_Host *host = ha->host;
+
+ host->can_queue = 0xfffff; /* unlimited */
+ host->cmd_per_lun = 1;
+ host->select_queue_depths = qla1280_select_queue_depth;
+ host->n_io_port = 0xFF;
+ host->base = (unsigned long) ha->mmpbase;
+ host->max_channel = maxchannels;
+ host->max_lun = MAX_LUNS-1;
+ host->unique_id = ha->instance;
+ host->max_id = MAX_TARGETS;
+ host->unique_id = ha->instance;
+
+ /* set our host ID (need to do something about our two IDs) */
+ host->this_id = ha->bus_settings[0].id;
+ /* Register the IRQ with Linux (sharable) */
+ if ( request_irq(host->irq, qla1280_intr_handler, SA_INTERRUPT| SA_SHIRQ, "qla1280", ha))
+ {
+ printk("qla1280 : Failed to reserved interrupt %d already in use\n", host->irq);
+ qla1280_mem_free(ha);
+ scsi_unregister(host);
+ return 1;
+ }
+
+ /* Register the I/O space with Linux */
+ if (check_region(host->io_port, 0xff))
+ {
+ printk("qla1280 : Failed to reserved i/o region 0x%04lx-0x%04lx already in use\n",
+ host->io_port, host->io_port + 0xff);
+ free_irq(host->irq, NULL);
+ qla1280_mem_free(ha);
+ scsi_unregister(host);
+ return 1;
+ }
+
+ request_region(host->io_port, 0xff, "qla1280");
+
+ return 0;
+}
+
+
+/**************************************************************************
+ * qla1280_release
+ * Free the passed in Scsi_Host memory structures prior to unloading the
+ * module.
+ **************************************************************************/
+int
+qla1280_release(struct Scsi_Host *host)
+{
+ scsi_qla_host_t *ha = (scsi_qla_host_t *) 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);
+
+ /* release io space registers */
+ if( host->io_port )
+ release_region(host->io_port, 0xff);
+
+#if MEMORY_MAPPED_IO
+ if(ha->mmpbase)
+ {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
+ vfree((void *) (((unsigned long) ha->mmpbase) & PAGE_MASK));
+#else
+ iounmap((void *) (((unsigned long) ha->mmpbase) & PAGE_MASK));
+#endif
+ }
+#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_buffer[125];
+ char *bp;
+ scsi_qla_host_t *ha;
+ qla_boards_t *bdp;
+
+ bp = &qla1280_buffer[0];
+ ha = (scsi_qla_host_t *)host->hostdata;
+ bdp = &QLBoardTbl[ha->devnum];
+ memset(bp, 0, sizeof(qla1280_buffer));
+ sprintf(bp,
+ "QLogic %sPCI to SCSI Host Adapter: bus %d device %d irq %d\n"
+ " Firmware version: %2d.%02d.%02d, Driver version %s",
+ (char *)&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 *))
+{
+ scsi_qla_host_t *ha;
+ srb_t *sp;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+ unsigned long cpu_flags = 0;
+#endif
+ struct Scsi_Host *host;
+ uint32_t b, t, l;
+ scsi_lu_t *q;
+ u_long handle;
+
+ ENTER("qla1280_queuecommand");
+ COMTRACE('C')
+
+ host = cmd->host;
+ ha = (scsi_qla_host_t *) 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;
+ }
+
+ DEBUG5(qla1280_print_scsi_cmd(cmd));
+
+ /* Generate LU queue on bus, target, LUN */
+ b = SCSI_BUS_32(cmd);
+ t = SCSI_TCN_32(cmd);
+ l = SCSI_LUN_32(cmd);
+ if((q = LU_Q(ha, b, t, l)) == NULL )
+ {
+ DRIVER_LOCK
+ if( (q = (scsi_lu_t *)KMALLOC(sizeof(struct scsi_lu))) )
+ {
+ LU_Q(ha, b, t, l) = q;
+ BZERO(q,sizeof(struct scsi_lu));
+ DEBUG(sprintf(debug_buff,"Allocate new device queue 0x%x\n",q));
+ DEBUG(qla1280_print(debug_buff));
+ DRIVER_UNLOCK
+ }
+ else
+ {
+ CMD_RESULT(cmd) = (int) (DID_BUS_BUSY << 16);
+ qla1280_done_q_put(sp, &ha->done_q_first, &ha->done_q_last);
+ queue_task(&ha->run_qla_bh,&tq_scheduler);
+ ha->flags.dpc_sched = TRUE;
+ DRIVER_UNLOCK
+ return(0);
+ }
+ }
+ /* Set an invalid handle until we issue the command to ISP */
+ /* then we will set the real handle value. */
+ handle = INVALID_HANDLE;
+ CMD_HANDLE(cmd) = (unsigned char *)handle;
+
+ /* Bookkeeping information */
+ sp->r_start = jiffies; /* time the request was recieved */
+ sp->u_start = 0;
+
+ /* add the command to our queue */
+ ha->qthreads++;
+ qla1280_putq_t(q,sp);
+
+ DEBUG(sprintf(debug_buff,"qla1280_queuecmd: queue pid=%d, hndl=0x%x\n\r",cmd->pid,handle));
+ DEBUG(qla1280_print(debug_buff));
+
+ /* send command to adapter */
+ DRIVER_LOCK
+ if (q->q_outcnt == 0)
+ qla1280_restart_queues(ha);
+ DRIVER_UNLOCK
+
+
+ LEAVE("qla1280_queuecommand");
+ return (0);
+}
+
+/**************************************************************************
+ * qla1200_abort
+ * Abort the speciifed SCSI command(s).
+ **************************************************************************/
+int
+qla1280_abort(Scsi_Cmnd *cmd)
+{
+ scsi_qla_host_t *ha;
+ srb_t *sp;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+ unsigned long cpu_flags = 0;
+#endif
+ struct Scsi_Host *host;
+ uint32_t b, t, l;
+ scsi_lu_t *q;
+ int return_status = SCSI_ABORT_SUCCESS;
+ int found = 0;
+ int i;
+ u_long handle;
+ u_short data;
+
+ ENTER("qla1280_abort");
+ COMTRACE('A')
+ ha = (scsi_qla_host_t *) cmd->host->hostdata;
+ host = cmd->host;
+ DRIVER_LOCK
+
+ /* Get the SCSI request ptr */
+ sp = (srb_t *) CMD_SP(cmd);
+ handle = (u_long) CMD_HANDLE(cmd);
+ if (qla1280_verbose)
+ printk("scsi(%d): ABORT Command=0x%lx, handle=0x%lx\n",(int)ha->host_no,(long)cmd,handle);
+
+ /* Check for pending interrupts. */
+ if( handle == 0L )
+ {
+ COMTRACE('a')
+ /* we never got this command */
+ printk(KERN_INFO "qla1280: Aborting a NULL handle\n");
+ DRIVER_UNLOCK
+ return(SCSI_ABORT_NOT_RUNNING); /* no action - we don't have command */
+ }
+ data = qla1280_debounce_register(&ha->iobase->istatus);
+ if( !(ha->flags.in_isr) && (data & RISC_INT) )
+ {
+ /* put any pending command in done queue */
+ qla1280_isr(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last);
+ }
+
+ handle = (u_long) CMD_HANDLE(cmd);
+
+ /* Generate LU queue on bus, target, LUN */
+ b = SCSI_BUS_32(cmd);
+ t = SCSI_TCN_32(cmd);
+ l = SCSI_LUN_32(cmd);
+ if((q = LU_Q(ha, b, t, l)) == NULL )
+ {
+ COMTRACE('a')
+ /* No lun queue -- command must not be active */
+ DRIVER_UNLOCK
+ printk(KERN_WARNING "qla1280 (%d:%d:%d): No LUN queue for the specified device\n",(int)b,(int)t,(int)l);
+ return(SCSI_ABORT_NOT_RUNNING); /* no action - we don't have command */
+ }
+
+#if AUTO_ESCALATE_ABORT
+ if ( (sp->flags & SRB_ABORTED) )
+ {
+ DRIVER_UNLOCK
+ DEBUG(qla1280_print("qla1280_abort: Abort escalayted - returning SCSI_ABORT_SNOOZE.\n\r"));
+ return(SCSI_ABORT_SNOOZE);
+ }
+#endif
+
+ if ( (sp->flags & SRB_ABORT_PENDING) )
+ {
+ COMTRACE('a')
+ DRIVER_UNLOCK
+ if( qla1280_verbose )
+ printk("scsi(): Command has a pending abort message - ABORT_PENDING.\n");
+ DEBUG(qla1280_print("qla1280: Command has a pending abort message - ABORT_PENDING.\n\r"));
+ return(SCSI_ABORT_PENDING);
+ }
+
+#if STOP_ON_ABORT
+ printk("Scsi layer issued a ABORT command= 0x%x\n",(int)cmd);
+ DEBUG2(qla1280_print_scsi_cmd(cmd));
+#endif
+
+ ha->flags.in_abort = TRUE;
+ /*
+ * 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("scsi(): Command returned from queue aborted.\n");
+ DEBUG(qla1280_print("qla1280: Command returned from queue aborted.\n\r"));
+ /* 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++;
+ DEBUG(qla1280_print("qla1280: RISC aborting command.\n\r"));
+ 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 */
+
+ DEBUG(sprintf(debug_buff, "qla1280_abort: Aborted status returned = 0x%x.\n\r",return_status));
+ DEBUG(qla1280_print(debug_buff));
+
+ if( ha->done_q_first )
+ qla1280_done(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last);
+ if ( found )
+ {
+ qla1280_restart_queues(ha);
+ }
+ ha->flags.in_abort = FALSE;
+ DRIVER_UNLOCK
+
+ LEAVE("qla1280_abort");
+ COMTRACE('a')
+ 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)
+{
+ scsi_qla_host_t *ha;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+ unsigned long cpu_flags = 0;
+#endif
+ uint32_t b, t, l;
+ 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;
+ u_short data;
+ scsi_lu_t *q;
+ int result;
+
+
+ ENTER("qla1280_reset");
+ COMTRACE('R')
+ if (qla1280_verbose)
+ printk("scsi(): Resetting Cmnd=0x%lx, Handle=0x%lx, flags=0x%x\n",(long)cmd,(long)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 = (scsi_qla_host_t *) cmd->host->hostdata;
+ sp = (srb_t *) CMD_SP(cmd);
+
+#if STOP_ON_RESET
+ qla1280_panic("qla1280_reset",ha->host);
+#endif
+
+ DRIVER_LOCK
+ /* Check for pending interrupts. */
+ data = qla1280_debounce_register(&ha->iobase->istatus);
+ if( !(ha->flags.in_isr) && (data & RISC_INT) )
+ {
+ qla1280_isr(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last);
+ }
+ DRIVER_UNLOCK
+
+ /*
+ * Determine the suggested action that the mid-level driver wants
+ * us to perform.
+ */
+ if( CMD_HANDLE(cmd) == (unsigned char *) 0 )
+ {
+ /*
+ * 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;
+ }
+
+ b = SCSI_BUS_32(cmd);
+ t = SCSI_TCN_32(cmd);
+ l = SCSI_LUN_32(cmd);
+ q = LU_Q(ha, b, t, l);
+
+#if AUTO_ESCALATE_RESET
+ if ( (action & DEVICE_RESET) && (q->q_flag & QLA1280_QRESET) )
+ {
+ printk(KERN_INFO "qla1280(%d): Bus device reset already sent to " "device, escalating.\n", (int)ha->host_no);
+ action = BUS_RESET;
+ }
+ if ( (action & DEVICE_RESET) && (sp->flags & SRB_ABORT_PENDING) )
+ {
+ printk(KERN_INFO "qla1280(%d):Have already attempted to reach " "device with abort device\n", (int)ha->host_no);
+ printk(KERN_INFO "qla1280(%d):message, will escalate to BUS " "RESET.\n",(int) 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.
+ */
+ DRIVER_LOCK
+ 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(%d:%d:%d:%d): Queueing abort device command.\n", (int)ha->host_no,(int)b,(int)t,(int)l);
+ qla1280_abort_queue_single(ha,b,t,l,DID_ABORT);
+ if( qla1280_abort_device(ha, b, t, l) == 0)
+ result = SCSI_RESET_PENDING;
+ break;
+
+ case DEVICE_RESET:
+ if (qla1280_verbose)
+ printk(KERN_INFO "scsi(%d:%d:%d:%d): Queueing device reset command.\n",(int) ha->host_no,(int)b,(int)t,(int)l);
+ ha->flags.in_reset = TRUE;
+ for (l = 0; l < MAX_LUNS; l++)
+ qla1280_abort_queue_single(ha,b,t,l,DID_ABORT);
+ if( qla1280_device_reset(ha, b, t) == 0 )
+ result = SCSI_RESET_PENDING;
+ q->q_flag |= QLA1280_QRESET;
+ break;
+
+ case BUS_RESET:
+ if (qla1280_verbose)
+ printk(KERN_INFO "qla1280(%d:%d:%d:%d): Issuing BUS DEVICE RESET.\n",(int) ha->host_no,(int)b,(int)t,(int)l);
+ ha->flags.in_reset = TRUE;
+ for (t = 0; t < MAX_TARGETS; t++)
+ for (l = 0; l < MAX_LUNS; l++)
+ qla1280_abort_queue_single(ha,b,t,l,DID_RESET);
+ qla1280_bus_reset(ha, b);
+ /*
+ * 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;
+ mdelay(4 * 1000); barrier();
+ if( flags & SCSI_RESET_SYNCHRONOUS )
+ {
+ CMD_RESULT(cmd) = (int) (DID_BUS_BUSY << 16);
+ (*(cmd)->scsi_done)(cmd);
+ }
+ /* ha->reset_start = jiffies; */
+ break;
+
+ case ADAPTER_RESET:
+ default:
+ if (qla1280_verbose)
+ {
+ printk(KERN_INFO "scsi(%d:%d:%d:%d): Issued an ADAPTER RESET.\n",(int) ha->host_no,(int)b,(int)t,(int)l);
+ printk(KERN_INFO "scsi(%d:%d:%d:%d): I/O processing will continue automatically.\n",(int) ha->host_no,(int)b,(int)t,(int)l);
+ }
+ 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, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last);
+ qla1280_restart_queues(ha);
+ ha->flags.in_reset = FALSE;
+
+DRIVER_UNLOCK
+ DEBUG(printk("RESET returning %d\n", result));
+
+ COMTRACE('r')
+ LEAVE("qla1280_reset");
+ return( result );
+}
+
+/**************************************************************************
+ * qla1200_biosparam
+ * Return the disk geometry for the given SCSI device.
+ **************************************************************************/
+int
+qla1280_biosparam(Disk *disk, kdev_t dev, int geom[])
+{
+ int heads, sectors, cylinders;
+
+ heads = 64;
+ sectors = 32;
+ cylinders = disk->capacity / (heads * sectors);
+ if (cylinders > 1024)
+ {
+ heads = 255;
+ sectors = 63;
+ cylinders = disk->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)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,95)
+ unsigned long cpu_flags = 0;
+#endif
+ scsi_qla_host_t *ha;
+ u_short data;
+ device_reg_t *reg;
+
+ ENTER_INTR("qla1280_intr_handler");
+ COMTRACE('I')
+ ha = (scsi_qla_host_t *) dev_id;
+ if(!ha)
+ {
+ printk(KERN_INFO "scsi(): Interrupt with NULL host ptr\n");
+ COMTRACE('X')
+ return;
+ }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,95)
+ spin_lock_irqsave(&io_request_lock, cpu_flags);
+ if(test_and_set_bit(QLA1280_IN_ISR_BIT, &ha->flags))
+ {
+ COMTRACE('X')
+ return;
+ }
+ ha->isr_count++;
+ reg = ha->iobase;
+ /* disable our interrupt. */
+ WRT_REG_WORD(®->ictrl, 0);
+ data = qla1280_debounce_register(®->istatus);
+ /* Check for pending interrupts. */
+ if ( !(data & RISC_INT) )
+ {
+ /* spurious interrupts can happen legally */
+ DEBUG(printk("scsi(%d): Spurious interrupt - ignoring\n",(int)ha->host_no));
+ COMTRACE('X')
+ }
+ else
+ qla1280_isr(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last);
+ if (ha->done_q_first)
+ qla1280_done(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last);
+
+ clear_bit(QLA1280_IN_ISR_BIT, &ha->flags);
+ spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) */
+
+ if( test_bit(QLA1280_IN_ISR_BIT, (int *)&ha->flags) )
+ {
+ COMTRACE('X')
+ printk(KERN_INFO "scsi(%d): Already in interrupt - returning \n", (int)ha->host_no);
+ return;
+ }
+ set_bit(QLA1280_IN_ISR_BIT, (int *)&ha->flags);
+ ha->isr_count++;
+ reg = ha->iobase;
+ /* disable our interrupt. */
+ WRT_REG_WORD(®->ictrl, 0);
+
+ data = qla1280_debounce_register(®->istatus);
+ /* Check for pending interrupts. */
+ if ( !(data & RISC_INT) )
+ {
+ /* spurious interrupts can happen legally */
+ DEBUG(printk("scsi(%d): Spurious interrupt - ignoring\n",(int)ha->host_no));
+ COMTRACE('X')
+ }
+ else
+ qla1280_isr(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last);
+
+ /* if no work to do then call the SCSI mid-level right away */
+ if( ha->done_q_first )
+ qla1280_done(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last);
+
+ /* Schedule the DPC routine */
+ if (ha->flags.isp_abort_needed || ha->flags.reset_marker ||
+ ha->done_q_first )
+ {
+ ha->run_qla_bh.data = (void *) ha;
+ ha->run_qla_bh.routine = qla1280_do_dpc;
+
+ COMTRACE('P')
+ queue_task_irq(&ha->run_qla_bh,&tq_scheduler);
+ ha->flags.dpc_sched = TRUE;
+ }
+ clear_bit(QLA1280_IN_ISR_BIT, (int *)&ha->flags);
+#endif
+ /* enable our interrupt. */
+ WRT_REG_WORD(®->ictrl, ISP_EN_INT + ISP_EN_RISC);
+
+ COMTRACE('i')
+ 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)
+{
+ scsi_qla_host_t *ha = (scsi_qla_host_t *) p;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95)
+ unsigned long cpu_flags = 0;
+#endif
+
+ COMTRACE('p')
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95)
+ spin_lock_irqsave(&io_request_lock, cpu_flags);
+#endif
+ 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, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last);
+ ha->flags.dpc_sched = FALSE;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95)
+ spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+#endif
+}
+
+/**************************************************************************
+ * qla1280_device_queue_depth
+ *
+ * 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 void qla1280_device_queue_depth(scsi_qla_host_t *p, Scsi_Device *device)
+{
+ int default_depth = 3;
+ int bus = device->channel;
+ int target = device->id;
+
+ device->queue_depth = default_depth;
+
+ if (device->tagged_supported &&
+ (p->bus_settings[bus].qtag_enables & (BIT_0 << target)) )
+ {
+ device->tagged_queue = 1;
+ device->current_tag = 0;
+ device->queue_depth = p->bus_settings[bus].hiwat;
+ /* device->queue_depth = 20; */
+ printk(KERN_INFO "scsi(%d:%d:%d:%d): Enabled tagged queuing, queue depth %d.\n",
+ (int)p->host_no, device->channel, device->id,
+ device->lun, device->queue_depth);
+ }
+ qla12160_get_target_parameters(p, bus, target, device->lun);
+
+}
+
+/**************************************************************************
+ * qla1280_select_queue_depth
+ *
+ * Sets the queue depth for each SCSI device hanging off the input
+ * host adapter. We use a queue depth of 2 for devices that do not
+ * support tagged queueing.
+ **************************************************************************/
+STATIC void
+qla1280_select_queue_depth(struct Scsi_Host *host, Scsi_Device *scsi_devs)
+{
+ Scsi_Device *device;
+ scsi_qla_host_t *p = (scsi_qla_host_t *) host->hostdata;
+
+ ENTER("qla1280_select_queue_depth");
+ for (device = scsi_devs; device != NULL; device = device->next)
+ {
+ if (device->host == host)
+ qla1280_device_queue_depth(p, device);
+ }
+ LEAVE("qla1280_select_queue_depth");
+}
+
+/*--------------------------**
+** Driver Support Routines **
+**--------------------------*/
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
+/*
+ * mdelay
+ * Delay in milliseconds
+ *
+ * Input:
+ * milliseconds = delay
+ */
+STATIC inline void mdelay(int milliseconds)
+{
+ int i;
+
+ for(i=0; i<milliseconds; i++)
+ udelay(1000);
+}
+#endif
+
+/*
+ * 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(scsi_qla_host_t *ha, srb_t **done_q_first, srb_t **done_q_last)
+{
+ srb_t *sp;
+ scsi_lu_t *q;
+ uint32_t b, t, l;
+ Scsi_Cmnd *cmd;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+ unsigned long cpu_flags = 0;
+#endif
+
+ ENTER("qla1280_done");
+ COMTRACE('D')
+
+ DRIVER_LOCK
+ 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;
+ b = SCSI_BUS_32(cmd);
+ t = SCSI_TCN_32(cmd);
+ l = SCSI_LUN_32(cmd);
+ q = LU_Q(ha, b, t, l);
+
+ /* Decrement outstanding commands on device. */
+ if (q->q_outcnt)
+ q->q_outcnt--;
+ if (q->q_outcnt < ha->bus_settings[b].hiwat)
+ {
+ q->q_flag &= ~QLA1280_QBUSY;
+ }
+
+ q->resp_time += jiffies - sp->r_start; /* Lun bookkeeping information */
+ q->act_time += jiffies - sp->u_start;
+ 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, b, t, 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;
+ }
+
+ /* Call the mid-level driver interrupt handler */
+ CMD_HANDLE(sp->cmd) = (unsigned char *) 0;
+ ha->actthreads--;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+ sti();
+ (*(cmd)->scsi_done)(cmd);
+ cli();
+#else
+ (*(cmd)->scsi_done)(cmd);
+#endif
+ qla1280_next(ha, q, b);
+ }
+ DRIVER_UNLOCK
+
+
+ COMTRACE('d')
+ 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
+ /*
+ DEBUG(printk("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:
+#ifdef QL_DEBUG_LEVEL_2
+ printk("Data overrun 0x%x\n",(int)sts->residual_length);
+ qla1280_print(
+ "\n\rqla1280_isr: response packet data\n\r");
+ qla1280_dump_buffer((caddr_t)sts,
+ RESPONSE_ENTRY_SIZE);
+#endif
+ host_status = DID_ERROR;
+ break;
+ case CS_DATA_UNDERRUN:
+ if ( (CMD_XFRLEN(cp) - sts->residual_length) < cp->underflow)
+ {
+ printk("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
+ sprintf(debug_buff, "qla1280 ISP status: host status (%s) scsi status %x\n\r", reason[host_status], sts->scsi_status);
+ qla1280_print(debug_buff);
+#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)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+ unsigned long cpu_flags = 0;
+#endif
+#ifdef QL_DEBUG_LEVEL_3
+ ENTER("qla1280_put_done_q");
+#endif
+ /* Place block on done queue */
+ DRIVER_LOCK
+ 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;
+
+ DRIVER_UNLOCK
+#ifdef QL_DEBUG_LEVEL_3
+ LEAVE("qla1280_put_done_q");
+#endif
+}
+
+/*
+ * qla1280_next
+ * Retrieve and process next job in the queue.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ * q = SCSI LU pointer.
+ * b = SCSI bus number.
+ * SCSI_LU_Q lock must be already obtained and no other locks.
+ *
+ * Output:
+ * Releases SCSI_LU_Q upon exit.
+ */
+STATIC void
+qla1280_next(scsi_qla_host_t *ha, scsi_lu_t *q, uint8_t b)
+{
+ srb_t *sp;
+ uint32_t cnt;
+ uint8_t status;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+ unsigned long cpu_flags = 0;
+#endif
+
+ ENTER("qla1280_next");
+
+ DRIVER_LOCK
+ while ( ((sp = q->q_first) != NULL) && /* we have a queue pending */
+ !(q->q_flag & QLA1280_QBUSY) && /* device not busy */
+ !ha->flags.abort_isp_active && /* not resetting the adapter */
+ !(q->q_flag & QLA1280_QSUSP) ) /* device not suspended */
+ {
+ /* Remove srb from SCSI LU queue. */
+ qla1280_removeq(q, sp);
+
+ DEBUG(sprintf(debug_buff,"starting request 0x%p<-(0x%p)\n\r",q,sp));
+ DEBUG(qla1280_print(debug_buff));
+ {
+ /* Set busy flag if reached high water mark. */
+ q->q_outcnt++;
+ if (q->q_outcnt >= ha->bus_settings[b].hiwat)
+ q->q_flag |= QLA1280_QBUSY;
+
+#if QLA1280_64BIT_SUPPORT
+ 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)
+ {
+ /* Release SCSI LU queue specific lock */
+ QLA1280_SCSILU_UNLOCK(q);
+
+ /* Wait for 30 sec for command to be accepted. */
+ for (cnt = 6000000; cnt; cnt--)
+ {
+#if QLA1280_64BIT_SUPPORT
+ 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);
+
+ SYS_DELAY(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
+ COMTRACE('M')
+ CMD_HANDLE(sp->cmd) = (unsigned char *) 0;
+
+ /* Call the mid-level driver interrupt handler */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+ sti();
+ (*(sp->cmd)->scsi_done)(sp->cmd);
+ cli();
+#else
+ (*(sp->cmd)->scsi_done)(sp->cmd);
+#endif
+
+ /* Acquire LU queue specific lock */
+ QLA1280_SCSILU_LOCK(q);
+
+ if (q->q_outcnt)
+ q->q_outcnt--;
+ }
+ else
+ /* Acquire LU queue specific lock */
+ QLA1280_SCSILU_LOCK(q);
+ }
+ 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[b].hiwat)
+ q->q_flag &= ~QLA1280_QBUSY;
+ break;
+ }
+ }
+ }
+ }
+ DRIVER_UNLOCK
+
+ /* Release SCSI LU queue specific lock */
+ QLA1280_SCSILU_UNLOCK(q);
+
+ 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_Q lock must be already obtained.
+ */
+STATIC void
+qla1280_putq_t(scsi_lu_t *q, srb_t *sp)
+{
+ srb_t *srb_p;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+ unsigned long cpu_flags = 0;
+#endif
+
+#ifdef QL_DEBUG_LEVEL_3
+ ENTER("qla1280_putq_t");
+#endif
+ DRIVER_LOCK
+ DEBUG(sprintf(debug_buff,"Adding to device 0x%p<-(0x%p)\n\r",q,sp));
+ DEBUG(qla1280_print(debug_buff));
+ sp->s_next = NULL;
+ if (!q->q_first) /* If queue empty */
+ {
+ sp->s_prev = NULL;
+ q->q_first = sp;
+ q->q_last = sp;
+ }
+ else
+ {
+ srb_p = q->q_first;
+ while (srb_p )
+ srb_p = srb_p->s_next;
+
+ if (srb_p)
+ {
+ sp->s_prev = srb_p->s_prev;
+ if (srb_p->s_prev)
+ srb_p->s_prev->s_next = sp;
+ else
+ q->q_first = sp;
+ srb_p->s_prev = sp;
+ sp->s_next = srb_p;
+ }
+ else
+ {
+ sp->s_prev = q->q_last;
+ q->q_last->s_next = sp;
+ q->q_last = sp;
+ }
+ }
+
+ DRIVER_UNLOCK
+#ifdef QL_DEBUG_LEVEL_3
+ LEAVE("qla1280_putq_t");
+#endif
+}
+
+/*
+ * qla1280_removeq
+ * Function used to remove a command block from the
+ * LU queue.
+ *
+ * Input:
+ * q = SCSI LU pointer.
+ * sp = srb pointer.
+ * SCSI_LU_Q lock must be already obtained.
+ */
+STATIC void
+qla1280_removeq(scsi_lu_t *q, srb_t *sp)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+ unsigned long cpu_flags = 0;
+#endif
+ DEBUG(sprintf(debug_buff,"Removing from device_q (0x%p)->(0x%p)\n\r",q,sp));
+ DEBUG(qla1280_print(debug_buff));
+ DRIVER_LOCK
+ 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;
+ DRIVER_UNLOCK
+}
+
+/*
+* qla1280_mem_alloc
+* Allocates adapter memory.
+*
+* Returns:
+* 0 = success.
+* 1 = failure.
+*/
+STATIC uint8_t
+qla1280_mem_alloc(scsi_qla_host_t *ha)
+{
+
+ uint8_t status = 1;
+
+#ifdef QL_DEBUG_LEVEL_3
+ ENTER("qla1280_mem_alloc");
+#endif
+
+#ifdef DYNAMIC_MEM_ALLOC
+ ha->request_ring = qla1280_alloc_phys(REQUEST_ENTRY_SIZE * REQUEST_ENTRY_CNT,
+ &ha->request_dma);
+ if(ha->request_ring) {
+ ha->response_ring = qla1280_alloc_phys(RESPONSE_ENTRY_SIZE * RESPONSE_ENTRY_CNT,
+ &ha->response_dma);
+ if(ha->response_ring) {
+ status = 0;
+ }
+ }
+#else
+ ha->request_ring = &ha->req[0];
+ ha->request_dma = VIRT_TO_BUS(&ha->req[0]);
+ ha->response_ring = &ha->res[0];
+ ha->response_dma = VIRT_TO_BUS(&ha->res[0]);
+ status = 0;
+#endif
+
+ if(status) {
+#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3)
+ qla1280_print("qla1280_mem_alloc: **** FAILED ****\n");
+#endif
+ }
+#ifdef QL_DEBUG_LEVEL_3
+ else
+ LEAVE("qla1280_mem_alloc");
+#endif
+ return(status);
+}
+
+/*
+ * qla1280_mem_free
+ * Frees adapter allocated memory.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ */
+STATIC void
+qla1280_mem_free(scsi_qla_host_t *ha)
+{
+ scsi_lu_t *q;
+ uint32_t b, t, l;
+
+ ENTER("qlc1280_mem_free");
+ if (ha)
+ {
+ /* Free device queues. */
+ for (b = 0; b < MAX_BUSES; b++)
+ {
+ q = LU_Q(ha, b, ha->bus_settings[b].id, 0);
+ for (t = 0; t < MAX_TARGETS; t++)
+ for (l = 0; l < MAX_LUNS; l++)
+ if (LU_Q(ha, b, t, l) != NULL && LU_Q(ha, b, t, l) != q)
+ KMFREE(LU_Q(ha, b, t, l),sizeof(struct scsi_lu));
+ KMFREE(q, sizeof(struct scsi_lu));
+ }
+ for( b =0; b < MAX_EQ; b++ )
+ ha->dev[b] = (scsi_lu_t *)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(scsi_qla_host_t *ha) {
+ device_reg_t *reg;
+
+ reg = ha->iobase;
+ ha->flags.interrupts_on = 1;
+ /* enable risc and host interrupts */
+ WRT_REG_WORD(®->ictrl, (ISP_EN_INT+ ISP_EN_RISC));
+ }
+
+ static inline void qla1280_disable_intrs(scsi_qla_host_t *ha) {
+ device_reg_t *reg;
+
+ reg = ha->iobase;
+ ha->flags.interrupts_on = 0;
+ /* disable risc and host interrupts */
+ WRT_REG_WORD(®->ictrl, 0);
+ }
+
+/*
+ * qla1280_initialize_adapter
+ * Initialize board.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ *
+ * Returns:
+ * 0 = success
+ */
+STATIC uint8_t
+qla1280_initialize_adapter(scsi_qla_host_t *ha)
+{
+ device_reg_t *reg;
+ uint8_t status;
+ /* uint8_t cnt; */
+ uint8_t b;
+
+#ifdef QL_DEBUG_LEVEL_3
+ ENTER("qla1280_initialize_adapter");
+#endif
+
+ /* 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.watchdog_enabled = FALSE;
+
+ DEBUG(printk("Configure PCI space for adapter...\n"));
+ if (!(status = qla1280_pci_config(ha)))
+ {
+ reg = ha->iobase;
+
+ /* Disable ISP interrupts. */
+ WRT_REG_WORD(®->ictrl, 0);
+
+ /* 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("scsi(%d): Determining if RISC is loaded...\n",(int)ha->host_no);
+ if (qla1280_isp_firmware(ha))
+ {
+ if (qla1280_verbose)
+ printk("scsi(%d): Verifying chip...\n",(int)ha->host_no);
+ if (!(status = qla1280_chip_diag(ha)))
+ {
+ if (qla1280_verbose)
+ printk("scsi(%d): Setup chip...\n",(int)ha->host_no);
+ status = qla1280_setup_chip(ha);
+ }
+ }
+
+ if (!status)
+ {
+ /* Setup adapter based on NVRAM parameters. */
+ if (qla1280_verbose)
+ printk("scsi(%d): Configure NVRAM parameters...\n",(int)ha->host_no);
+ qla1280_nvram_config(ha);
+
+ if (!ha->flags.disable_host_adapter &&
+ !qla1280_init_rings(ha))
+ {
+ /* Issue SCSI reset. */
+ for (b = 0; b < ha->ports; b++)
+ if (!ha->bus_settings[b].disable_scsi_reset)
+ {
+ /* dg 03/13 if we can't reset twice then bus is dead */
+ if( qla1280_bus_reset(ha, b) )
+ if( qla1280_bus_reset(ha, b) )
+ {
+ ha->bus_settings[b].scsi_bus_dead = TRUE;
+ }
+ }
+
+ do
+ {
+ /* Issue marker command. */
+ ha->flags.reset_marker = FALSE;
+ for (b = 0; b < ha->ports; b++)
+ {
+ ha->bus_settings[b].reset_marker = FALSE;
+ qla1280_marker(ha, b, 0, 0, MK_SYNC_ALL);
+ }
+ }while (ha->flags.reset_marker);
+
+ ha->flags.online = TRUE;
+
+ /* Enable host adapter target mode. */
+ for (b = 0; b < ha->ports; b++)
+ {
+ if (!(status = qla1280_enable_tgt(ha, b)))
+ {
+ /* for (cnt = 0; cnt < MAX_LUNS; cnt++)
+ {
+ qla1280_enable_lun(ha, b, cnt);
+ qla1280_poll(ha);
+ }*/
+ }
+ else
+ break;
+ }
+ }
+ else
+ status = 1;
+ }
+ }
+
+#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3)
+ if (status)
+ qla1280_print("qla1280_initialize_adapter: **** FAILED ****\n\r");
+#endif
+#ifdef QL_DEBUG_LEVEL_3
+ else
+ LEAVE("qla1280_initialize_adapter");
+#endif
+ return(status);
+}
+
+/*
+ * qla1280_enable_tgt
+ * Enable target mode.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ * b = SCSI bus number.
+ *
+ * Returns:
+ * 0 = success.
+ */
+STATIC uint8_t
+qla1280_enable_tgt(scsi_qla_host_t *ha, uint8_t b)
+{
+ uint8_t status = 0;
+ /* uint16_t mb[MAILBOX_REGISTER_COUNT]; */
+
+#ifdef QL_DEBUG_LEVEL_3
+ qla1280_print("qla1280_enable_tgt: entered\n\r");
+#endif
+
+ /* Enable target mode. */
+ /*
+ mb[0] = MBC_ENABLE_TARGET_MODE;
+ mb[1] = BIT_15;
+ mb[2] = (uint16_t)(b << 15);
+ status = qla1280_mailbox_command(ha, BIT_2|BIT_1|BIT_0, &mb[0]);
+ */
+#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3)
+ if (status)
+ qla1280_print("qla1280_enable_tgt: **** FAILED ****\n\r");
+#endif
+#ifdef QL_DEBUG_LEVEL_3
+ else
+ qla1280_print("qla1280_enable_tgt: exiting normally\n\r");
+#endif
+ 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 uint8_t
+qla1280_isp_firmware(scsi_qla_host_t *ha)
+{
+ nvram_t *nv = (nvram_t *)ha->response_ring;
+ uint16_t *wptr;
+ uint8_t chksum;
+ uint8_t cnt;
+ uint8_t status = 0; /* dg 2/27 always loads RISC */
+ uint16_t mb[MAILBOX_REGISTER_COUNT];
+
+ ENTER("qla1280_isp_firmware");
+
+ /* Verify valid NVRAM checksum. */
+ wptr = (uint16_t *)ha->response_ring;
+ DEBUG(printk("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++;
+ }
+ DEBUG(printk("qla1280_isp_firmware: Completed Reading NVRAM\n"));
+
+#if defined(QL_DEBUG_LEVEL_3)
+ sprintf(debug_buff,"qla1280_isp_firmware: NVRAM Magic ID= %c %c %c\n\r",(char *) nv->id[0],nv->id[1],nv->id[2]);
+ qla1280_print(debug_buff);
+#endif
+
+ /* 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)
+ {
+#if defined(QL_DEBUG_LEVEL_3)
+ qla1280_print("qla1280_isp_firmware: Telling RISC to verify checksum of loaded BIOS code.\n\r");
+#endif
+ /* Verify checksum of loaded RISC code. */
+ mb[0] = MBC_VERIFY_CHECKSUM;
+ /* mb[1] = ql12_risc_code_addr01; */
+ mb[1] = *QLBoardTbl[ha->devnum].fwstart;
+
+ if (!(status = qla1280_mailbox_command(ha, BIT_1|BIT_0, &mb[0])))
+ {
+ /* Start firmware execution. */
+#if defined(QL_DEBUG_LEVEL_3)
+ qla1280_print("qla1280_isp_firmware: Startng F/W execution.\n\r");
+#endif
+ mb[0] = MBC_EXECUTE_FIRMWARE;
+ /* mb[1] = ql12_risc_code_addr01; */
+ mb[1] = *QLBoardTbl[ha->devnum].fwstart;
+ qla1280_mailbox_command(ha, BIT_1|BIT_0, &mb[0]);
+ }
+ else
+ printk(KERN_INFO "qla1280: RISC checksum failed.\n");
+ }
+ else
+ {
+ DEBUG(printk("qla1280: NVRAM configured to load RISC load.\n"));
+ status = 1;
+ }
+
+#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3)
+ if (status)
+ qla1280_print(
+ "qla1280_isp_firmware: **** Load RISC code ****\n\r");
+#endif
+ LEAVE("qla1280_isp_firmware");
+ return(status);
+}
+
+/*
+ * PCI configuration
+ * Setup device PCI configuration registers.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ *
+ * Returns:
+ * 0 = success.
+ */
+STATIC uint8_t
+qla1280_pci_config(scsi_qla_host_t *ha)
+{
+ uint8_t status = 1;
+ uint32_t command;
+#if MEMORY_MAPPED_IO
+ uint32_t page_offset, base;
+ uint32_t mmapbase;
+#endif
+ config_reg_t *creg = 0;
+ uint16_t buf_wd;
+
+ ENTER("qla1280_pci_config");
+
+ /* Get command register. */
+ if (pci_read_config_word(ha->pdev,OFFSET(creg->command), &buf_wd) == PCIBIOS_SUCCESSFUL)
+ {
+ command = buf_wd;
+ /*
+ * Set Bus Master Enable, Memory Address Space Enable and
+ * reset any error bits.
+ */
+ buf_wd &= ~0x7;
+#if MEMORY_MAPPED_IO
+ DEBUG(printk("qla1280: MEMORY MAPPED IO is enabled.\n"));
+ buf_wd |= BIT_2 + BIT_1 + BIT_0;
+#else
+ buf_wd |= BIT_2 + BIT_0;
+#endif
+ if( pci_write_config_word(ha->pdev,OFFSET(creg->command), buf_wd) )
+ {
+ printk(KERN_WARNING "qla1280: Could not write config word.\n");
+ }
+ /* Get expansion ROM address. */
+ if (pci_read_config_word(ha->pdev,OFFSET(creg->expansion_rom), &buf_wd) == PCIBIOS_SUCCESSFUL)
+ {
+ /* Reset expansion ROM address decode enable. */
+ buf_wd &= ~BIT_0;
+ if (pci_write_config_word(ha->pdev,OFFSET(creg->expansion_rom), buf_wd) == PCIBIOS_SUCCESSFUL)
+ {
+#if MEMORY_MAPPED_IO
+ /* Get memory mapped I/O address. */
+ pci_read_config_dword(ha->pdev,OFFSET(cfgp->mem_base_addr), &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. */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+ ha->mmpbase = ioremap_nocache(base, page_offset + 256);
+#else
+ ha->mmpbase = vremap(base,page_offset + 256);
+#endif
+ 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 uint8_t
+qla1280_chip_diag(scsi_qla_host_t *ha)
+{
+ device_reg_t *reg = ha->iobase;
+ uint8_t status = 0;
+ uint16_t data;
+ uint32_t cnt;
+ uint16_t mb[MAILBOX_REGISTER_COUNT];
+
+#ifdef QL_DEBUG_LEVEL_3
+ sprintf(debug_buff, "qla1280_chip_diag: testing device at 0x%p \n\r",®->id_l);
+ qla1280_print(debug_buff);
+#endif
+
+ /* Soft reset chip and wait for it to finish. */
+ WRT_REG_WORD(®->ictrl, ISP_RESET);
+ data = qla1280_debounce_register(®->ictrl);
+ for (cnt = 6000000; cnt && data & ISP_RESET; cnt--)
+ {
+ SYS_DELAY(5);
+ data = RD_REG_WORD(®->ictrl);
+ }
+ if (cnt)
+ {
+ /* Reset register not cleared by chip reset. */
+#if defined(QL_DEBUG_LEVEL_3)
+ qla1280_print("qla1280_chip_diag: reset register cleared by chip reset\n\r");
+#endif
+ 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);
+ for (cnt = 6000000; cnt && data == MBS_BUSY; cnt--)
+ {
+ SYS_DELAY(5);
+ data = RD_REG_WORD(®->mailbox0);
+ }
+
+ if (cnt)
+ {
+ /* Check product ID of chip */
+#if defined(QL_DEBUG_LEVEL_3)
+ qla1280_print("qla1280_chip_diag: Checking product ID of chip\n\r");
+#endif
+ 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
+ {
+ DEBUG(printk("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)
+ status = 1;
+ if (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 defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3)
+ if (status)
+ qla1280_print("qla1280_chip_diag: **** FAILED ****\n\r");
+#endif
+#ifdef QL_DEBUG_LEVEL_3
+ else
+ qla1280_print("qla1280_chip_diag: exiting normally\n\r");
+#endif
+ return(status);
+}
+
+/*
+ * Setup chip
+ * Load and start RISC firmware.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ *
+ * Returns:
+ * 0 = success.
+ */
+STATIC uint8_t
+qla1280_setup_chip(scsi_qla_host_t *ha)
+{
+ uint8_t status = 0;
+ uint16_t risc_address;
+ uint16_t *risc_code_address;
+ long risc_code_size;
+ uint16_t mb[MAILBOX_REGISTER_COUNT];
+#ifdef QLA1280_UNUSED
+ int i;
+#endif
+ uint16_t cnt;
+ int num;
+ uint8_t *tbuf, *sp;
+ u_long p_tbuf;
+ int i;
+
+#ifdef QL_DEBUG_LEVEL_3
+ ENTER("qla1280_setup_chip");
+#endif
+
+ if( (tbuf = (uint8_t *)KMALLOC(8000) ) == NULL )
+ {
+ printk("setup_chip: couldn't alloacte memory\n");
+ return(1);
+ }
+ p_tbuf = VIRT_TO_BUS(tbuf);
+ /* Load RISC code. */
+ /*
+ risc_address = ql12_risc_code_addr01;
+ risc_code_address = &ql12_risc_code01[0];
+ risc_code_size = ql12_risc_code_length01;
+ */
+ risc_address = *QLBoardTbl[ha->devnum].fwstart;
+ risc_code_address = QLBoardTbl[ha->devnum].fwcode;
+ risc_code_size = (long)(*QLBoardTbl[ha->devnum].fwlen & 0xffff);
+
+ DEBUG(printk("qla1280: DMAing RISC code (%d) words.\n",(int)risc_code_size));
+ DEBUG(sprintf(debug_buff,"qla1280_setup_chip: Loading RISC code size =(%ld).\n\r",risc_code_size);)
+ DEBUG(qla1280_print(debug_buff));
+ num =0;
+ while (risc_code_size > 0 && !status)
+ {
+ cnt = 2000 >> 1;
+
+ if ( cnt > risc_code_size )
+ cnt = risc_code_size;
+
+ DEBUG(sprintf(debug_buff,"qla1280_setup_chip: loading risc @ =(0x%p),%d,%d(0x%x).\n\r",risc_code_address,cnt,num,risc_address);)
+ DEBUG(qla1280_print(debug_buff));
+ printk("qla1280_setup_chip: loading risc @ =code=(0x%p),cnt=%d,seg=%d,addr=0x%x\n\r",risc_code_address,cnt,num,risc_address);
+ BCOPY((caddr_t) risc_code_address,(caddr_t) ha->request_ring, (cnt <<1));
+ mb[0] = MBC_LOAD_RAM;
+ /* mb[0] = MBC_LOAD_RAM_A64; */
+ mb[1] = risc_address;
+ mb[4] = cnt;
+ mb[3] = (uint16_t) ha->request_dma & 0xffff;
+ mb[2] = (uint16_t) (ha->request_dma >> 16) & 0xffff;
+ mb[7] = (uint16_t) (MS_64BITS(ha->request_dma) & 0xffff);
+ mb[6] = (uint16_t) (MS_64BITS(ha->request_dma) >> 16) & 0xffff;
+ printk("qla1280_setup_chip: op=%d 0x%lx = 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("Failed to load partial segment of f/w\n");
+ break;
+ }
+ /* dump it back */
+
+#if 0
+ mb[0] = MBC_DUMP_RAM_A64;
+ mb[1] = risc_address;
+ mb[4] = cnt;
+ mb[3] = (uint16_t) p_tbuf & 0xffff;
+ mb[2] = (uint16_t) (p_tbuf >> 16) & 0xffff;
+ mb[7] = (uint16_t) (p_tbuf >> 32) & 0xffff;
+ mb[6] = (uint16_t) (p_tbuf >> 48) & 0xffff;
+
+ if( (status = qla1280_mailbox_command(ha, BIT_4|BIT_3|BIT_2|BIT_1|BIT_0,
+ &mb[0])) )
+ {
+ printk("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("qla1280 : firmware compare error @ byte (0x%x)\n",i);
+ break;
+ }
+ }
+
+#endif
+ risc_address += cnt;
+ risc_code_size = risc_code_size - cnt;
+ risc_code_address = risc_code_address + cnt;
+ num++;
+ }
+#ifdef QLA1280_UNUSED
+ DEBUG(ql_debug_print = 0;)
+ {
+ for (i = 0; i < ql12_risc_code_length01; i++)
+ {
+ mb[0] = 0x4;
+ mb[1] = ql12_risc_code_addr01 + i;
+ mb[2] = ql12_risc_code01[i];
+
+ status = qla1280_mailbox_command(ha, BIT_2|BIT_1|BIT_0,
+ &mb[0]);
+ if (status)
+ {
+ printk("qla1280 : firmware load failure\n");
+ break;
+ }
+
+ mb[0] = 0x5;
+ mb[1] = ql12_risc_code_addr01 + i;
+ mb[2] = 0;
+
+ status = qla1280_mailbox_command(ha, BIT_2|BIT_1|BIT_0,
+ &mb[0]);
+ if (status)
+ {
+ printk("qla1280 : firmware dump failure\n");
+ break;
+ }
+ if( mb[2] != ql12_risc_code01[i] )
+ printk("qla1280 : firmware compare error @ (0x%x)\n",ql12_risc_code_addr01+i);
+ }
+ }
+ DEBUG(ql_debug_print = 1;)
+#endif
+
+ /* Verify checksum of loaded RISC code. */
+ if (!status)
+ {
+ DEBUG(printk("qla1280_setup_chip: Verifying checksum of loaded RISC code.\n");)
+ mb[0] = MBC_VERIFY_CHECKSUM;
+ /* mb[1] = ql12_risc_code_addr01; */
+ mb[1] = *QLBoardTbl[ha->devnum].fwstart;
+
+ if (!(status = qla1280_mailbox_command(ha, BIT_1|BIT_0, &mb[0])))
+ {
+ /* Start firmware execution. */
+ DEBUG(qla1280_print("qla1280_setup_chip: start firmware running.\n\r");)
+ mb[0] = MBC_EXECUTE_FIRMWARE;
+ /* mb[1] = ql12_risc_code_addr01; */
+ mb[1] = *QLBoardTbl[ha->devnum].fwstart;
+ qla1280_mailbox_command(ha, BIT_1|BIT_0, &mb[0]);
+ }
+ else
+ printk("qla1280_setup_chip: Failed checksum.\n");
+ }
+
+ KMFREE(tbuf,8000);
+
+#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3)
+ if (status)
+ qla1280_print("qla1280_setup_chip: **** FAILED ****\n\r");
+#endif
+#ifdef QL_DEBUG_LEVEL_3
+ else
+ LEAVE("qla1280_setup_chip");
+#endif
+ 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 uint8_t
+qla1280_init_rings(scsi_qla_host_t *ha)
+{
+ uint8_t status = 0;
+ uint16_t cnt;
+ uint16_t mb[MAILBOX_REGISTER_COUNT];
+
+#ifdef QL_DEBUG_LEVEL_3
+ ENTER("qla1280_init_rings");
+#endif
+ /* 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] = (uint16_t)LS_64BITS(ha->request_dma);
+ mb[2] = (uint16_t)( LS_64BITS(ha->request_dma) >> 16);
+ mb[4] = 0;
+ mb[7] = (uint16_t)MS_64BITS(ha->request_dma);
+ mb[6] = (uint16_t)( MS_64BITS(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] = (uint16_t)LS_64BITS(ha->response_dma);
+ mb[2] = (uint16_t)(LS_64BITS(ha->response_dma) >> 16);
+ mb[5] = 0;
+ mb[7] = (uint16_t)MS_64BITS(ha->response_dma);
+ mb[6] = (uint16_t)(MS_64BITS(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 defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3)
+ if (status)
+ qla1280_print("qla1280_init_rings: **** FAILED ****\n\r");
+#endif
+#ifdef QL_DEBUG_LEVEL_3
+ else
+ LEAVE("qla1280_init_rings");
+#endif
+ 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 uint8_t
+qla1280_nvram_config(scsi_qla_host_t *ha)
+{
+ device_reg_t *reg = ha->iobase;
+ nvram_t *nv = (nvram_t *)ha->response_ring;
+ uint8_t status = 0;
+ uint32_t b, t, l;
+ uint16_t *wptr;
+ uint16_t mb[MAILBOX_REGISTER_COUNT];
+ uint8_t cnt;
+ uint8_t chksum;
+ uint32_t nvsize;
+
+#if defined(QL_DEBUG_ROUTINES) && !defined(QL_DEBUG_LEVEL_4)
+ uint8_t saved_print_status = ql_debug_print;
+#endif
+ ENTER("qla1280_nvram_config");
+#if defined(QL_DEBUG_ROUTINES) && !defined(QL_DEBUG_LEVEL_4)
+ ql_debug_print = FALSE;
+#endif
+
+ /* Verify valid NVRAM checksum. */
+#if USE_NVRAM_DEFAULTS
+ chksum = 1;
+#else
+ wptr = (uint16_t *)ha->response_ring;
+ chksum = 0;
+ if( ha->device_id == QLA12160_DEVICE_ID ||
+ ha->device_id == QLA10160_DEVICE_ID )
+ 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
+ DEBUG(printk("Using defaults for NVRAM\n"));
+#else
+ DEBUG(printk("Using defaults for NVRAM: \n"));
+ DEBUG(printk("checksum=0x%x, Id=%c, version=0x%x\n",chksum,nv->id[0],nv->version));
+#if defined(QL_DEBUG_LEVEL_3)
+ /* ql_debug_print = 1;
+ qla1280_dump_buffer((caddr_t)ha->response_ring, REQUEST_ENTRY_SIZE);
+ ql_debug_print = 0; */
+#endif
+ wptr = (uint16_t *)ha->response_ring;
+ for (cnt = 0; cnt < sizeof(nvram_t)/2; cnt++)
+ *wptr++ = 0;
+#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 (b = 0; b < MAX_BUSES; b++)
+ {
+ nv->bus[b].config_1.initiator_id = 7;
+ nv->bus[b].bus_reset_delay = 5;
+ nv->bus[b].config_2.async_data_setup_time = 9;
+ nv->bus[b].config_2.req_ack_active_negation = 1;
+ nv->bus[b].config_2.data_line_active_negation = 1;
+ nv->bus[b].selection_timeout = 250;
+ nv->bus[b].max_queue_depth = 256;
+
+ for (t = 0; t < MAX_TARGETS; t++)
+ {
+ nv->bus[b].target[t].parameter.f.auto_request_sense = 1;
+ nv->bus[b].target[t].parameter.f.disconnect_allowed = 1;
+ nv->bus[b].target[t].parameter.f.tag_queuing = 1;
+ nv->bus[b].target[t].flags.device_enable = 1;
+ }
+ }
+
+#if USE_NVRAM_DEFAULTS
+ status = 0;
+#else
+ status = 1;
+#endif
+ }
+ else
+ {
+ /* Always force AUTO sense for LINUX SCSI */
+ for (b = 0; b < MAX_BUSES; b++)
+ for (t = 0; t < MAX_TARGETS; t++)
+ {
+ nv->bus[b].target[t].parameter.f.auto_request_sense = 1;
+ }
+ }
+#if DEBUG_PRINT_NVRAM
+ ql_debug_print = 1;
+ sprintf(debug_buff,"qla1280 : initiator scsi id bus[0]=%d\n\r",
+ nv->bus[0].config_1.initiator_id);
+ qla1280_print(debug_buff);
+ sprintf(debug_buff,"qla1280 : initiator scsi id bus[1]=%d\n\r",
+ nv->bus[1].config_1.initiator_id);
+ qla1280_print(debug_buff);
+
+ sprintf(debug_buff,"qla1280 : bus reset delay[0]=%d\n\r",
+ nv->bus[0].bus_reset_delay);
+ qla1280_print(debug_buff);
+ sprintf(debug_buff,"qla1280 : bus reset delay[1]=%d\n\r",
+ nv->bus[1].bus_reset_delay);
+ qla1280_print(debug_buff);
+
+ sprintf(debug_buff,"qla1280 : retry count[0]=%d\n\r",
+ nv->bus[0].retry_count);
+ qla1280_print(debug_buff);
+ sprintf(debug_buff,"qla1280 : retry delay[0]=%d\n\r",
+ nv->bus[0].retry_delay);
+ qla1280_print(debug_buff);
+ sprintf(debug_buff,"qla1280 : retry count[1]=%d\n\r",
+ nv->bus[1].retry_count);
+ qla1280_print(debug_buff);
+ sprintf(debug_buff,"qla1280 : retry delay[1]=%d\n\r",
+ nv->bus[1].retry_delay);
+ qla1280_print(debug_buff);
+
+ sprintf(debug_buff,"qla1280 : async data setup time[0]=%d\n\r",
+ nv->bus[0].config_2.async_data_setup_time);
+ qla1280_print(debug_buff);
+ sprintf(debug_buff,"qla1280 : async data setup time[1]=%d\n\r",
+ nv->bus[1].config_2.async_data_setup_time);
+ qla1280_print(debug_buff);
+
+ sprintf(debug_buff,"qla1280 : req/ack active negation[0]=%d\n\r",
+ nv->bus[0].config_2.req_ack_active_negation);
+ qla1280_print(debug_buff);
+ sprintf(debug_buff,"qla1280 : req/ack active negation[1]=%d\n\r",
+ nv->bus[1].config_2.req_ack_active_negation);
+ qla1280_print(debug_buff);
+
+ sprintf(debug_buff,"qla1280 : data line active negation[0]=%d\n\r",
+ nv->bus[0].config_2.data_line_active_negation);
+ qla1280_print(debug_buff);
+ sprintf(debug_buff,"qla1280 : data line active negation[1]=%d\n\r",
+ nv->bus[1].config_2.data_line_active_negation);
+ qla1280_print(debug_buff);
+
+
+ sprintf(debug_buff,"qla1280 : disable loading risc code=%d\n\r",
+ nv->cntr_flags_1.disable_loading_risc_code);
+ qla1280_print(debug_buff);
+
+ sprintf(debug_buff,"qla1280 : enable 64bit addressing=%d\n\r",
+ nv->cntr_flags_1.enable_64bit_addressing);
+ qla1280_print(debug_buff);
+
+ sprintf(debug_buff,"qla1280 : selection timeout limit[0]=%d\n\r",
+ nv->bus[0].selection_timeout);
+ qla1280_print(debug_buff);
+ sprintf(debug_buff,"qla1280 : selection timeout limit[1]=%d\n\r",
+ nv->bus[1].selection_timeout);
+
+ qla1280_print(debug_buff);
+ sprintf(debug_buff,"qla1280 : max queue depth[0]=%d\n\r",
+ nv->bus[0].max_queue_depth);
+ qla1280_print(debug_buff);
+ sprintf(debug_buff,"qla1280 : max queue depth[1]=%d\n\r",
+ nv->bus[1].max_queue_depth);
+ qla1280_print(debug_buff);
+#endif
+
+ DEBUG(ql_debug_print = 0;)
+
+ /* Disable RISC load of firmware. */
+ ha->flags.disable_risc_code_load =
+ nv->cntr_flags_1.disable_loading_risc_code;
+ /* Enable 64bit addressing. */
+ ha->flags.enable_64bit_addressing =
+ nv->cntr_flags_1.enable_64bit_addressing;
+
+ /* 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 (b = 0; b < ha->ports; b++)
+ {
+ /* SCSI Reset Disable. */
+ ha->bus_settings[b].disable_scsi_reset = nv->bus[b].config_1.scsi_reset_disable;
+
+ /* Initiator ID. */
+ ha->bus_settings[b].id = nv->bus[b].config_1.initiator_id;
+ mb[0] = MBC_SET_INITIATOR_ID;
+ mb[1] = b ? ha->bus_settings[b].id | BIT_7 : ha->bus_settings[b].id;
+ status |= qla1280_mailbox_command(ha, BIT_1|BIT_0, &mb[0]);
+
+ /* Reset Delay. */
+ ha->bus_settings[b].bus_reset_delay = nv->bus[b].bus_reset_delay;
+
+ /* Command queue depth per device. */
+ ha->bus_settings[b].hiwat = nv->bus[b].max_queue_depth - 1;
+
+ /* Set target parameters. */
+ for (t = 0; t < MAX_TARGETS; t++)
+ {
+ if( ha->device_id == QLA12160_DEVICE_ID ||
+ ha->device_id == QLA10160_DEVICE_ID )
+ {
+ status = qla12160_set_target_parameters(ha,b,t,0,(nvram160_t *)nv);
+ }
+ else
+ {
+ /* Set Target Parameters. */
+ mb[0] = MBC_SET_TARGET_PARAMETERS;
+ mb[1] = (uint16_t)(b ? t | BIT_7 :t);
+ mb[1] <<= 8;
+ mb[2] = nv->bus[b].target[t].parameter.c << 8;
+ mb[2] |= TP_AUTO_REQUEST_SENSE;
+ mb[2] &= ~TP_STOP_QUEUE;
+ mb[3] = nv->bus[b].target[t].flags.sync_offset << 8;
+ mb[3] |= nv->bus[b].target[t].sync_period;
+ status |= qla1280_mailbox_command(ha, BIT_3|BIT_2|BIT_1|BIT_0,
+ &mb[0]);
+ }
+
+ /* Save Tag queuing enable flag. */
+ mb[0] = BIT_0 << t;
+ if (nv->bus[b].target[t].parameter.f.tag_queuing)
+ ha->bus_settings[b].qtag_enables |= mb[0];
+
+ /* Save Device enable flag. */
+ if (nv->bus[b].target[t].flags.device_enable)
+ ha->bus_settings[b].device_enables |= mb[0];
+
+ /* Save LUN disable flag. */
+ if (nv->bus[b].target[t].flags.lun_disable)
+ ha->bus_settings[b].lun_disables |= mb[0];
+
+ /* Set Device Queue Parameters. */
+ for (l = 0; l < MAX_LUNS; l++)
+ {
+ mb[0] = MBC_SET_DEVICE_QUEUE;
+ mb[1] = (uint16_t)(b ? t | BIT_7 :t);
+ mb[1] = mb[1] << 8 | l;
+ mb[2] = nv->bus[b].max_queue_depth;
+ mb[3] = nv->bus[b].target[t].execution_throttle;
+ status |= qla1280_mailbox_command(ha, BIT_3|BIT_2|BIT_1|BIT_0,
+ &mb[0]);
+ }
+ }
+ }
+ DEBUG(ql_debug_print = 0;)
+
+#if defined(QL_DEBUG_ROUTINES) && !defined(QL_DEBUG_LEVEL_4)
+ ql_debug_print = saved_print_status;
+#endif
+
+#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3)
+ DEBUG(if (status))
+ DEBUG(qla1280_print("qla1280_nvram_config: **** FAILED ****\n\r");)
+#endif
+ 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(scsi_qla_host_t *ha, uint32_t address)
+{
+ uint32_t nv_cmd;
+ uint16_t data;
+
+#ifdef QL_DEBUG_ROUTINES
+ uint8_t saved_print_status = ql_debug_print;
+#endif
+#ifdef QL_DEBUG_LEVEL_4
+ ENTER("qla1280_get_nvram_word");
+#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
+
+#ifdef QL_DEBUG_LEVEL_4
+ qla1280_print("qla1280_get_nvram_word: exiting normally NVRAM data = ");
+ qla1280_output_number((uint32_t)data, 16);
+ qla1280_print("\n\r");
+#endif
+ 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(scsi_qla_host_t *ha, uint32_t nv_cmd)
+{
+ uint8_t cnt;
+ device_reg_t *reg = ha->iobase;
+ 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);
+ /* qla1280_nv_delay(ha); */
+ 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);
+ /* qla1280_nv_delay(ha); */
+ NVRAM_DELAY();
+ }
+
+ /* Deselect chip. */
+
+ WRT_REG_WORD(®->nvram, NV_DESELECT);
+ /* qla1280_nv_delay(ha); */
+ NVRAM_DELAY();
+
+ return(data);
+}
+
+STATIC void
+qla1280_nv_write(scsi_qla_host_t *ha, uint16_t data)
+{
+ device_reg_t *reg = ha->iobase;
+
+ WRT_REG_WORD(®->nvram, data | NV_SELECT);
+ NVRAM_DELAY();
+ /* qla1280_nv_delay(ha); */
+ WRT_REG_WORD(®->nvram, data | NV_SELECT | NV_CLOCK);
+ /* qla1280_nv_delay(ha); */
+ NVRAM_DELAY();
+ WRT_REG_WORD(®->nvram, data | NV_SELECT);
+ /* qla1280_nv_delay(ha); */
+ NVRAM_DELAY();
+}
+
+STATIC void
+qla1280_nv_delay(scsi_qla_host_t *ha)
+{
+ device_reg_t *reg = ha->iobase;
+ int cnt = NV_DELAY_COUNT;
+ uint16_t data = 0;
+
+ while (cnt--)
+ data |= RD_REG_WORD(®->nvram);
+}
+
+/*
+ * 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 uint8_t
+qla1280_mailbox_command(scsi_qla_host_t *ha, uint8_t mr, uint16_t *mb)
+{
+ device_reg_t *reg = ha->iobase;
+ uint8_t status = 0;
+ uint32_t cnt;
+ uint16_t *optr, *iptr;
+ uint16_t data;
+ srb_t *done_q_first = 0;
+ srb_t *done_q_last = 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+ unsigned long cpu_flags = 0;
+#endif
+
+#ifdef QL_DEBUG_LEVEL_3
+ ENTER("qla1280_mailbox_command");
+#endif
+
+ /* Acquire interrupt specific lock */
+ QLA1280_INTR_LOCK(ha);
+ DRIVER_LOCK
+ ha->flags.mbox_busy = TRUE;
+
+ /* 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;
+ WRT_REG_WORD(®->host_cmd, HC_SET_HOST_INT);
+ data = qla1280_debounce_register(®->istatus);
+
+ /* Wait for 30 seconds for command to finish. */
+ for (cnt = 30000000; cnt > 0 && !ha->flags.mbox_int; cnt--)
+ {
+ /* Check for pending interrupts. */
+ if (data & RISC_INT)
+ {
+ qla1280_isr(ha, (srb_t **)&done_q_first, (srb_t **)&done_q_last);
+ }
+ SYS_DELAY(1);
+ data = RD_REG_WORD(®->istatus);
+ }
+
+ /* Check for mailbox command timeout. */
+ if ( !cnt )
+ {
+#ifdef QL_DEBUG_LEVEL_2
+ qla1280_print(
+ "qla1280_mailbox_command: **** Command Timeout, mailbox0 = ");
+ qla1280_output_number((uint32_t)mb[0], 16);
+ qla1280_print(" ****\n\r");
+#endif
+ 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;
+ while (mr--)
+ *optr++ = *iptr++;
+
+ /* Go check for any response interrupts pending. */
+ ha->flags.mbox_busy = FALSE;
+ qla1280_isr(ha, (srb_t **)&done_q_first, (srb_t **)&done_q_last);
+
+ /* Release interrupt specific lock */
+ QLA1280_INTR_UNLOCK(ha);
+ DRIVER_UNLOCK
+
+ 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, (srb_t **)&done_q_first, (srb_t **)&done_q_last);
+
+#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3)
+ if (status)
+ {
+ qla1280_print("qla1280_mailbox_command: **** FAILED, mailbox0 = ");
+ qla1280_output_number((uint32_t)mb[0], 16);
+ qla1280_print(" ****\n\r");
+ }
+#endif
+#ifdef QL_DEBUG_LEVEL_3
+ else
+ LEAVE("qla1280_mailbox_command");
+#endif
+ return(status);
+}
+
+/*
+ * qla1280_poll
+ * Polls ISP for interrupts.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ */
+STATIC void
+qla1280_poll(scsi_qla_host_t *ha)
+{
+ device_reg_t *reg = ha->iobase;
+ uint16_t data;
+ srb_t *done_q_first = 0;
+ srb_t *done_q_last = 0;
+
+#ifdef QL_DEBUG_LEVEL_3
+ /* ENTER("qla1280_poll"); */
+#endif
+
+ /* Acquire interrupt specific lock */
+ QLA1280_INTR_LOCK(ha);
+
+ /* Check for pending interrupts. */
+ data = RD_REG_WORD(®->istatus);
+ if (data & RISC_INT)
+ qla1280_isr(ha, (srb_t **)&done_q_first, (srb_t **)&done_q_last);
+
+ /* Release interrupt specific lock */
+ QLA1280_INTR_UNLOCK(ha);
+
+ 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, (srb_t **)&done_q_first, (srb_t **)&done_q_last);
+
+#ifdef QL_DEBUG_LEVEL_3
+ /* LEAVE("qla1280_poll"); */
+#endif
+}
+
+/*
+ * qla1280_bus_reset
+ * Issue SCSI bus reset.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ * b = SCSI bus number.
+ *
+ * Returns:
+ * 0 = success
+ */
+STATIC uint8_t
+qla1280_bus_reset(scsi_qla_host_t *ha, uint8_t b)
+{
+ uint8_t status;
+ uint16_t mb[MAILBOX_REGISTER_COUNT];
+
+#ifdef QL_DEBUG_LEVEL_3
+ qla1280_print("qla1280_bus_reset: entered\n\r");
+#endif
+ if( qla1280_verbose )
+ {
+ printk("scsi(%d): Resetting SCSI BUS (%d)\n",(int)ha->host_no,b);
+ }
+
+ mb[0] = MBC_BUS_RESET;
+ mb[1] = ha->bus_settings[b].bus_reset_delay;
+ mb[2] = (uint16_t)b;
+ status = qla1280_mailbox_command(ha, BIT_2|BIT_1|BIT_0, &mb[0]);
+
+ if (status)
+ {
+ if (ha->bus_settings[b].failed_reset_count > 2) /* dg - 03/13/99 */
+ ha->bus_settings[b].scsi_bus_dead = TRUE;
+ ha->bus_settings[b].failed_reset_count++;
+ }
+ else
+ {
+ QLA1280_DELAY(4);
+ ha->bus_settings[b].scsi_bus_dead = FALSE; /* dg - 03/13/99 */
+ ha->bus_settings[b].failed_reset_count = 0;
+ /* Issue marker command. */
+ qla1280_marker(ha, b, 0, 0, MK_SYNC_ALL);
+ }
+#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3)
+ if (status)
+ qla1280_print("qla1280_bus_reset: **** FAILED ****\n\r");
+#endif
+#ifdef QL_DEBUG_LEVEL_3
+ else
+ qla1280_print("qla1280_bus_reset: exiting normally\n\r");
+#endif
+ return(status);
+}
+
+/*
+ * qla1280_device_reset
+ * Issue bus device reset message to the target.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ * b = SCSI BUS number.
+ * t = SCSI ID.
+ *
+ * Returns:
+ * 0 = success
+ */
+STATIC uint8_t
+qla1280_device_reset(scsi_qla_host_t *ha, uint8_t b, uint32_t t)
+{
+ uint8_t status;
+ uint16_t mb[MAILBOX_REGISTER_COUNT];
+
+#ifdef QL_DEBUG_LEVEL_3
+ ENTER("qla1280_device_reset");
+#endif
+
+ mb[0] = MBC_ABORT_TARGET;
+ mb[1] = (b ? (t | BIT_7) : t) << 8;
+ mb[2] = 1;
+ status = qla1280_mailbox_command(ha, BIT_2|BIT_1|BIT_0, &mb[0]);
+
+ /* Issue marker command. */
+ qla1280_marker(ha, b, t, 0, MK_SYNC_ID);
+
+#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3)
+ if (status)
+ qla1280_print("qla1280_device_reset: **** FAILED ****\n\r");
+#endif
+#ifdef QL_DEBUG_LEVEL_3
+ else
+ LEAVE("qla1280_device_reset");
+#endif
+ return(status);
+}
+
+/*
+ * qla1280_abort_device
+ * Issue an abort message to the device
+ *
+ * Input:
+ * ha = adapter block pointer.
+ * b = SCSI BUS.
+ * t = SCSI ID.
+ * l = SCSI LUN.
+ *
+ * Returns:
+ * 0 = success
+ */
+STATIC uint8_t
+qla1280_abort_device(scsi_qla_host_t *ha, uint8_t b, uint32_t t, uint32_t l)
+{
+ uint8_t status;
+ uint16_t mb[MAILBOX_REGISTER_COUNT];
+
+#ifdef QL_DEBUG_LEVEL_3
+ ENTER("qla1280_abort_device");
+#endif
+
+ mb[0] = MBC_ABORT_DEVICE;
+ mb[1] = (b ? t | BIT_7 : t) << 8 | l;
+ status = qla1280_mailbox_command(ha, BIT_1|BIT_0, &mb[0]);
+
+ /* Issue marker command. */
+ qla1280_marker(ha, b, t, l, MK_SYNC_ID_LUN);
+
+#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3)
+ if (status)
+ qla1280_print("qla1280_abort_device: **** FAILED ****\n\r");
+#endif
+#ifdef QL_DEBUG_LEVEL_3
+ else
+ LEAVE("qla1280_abort_device");
+#endif
+ return(status);
+}
+
+/*
+ * qla1280_abort_command
+ * Abort command aborts a specified IOCB.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ * sp = SB structure pointer.
+ *
+ * Returns:
+ * 0 = success
+ */
+STATIC uint8_t
+qla1280_abort_command(scsi_qla_host_t *ha, srb_t *sp)
+{
+ uint8_t status;
+ uint16_t mb[MAILBOX_REGISTER_COUNT];
+ uint32_t b, t, l;
+ uint32_t handle;
+
+#ifdef QL_DEBUG_LEVEL_3
+ ENTER("qla1280_abort_command");
+#endif
+
+ /* Locate handle number. */
+ for (handle = 0; handle < MAX_OUTSTANDING_COMMANDS; handle++)
+ if (ha->outstanding_cmds[handle] == sp)
+ break;
+
+ b = SCSI_BUS_32(sp->cmd);
+ t = SCSI_TCN_32(sp->cmd);
+ l = SCSI_LUN_32(sp->cmd);
+
+ mb[0] = MBC_ABORT_COMMAND;
+ mb[1] = (b ? t | BIT_7 : t) << 8 | l;
+ mb[2] = handle >> 16;
+ mb[3] = (uint16_t)handle;
+ status = qla1280_mailbox_command(ha, BIT_3|BIT_2|BIT_1|BIT_0, &mb[0]);
+
+#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3)
+ if (status)
+ qla1280_print("qla1280_abort_command: **** FAILED ****\n\r");
+#endif
+ 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(scsi_qla_host_t *ha)
+{
+ device_reg_t *reg = ha->iobase;
+
+#ifdef QL_DEBUG_LEVEL_3
+ ENTER("qla1280_reset_adapter");
+#endif
+
+ /* 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);
+
+#ifdef QL_DEBUG_LEVEL_3
+ LEAVE("qla1280_reset_adapter");
+#endif
+}
+
+/*
+ * Issue marker command.
+ * Function issues marker IOCB.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ * b = SCSI BUS number
+ * t = SCSI ID
+ * l = SCSI LUN
+ * type = marker modifier
+ */
+STATIC void
+qla1280_marker(scsi_qla_host_t *ha, uint8_t b, uint32_t t, uint32_t l, uint8_t type)
+{
+ mrk_entry_t *pkt;
+
+#ifdef QL_DEBUG_LEVEL_3
+ ENTER("qla1280_marker");
+#endif
+
+ /* Get request packet. */
+ if ( (pkt = (mrk_entry_t *)qla1280_req_pkt(ha)) )
+ {
+ pkt->entry_type = MARKER_TYPE;
+ pkt->lun = (uint8_t)l;
+ pkt->target = (uint8_t)(b ? (t | BIT_7) : t);
+ pkt->modifier = type;
+
+ /* Issue command to ISP */
+ qla1280_isp_cmd(ha);
+ }
+
+#ifdef QL_DEBUG_LEVEL_3
+ LEAVE("qla1280_marker");
+#endif
+}
+
+#if QLA1280_64BIT_SUPPORT
+/*
+ * 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 uint8_t
+qla1280_64bit_start_scsi(scsi_qla_host_t *ha, srb_t *sp)
+{
+ device_reg_t *reg = ha->iobase;
+ uint8_t status = 0;
+ Scsi_Cmnd *cmd = sp->cmd;
+ uint32_t cnt;
+ cmd_a64_entry_t *pkt;
+ uint16_t req_cnt;
+ uint16_t seg_cnt;
+ struct scatterlist *sg = (struct scatterlist *) NULL;
+ uint32_t *dword_ptr;
+
+#ifdef QL_DEBUG_LEVEL_3
+ ENTER("qla1280_64bit_start_scsi:");
+#endif
+
+ if( qla1280_check_for_dead_scsi_bus(ha, sp) )
+ {
+ return(0);
+ }
+
+ /* Calculate number of entries and segments required. */
+ seg_cnt = 0;
+ req_cnt = 1;
+ if (cmd->use_sg)
+ {
+ seg_cnt = cmd->use_sg;
+ sg = (struct scatterlist *) cmd->request_buffer;
+
+ if (seg_cnt > 2)
+ {
+ req_cnt += (uint16_t)(seg_cnt - 2) / 5;
+ if ((uint16_t)(seg_cnt - 2) % 5)
+ req_cnt++;
+ }
+ }
+ else if (cmd->request_bufflen) /* If data transfer. */
+ {
+ DEBUG(printk("Single data transfer (0x%x)\n",cmd->request_bufflen));
+ seg_cnt = 1;
+ }
+
+ /* Acquire ring specific lock */
+ QLA1280_RING_LOCK(ha);
+
+ if ((uint16_t)(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 ((uint16_t)(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 *) (u_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. */
+ dword_ptr = (uint32_t *)pkt + 2;
+ for (cnt = 2; cnt < REQUEST_ENTRY_SIZE/4; cnt++)
+ *dword_ptr++ = 0;
+
+ /* Set ISP command timeout. */
+ pkt->timeout = (uint16_t)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);
+ BCOPY(&(CMD_CDBP(cmd)), pkt->scsi_cdb, pkt->cdb_len);
+ DEBUG(printk("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 = (uint32_t *)&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--)
+ {
+ DEBUG(sprintf(debug_buff,"SG Segment ap=0x%p, len=0x%x\n\r",sg->address,sg->length));
+ DEBUG(qla1280_print(debug_buff));
+ *dword_ptr++ = cpu_to_le32(VIRT_TO_BUS_LOW(sg->address));
+ *dword_ptr++ = cpu_to_le32(VIRT_TO_BUS_HIGH(sg->address));
+ *dword_ptr++ = sg->length;
+ sg++;
+ }
+#ifdef QL_DEBUG_LEVEL_5
+ qla1280_print(
+ "qla1280_64bit_start_scsi: Scatter/gather command packet data - ");
+ qla1280_print("b ");
+ qla1280_output_number((uint32_t)SCSI_BUS_32(cmd), 10);
+ qla1280_print(" t ");
+ qla1280_output_number((uint32_t)SCSI_TCN_32(cmd), 10);
+ qla1280_print(" d ");
+ qla1280_output_number((uint32_t)SCSI_LUN_32(cmd), 10);
+ qla1280_print("\n\r");
+ qla1280_dump_buffer((caddr_t)pkt, REQUEST_ENTRY_SIZE);
+#endif
+ /*
+ * Build continuation packets.
+ */
+ 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. */
+ dword_ptr = (uint32_t *)pkt;
+ for (cnt = 0;cnt < REQUEST_ENTRY_SIZE/4; cnt++)
+ *dword_ptr++ = 0;
+
+ /* 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 = (uint32_t *)
+ &((cont_a64_entry_t *)pkt)->dseg_0_address;
+
+ /* Load continuation entry data segments. */
+ for (cnt = 0; cnt < 5 && seg_cnt; cnt++, seg_cnt--)
+ {
+ *dword_ptr++ = cpu_to_le32(VIRT_TO_BUS_LOW(sg->address));
+ *dword_ptr++ = cpu_to_le32(VIRT_TO_BUS_HIGH(sg->address));
+ *dword_ptr++ = sg->length;
+ sg++;
+ }
+#ifdef QL_DEBUG_LEVEL_5
+ qla1280_print(
+ "qla1280_64bit_start_scsi: continuation packet data - c");
+ qla1280_print(" b ");
+ qla1280_output_number((uint32_t)SCSI_BUS_32(cmd), 10);
+
+ qla1280_print(" t ");
+ qla1280_output_number((uint32_t)SCSI_TCN_32(cmd), 10);
+ qla1280_print(" d ");
+ qla1280_output_number((uint32_t)SCSI_LUN_32(cmd), 10);
+ qla1280_print("\n\r");
+ qla1280_dump_buffer((caddr_t)pkt, REQUEST_ENTRY_SIZE);
+#endif
+ }
+ }
+ else /* No scatter gather data transfer */
+ {
+ *dword_ptr++ = cpu_to_le32(VIRT_TO_BUS_LOW(cmd->request_buffer));
+ *dword_ptr++ = cpu_to_le32(VIRT_TO_BUS_HIGH(cmd->request_buffer));
+ *dword_ptr = (uint32_t) cmd->request_bufflen;
+#ifdef QL_DEBUG_LEVEL_5
+ qla1280_print(
+ "qla1280_64bit_start_scsi: No scatter/gather command packet data - c");
+ qla1280_print(" b ");
+ qla1280_output_number((uint32_t)SCSI_BUS_32(cmd), 10);
+ qla1280_print(" t ");
+ qla1280_output_number((uint32_t)SCSI_TCN_32(cmd), 10);
+ qla1280_print(" d ");
+ qla1280_output_number((uint32_t)SCSI_LUN_32(cmd), 10);
+ qla1280_print("\n\r");
+ qla1280_dump_buffer((caddr_t)pkt, REQUEST_ENTRY_SIZE);
+#endif
+ }
+ }
+#ifdef QL_DEBUG_LEVEL_5
+ else /* No data transfer */
+ {
+ *dword_ptr++ = (uint32_t) 0;
+ *dword_ptr++ = (uint32_t) 0;
+ *dword_ptr = (uint32_t) 0;
+ qla1280_print(
+ "qla1280_64bit_start_scsi: No data, command packet data - c");
+ qla1280_print(" b ");
+ qla1280_output_number((uint32_t)SCSI_BUS_32(cmd), 10);
+ qla1280_print(" t ");
+ qla1280_output_number((uint32_t)SCSI_TCN_32(cmd), 10);
+ qla1280_print(" d ");
+ qla1280_output_number((uint32_t)SCSI_LUN_32(cmd), 10);
+ qla1280_print("\n\r");
+ qla1280_dump_buffer((caddr_t)pkt, REQUEST_ENTRY_SIZE);
+ }
+#endif
+ /* 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);
+ }
+ else
+ {
+ status = 1;
+#ifdef QL_DEBUG_LEVEL_2
+ qla1280_print(
+ "qla1280_64bit_start_scsi: NO ROOM IN OUTSTANDING ARRAY\n\r");
+ qla1280_print(" req_q_cnt=");
+ qla1280_output_number((uint32_t)ha->req_q_cnt, 16);
+#endif
+ }
+ }
+ else
+ {
+ status = 1;
+#ifdef QL_DEBUG_LEVEL_2
+ qla1280_print("qla1280_64bit_start_scsi: in-ptr=");
+ qla1280_output_number((uint32_t)ha->req_ring_index, 16);
+ qla1280_print(" req_q_cnt=");
+ qla1280_output_number((uint32_t)ha->req_q_cnt, 16);
+ qla1280_print(" req_cnt=");
+ qla1280_output_number((uint32_t)req_cnt, 16);
+ qla1280_print("\n\r");
+#endif
+ }
+
+ /* Release ring specific lock */
+ QLA1280_RING_UNLOCK(ha);
+
+#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3)
+ if (status)
+ qla1280_print("qla1280_64bit_start_scsi: **** FAILED ****\n\r");
+#endif
+#ifdef QL_DEBUG_LEVEL_3
+ else
+ qla1280_print("qla1280_64bit_start_scsi: exiting normally\n\r");
+#endif
+ return(status);
+}
+#endif /* QLA1280_64BIT_SUPPORT */
+
+/*
+ * 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 uint8_t
+qla1280_32bit_start_scsi(scsi_qla_host_t *ha, srb_t *sp)
+{
+ device_reg_t *reg = ha->iobase;
+ uint8_t status = 0;
+ Scsi_Cmnd *cmd = sp->cmd;
+ uint32_t cnt;
+ cmd_entry_t *pkt;
+ uint16_t req_cnt;
+ uint16_t seg_cnt;
+ struct scatterlist *sg = (struct scatterlist *) NULL;
+ uint8_t *data_ptr;
+ uint32_t *dword_ptr;
+
+ ENTER("qla1280_32bit_start_scsi");
+
+
+ if( qla1280_check_for_dead_scsi_bus(ha, sp) )
+ {
+ return(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.
+ */
+ seg_cnt = cmd->use_sg;
+ sg = (struct scatterlist *) cmd->request_buffer;
+ /*
+ * if greater than four sg entries then we need to allocate
+ * continuation entries
+ */
+ if (seg_cnt > 4)
+ {
+ req_cnt += (uint16_t)(seg_cnt - 4) / 7;
+ if ((uint16_t)(seg_cnt - 4) % 7)
+ req_cnt++;
+ }
+ DEBUG(sprintf(debug_buff,"S/G for data transfer -num segs(%d), req blk cnt(%d)\n\r",seg_cnt,req_cnt));
+ DEBUG(qla1280_print(debug_buff));
+ }
+ else if (cmd->request_bufflen) /* If data transfer. */
+ {
+ DEBUG(printk("Single data transfer (0x%x)\n",cmd->request_bufflen));
+ seg_cnt = 1;
+ }
+ else
+ {
+ DEBUG(printk("No data transfer \n"));
+ seg_cnt = 0;
+ }
+
+ /* Acquire ring specific lock */
+ QLA1280_RING_LOCK(ha);
+
+ if ((uint16_t)(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);
+ }
+
+ DEBUG(sprintf(debug_buff,"Number of free entries = (%d)\n\r",ha->req_q_cnt));
+ DEBUG(qla1280_print(debug_buff));
+ /* If room for request in request ring. */
+ if ((uint16_t)(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. */
+ dword_ptr = (uint32_t *)pkt + 2;
+ for (cnt = 2; cnt < REQUEST_ENTRY_SIZE/4; cnt++)
+ *dword_ptr++ = 0;
+
+ /* Set ISP command timeout. */
+ pkt->timeout = (uint16_t)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);
+ data_ptr = (uint8_t *) &(CMD_CDBP(cmd));
+ for (cnt = 0; cnt < pkt->cdb_len; cnt++)
+ pkt->scsi_cdb[cnt] = *data_ptr++;
+ DEBUG(printk("Build packet for command[0]=0x%x\n",pkt->scsi_cdb[0]));
+ /*
+ * Load data segments.
+ */
+ if (seg_cnt)
+ {
+ DEBUG(printk("loading data segments..\n"));
+ /* Set transfer direction (READ and WRITE) */
+ /* Linux doesn't tell us */
+
+ /*
+ * 3/10 dg - Normally, we should need this check with our F/W
+ * but because of a small issue with it we do.
+ *
+ * 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 = (uint32_t *)&pkt->dseg_0_address;
+
+ if (cmd->use_sg) /* If scatter gather */
+ {
+ DEBUG(qla1280_print("Building S/G data segments..\n\r"));
+ DEBUG(qla1280_dump_buffer((caddr_t)sg, 4*16 ));
+ /* Load command entry data segments. */
+ for (cnt = 0; cnt < 4 && seg_cnt; cnt++, seg_cnt--)
+ {
+ *dword_ptr++ = (uint32_t) cpu_to_le32(VIRT_TO_BUS(sg->address));
+ *dword_ptr++ = sg->length;
+ DEBUG(sprintf(debug_buff,"SG Segment ap=0x%p, len=0x%x\n\r",sg->address,sg->length));
+ DEBUG(qla1280_print(debug_buff));
+ sg++;
+ }
+ /*
+ * Build continuation packets.
+ */
+ 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. */
+ dword_ptr = (uint32_t *)pkt;
+ for (cnt = 0;cnt < REQUEST_ENTRY_SIZE/4; cnt++)
+ *dword_ptr++ = 0;
+
+ /* 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 = (uint32_t *)
+ &((cont_entry_t *)pkt)->dseg_0_address;
+
+ /* Load continuation entry data segments. */
+ for (cnt = 0; cnt < 7 && seg_cnt; cnt++, seg_cnt--)
+ {
+ *dword_ptr++ = (u_int) cpu_to_le32(VIRT_TO_BUS(sg->address));
+ *dword_ptr++ = sg->length;
+ sg++;
+ }
+#ifdef QL_DEBUG_LEVEL_5
+ qla1280_print(
+ "qla1280_32bit_start_scsi: continuation packet data - scsi(");
+ qla1280_output_number((uint32_t)SCSI_BUS_32(cmd), 10);
+ qla1280_print(":");
+ qla1280_output_number((uint32_t)SCSI_TCN_32(cmd), 10);
+ qla1280_print(":");
+ qla1280_output_number((uint32_t)SCSI_LUN_32(cmd), 10);
+ qla1280_print(")\n\r");
+ qla1280_dump_buffer((caddr_t)pkt, REQUEST_ENTRY_SIZE);
+#endif
+ }
+ }
+ else /* No scatter gather data transfer */
+ {
+ *dword_ptr++ = (uint32_t) cpu_to_le32(VIRT_TO_BUS(cmd->request_buffer));
+ *dword_ptr = (uint32_t) cmd->request_bufflen;
+ DEBUG(printk("Single Segment ap=0x%p, len=0x%x\n",cmd->request_buffer,cmd->request_bufflen));
+ }
+ }
+ else /* No data transfer */
+ {
+ *dword_ptr++ = (uint32_t) 0;
+ *dword_ptr = (uint32_t) 0;
+#ifdef QL_DEBUG_LEVEL_5
+ qla1280_print(
+ "qla1280_32bit_start_scsi: No data, command packet data - ");
+ qla1280_print("\n\r");
+ qla1280_dump_buffer((caddr_t)pkt, REQUEST_ENTRY_SIZE);
+#endif
+ }
+#ifdef QL_DEBUG_LEVEL_5
+ qla1280_print("qla1280_32bit_start_scsi: First IOCB block:\n\r");
+ qla1280_dump_buffer((caddr_t)ha->request_ring_ptr, REQUEST_ENTRY_SIZE);
+#endif
+ /* 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. */
+ DEBUG(qla1280_print("qla1280_32bit_start_scsi: Wakeup RISC for pending command\n\r"));
+ ha->qthreads--;
+ sp->u_start = jiffies;
+ sp->flags |= SRB_SENT;
+ ha->actthreads++;
+ /* qla1280_output_number((uint32_t)ha->actthreads++, 16); */
+ WRT_REG_WORD(®->mailbox4, ha->req_ring_index);
+ }
+ else
+ {
+ status = 1;
+#ifdef QL_DEBUG_LEVEL_2
+ qla1280_print(
+ "qla1280_32bit_start_scsi: NO ROOM IN OUTSTANDING ARRAY\n\r");
+ qla1280_print(" req_q_cnt=");
+ qla1280_output_number((uint32_t)ha->req_q_cnt, 16);
+ qla1280_print("\n\r");
+#endif
+ }
+ }
+ else
+ {
+ status = 1;
+#ifdef QL_DEBUG_LEVEL_2
+ /* qla1280_print("qla1280_32bit_start_scsi: in-ptr=");
+ qla1280_output_number((uint32_t)ha->req_ring_index, 16);
+ qla1280_print(" req_q_cnt=");
+ qla1280_output_number((uint32_t)ha->req_q_cnt, 16);
+ qla1280_print(" req_cnt=");
+ qla1280_output_number((uint32_t)req_cnt, 16);
+ qla1280_print("\n\r"); */
+#endif
+ }
+
+ /* Release ring specific lock */
+ QLA1280_RING_UNLOCK(ha);
+
+#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3)
+ /* if (status)
+ qla1280_print("qla1280_32bit_start_scsi: **** FAILED ****\n\r"); */
+#endif
+#ifdef QL_DEBUG_LEVEL_3
+ LEAVE("qla1280_32bit_start_scsi");
+#endif
+ 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(scsi_qla_host_t *ha)
+{
+ device_reg_t *reg = ha->iobase;
+ request_t *pkt = 0;
+ uint16_t cnt;
+ uint32_t *dword_ptr;
+ uint32_t timer;
+
+#ifdef QL_DEBUG_LEVEL_3
+ ENTER("qla1280_req_pkt");
+#endif
+
+ /* Wait for 30 seconds for slot. */
+ for (timer = 15000000; timer; timer--)
+ {
+ /* Acquire ring specific lock */
+ QLA1280_RING_LOCK(ha);
+
+ 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. */
+ dword_ptr = (uint32_t *)pkt;
+ for (cnt = 0; cnt < REQUEST_ENTRY_SIZE/4; cnt++)
+ *dword_ptr++ = 0;
+
+ /* Set system defined field. */
+ pkt->sys_define = (uint8_t)ha->req_ring_index;
+
+ /* Set entry count. */
+ pkt->entry_count = 1;
+
+ break;
+ }
+
+ /* Release ring specific lock */
+ QLA1280_RING_UNLOCK(ha);
+
+ SYS_DELAY(2); /* 10 */
+
+ /* Check for pending interrupts. */
+ qla1280_poll(ha);
+ }
+
+#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3)
+ if (!pkt)
+ qla1280_print("qla1280_req_pkt: **** FAILED ****\n\r");
+#endif
+#ifdef QL_DEBUG_LEVEL_3
+ else
+ qla1280_print("qla1280_req_pkt: exiting normally\n\r");
+#endif
+ 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(scsi_qla_host_t *ha)
+{
+ device_reg_t *reg = ha->iobase;
+
+#ifdef QL_DEBUG_LEVEL_3
+ ENTER("qla1280_isp_cmd");
+#endif
+
+#ifdef QL_DEBUG_LEVEL_5
+ qla1280_print("qla1280_isp_cmd: IOCB data:\n\r");
+ qla1280_dump_buffer((caddr_t)ha->request_ring_ptr, REQUEST_ENTRY_SIZE);
+#endif
+
+ /* 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);
+
+ /* Release ring specific lock */
+ QLA1280_RING_UNLOCK(ha);
+
+#ifdef QL_DEBUG_LEVEL_3
+ LEAVE("qla1280_isp_cmd");
+#endif
+}
+
+/*
+ * qla1280_enable_lun
+ * Issue enable LUN entry IOCB.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ * b = SCSI BUS number.
+ * l = LUN number.
+ */
+STATIC void
+qla1280_enable_lun(scsi_qla_host_t *ha, uint8_t b, uint32_t l)
+{
+ elun_entry_t *pkt;
+
+#ifdef QL_DEBUG_LEVEL_3
+ qla1280_print("qla1280_enable_lun: entered\n\r");
+#endif
+
+ /* Get request packet. */
+ /*
+ if (pkt = (elun_entry_t *)qla1280_req_pkt(ha))
+ {
+ pkt->entry_type = ENABLE_LUN_TYPE;
+ pkt->lun = (uint16_t)(b ? l | BIT_15 : l);
+ 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 defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3)
+ if (!pkt)
+ qla1280_print("qla1280_enable_lun: **** FAILED ****\n\r");
+#endif
+#ifdef QL_DEBUG_LEVEL_3
+ else
+ qla1280_print("qla1280_enable_lun: exiting normally\n\r");
+#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(scsi_qla_host_t *ha, notify_entry_t *inotify)
+{
+ nack_entry_t *pkt;
+
+#ifdef QL_DEBUG_LEVEL_3
+ qla1280_print("qla1280_notify_ack: entered\n\r");
+#endif
+
+ /* 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 defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3)
+ if (!pkt)
+ qla1280_print("qla1280_notify_ack: **** FAILED ****\n\r");
+#endif
+#ifdef QL_DEBUG_LEVEL_3
+ else
+ qla1280_print("qla1280_notify_ack: exiting normally\n\r");
+#endif
+}
+
+/*
+ * 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(scsi_qla_host_t *ha, notify_entry_t *inotify)
+{
+ notify_entry_t *pkt;
+
+#ifdef QL_DEBUG_LEVEL_3
+ qla1280_print("qla1280_immed_notify: entered\n\r");
+#endif
+
+ /* 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 defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3)
+ if (!pkt)
+ qla1280_print("qla1280_immed_notify: **** FAILED ****\n\r");
+#endif
+#ifdef QL_DEBUG_LEVEL_3
+ else
+ qla1280_print("qla1280_immed_notify: exiting normally\n\r");
+#endif
+}
+
+/*
+ * 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(scsi_qla_host_t *ha, ctio_ret_entry_t *ctio)
+{
+ atio_entry_t *pkt;
+
+#ifdef QL_DEBUG_LEVEL_3
+ qla1280_print("qla1280_accept_io: entered\n\r");
+#endif
+
+ /* 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 defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3)
+ if (!pkt)
+ qla1280_print("qla1280_accept_io: **** FAILED ****\n\r");
+#endif
+#ifdef QL_DEBUG_LEVEL_3
+ else
+ qla1280_print("qla1280_accept_io: exiting normally\n\r");
+#endif
+}
+
+/*
+ * 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(scsi_qla_host_t *ha, atio_entry_t *atio, uint32_t len,
+ paddr32_t *addr)
+{
+ ctio_a64_entry_t *pkt;
+ uint32_t *dword_ptr;
+
+#ifdef QL_DEBUG_LEVEL_3
+ qla1280_print("qla1280_64bit_continue_io: entered\n\r");
+#endif
+
+ /* 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 defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3)
+ if (!pkt)
+ qla1280_print("qla1280_64bit_continue_io: **** FAILED ****\n\r");
+#endif
+#ifdef QL_DEBUG_LEVEL_3
+ else
+ qla1280_print("qla1280_64bit_continue_io: exiting normally\n\r");
+#endif
+}
+
+/*
+ * 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(scsi_qla_host_t *ha, atio_entry_t *atio, uint32_t len,
+ paddr32_t *addr)
+{
+ ctio_entry_t *pkt;
+ uint32_t *dword_ptr;
+
+#ifdef QL_DEBUG_LEVEL_3
+ qla1280_print("qla1280_32bit_continue_io: entered\n\r");
+#endif
+
+ /* 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 defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3)
+ if (!pkt)
+ qla1280_print("qla1280_32bit_continue_io: **** FAILED ****\n\r");
+#endif
+#ifdef QL_DEBUG_LEVEL_3
+ else
+ qla1280_print("qla1280_32bit_continue_io: exiting normally\n\r");
+#endif
+}
+#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.
+ * INTR_LOCK must be already obtained.
+ ****************************************************************************/
+STATIC void
+qla1280_isr(scsi_qla_host_t *ha, srb_t **done_q_first, srb_t **done_q_last)
+{
+ device_reg_t *reg = ha->iobase;
+ response_t *pkt;
+ srb_t *sp;
+ uint16_t mailbox[MAILBOX_REGISTER_COUNT];
+ uint16_t *wptr;
+ uint32_t index;
+
+ ENTER("qla1280_isr");
+
+
+ /* 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. */
+
+ 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);
+
+#ifdef QL_DEBUG_LEVEL_5
+ qla1280_print("qla1280_isr: mailbox interrupt mailbox[0] = ");
+ qla1280_output_number((uint32_t)mailbox[0], 16);
+ qla1280_print("\n\r");
+#endif
+
+ /* Handle asynchronous event */
+
+ switch (mailbox[0])
+ {
+ case MBA_SCSI_COMPLETION: /* Response completion */
+#ifdef QL_DEBUG_LEVEL_5
+ qla1280_print("qla1280_isr: mailbox response completion\n\r");
+#endif
+ if (ha->flags.online)
+ {
+ /* Get outstanding command index. */
+ index = (uint32_t)(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
+ {
+#ifdef QL_DEBUG_LEVEL_2
+ qla1280_print("qla1280_isr: ISP invalid handle\n\r");
+#endif
+ printk(KERN_WARNING "qla1280: ISP invalid handle");
+ ha->flags.isp_abort_needed = TRUE;
+ }
+ }
+ break;
+ case MBA_BUS_RESET: /* SCSI Bus Reset */
+#ifdef QL_DEBUG_LEVEL_2
+ qla1280_print("qla1280_isr: asynchronous BUS_RESET\n\r");
+#endif
+ ha->flags.reset_marker = TRUE;
+ index = mailbox[6] & BIT_0;
+ ha->bus_settings[index].reset_marker = TRUE;
+ break;
+ case MBA_SYSTEM_ERR: /* System Error */
+#ifdef QL_DEBUG_LEVEL_2
+ qla1280_print("qla1280_isr: ISP System Error - mbx1=");
+ qla1280_output_number((uint32_t)mailbox[1], 16);
+ qla1280_print(", mbx2=");
+ qla1280_output_number((uint32_t)mailbox[2], 16);
+ qla1280_print(", mbx3=");
+ qla1280_output_number((uint32_t)mailbox[3], 16);
+ qla1280_print("\n\r");
+#endif
+ 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 */
+#ifdef QL_DEBUG_LEVEL_2
+ qla1280_print("qla1280_isr: ISP Request Transfer Error\n\r");
+#endif
+ printk(KERN_WARNING "qla1280: ISP Request Transfer Error\n");
+ ha->flags.isp_abort_needed = TRUE;
+ break;
+ case MBA_RSP_TRANSFER_ERR: /* Response Transfer Error */
+#ifdef QL_DEBUG_LEVEL_2
+ qla1280_print("qla1280_isr: ISP Response Transfer Error\n\r");
+#endif
+ printk(KERN_WARNING "qla1280: ISP Response Transfer Error\n");
+ ha->flags.isp_abort_needed = TRUE;
+ break;
+ case MBA_WAKEUP_THRES: /* Request Queue Wake-up */
+#ifdef QL_DEBUG_LEVEL_2
+ qla1280_print("qla1280_isr: asynchronous WAKEUP_THRES\n\r");
+#endif
+ break;
+ case MBA_TIMEOUT_RESET: /* Execution Timeout Reset */
+#ifdef QL_DEBUG_LEVEL_2
+ qla1280_print("qla1280_isr: asynchronous TIMEOUT_RESET\n\r");
+#endif
+ break;
+ case MBA_DEVICE_RESET: /* Bus Device Reset */
+#ifdef QL_DEBUG_LEVEL_2
+ qla1280_print(
+ "qla1280_isr: asynchronous BUS_DEVICE_RESET\n\r");
+#endif
+ ha->flags.reset_marker = TRUE;
+ index = mailbox[6] & BIT_0;
+ ha->bus_settings[index].reset_marker = TRUE;
+ break;
+ case MBA_BUS_MODE_CHANGE:
+#ifdef QL_DEBUG_LEVEL_2
+ qla1280_print(
+ "qla1280_isr: asynchronous BUS_MODE_CHANGE\n\r");
+#endif
+ break;
+ default:
+ if (mailbox[0] < MBA_ASYNC_EVENT)
+ {
+ wptr = &mailbox[0];
+ ha->mailbox_out[0] = *wptr++;
+ ha->mailbox_out[1] = *wptr++;
+ ha->mailbox_out[2] = *wptr++;
+ ha->mailbox_out[3] = *wptr++;
+ ha->mailbox_out[4] = *wptr++;
+ ha->mailbox_out[5] = *wptr++;
+ ha->mailbox_out[6] = *wptr++;
+ ha->mailbox_out[7] = *wptr;
+ ha->flags.mbox_int = TRUE;
+ }
+ break;
+ }
+ }
+ else
+ WRT_REG_WORD(®->host_cmd, HC_CLR_RISC_INT);
+
+ /*
+ * Response ring
+ */
+ if (ha->flags.online && !ha->flags.mbox_busy)
+ {
+ if (mailbox[5] < RESPONSE_ENTRY_CNT)
+ {
+ while (ha->rsp_ring_index != mailbox[5])
+ {
+ pkt = ha->response_ring_ptr;
+
+#ifdef QL_DEBUG_LEVEL_5
+ qla1280_print("qla1280_isr: ha->rsp_ring_index = ");
+ qla1280_output_number((uint32_t)ha->rsp_ring_index, 16);
+ qla1280_print(" mailbox[5] = ");
+ qla1280_output_number((uint32_t)mailbox[5], 16);
+ qla1280_print("\n\rqla1280_isr: response packet data\n\r");
+ qla1280_dump_buffer((caddr_t)pkt, RESPONSE_ENTRY_SIZE);
+#endif
+
+#if defined(QL_DEBUG_LEVEL_2) && !defined(QL_DEBUG_LEVEL_5)
+ if (pkt->entry_type == STATUS_TYPE)
+ {
+ if ((uint8_t)(pkt->scsi_status) || pkt->comp_status ||
+ pkt->entry_status)
+ {
+ DEBUG(qla1280_print("qla1280_isr: ha->rsp_ring_index = ");)
+ DEBUG(qla1280_output_number((uint32_t)ha->rsp_ring_index,
+ 16);)
+ DEBUG(qla1280_print(" mailbox[5] = ");)
+ DEBUG(qla1280_output_number((uint32_t)mailbox[5], 16);)
+ DEBUG(qla1280_print( "\n\r comp_status = ");)
+ DEBUG(qla1280_output_number((uint32_t)pkt->comp_status,16);)
+ DEBUG(qla1280_print( ", ");)
+ DEBUG(qla1280_print( " scsi_status = ");)
+ DEBUG(qla1280_output_number((uint32_t)pkt->scsi_status,16);)
+ DEBUG(qla1280_print( "\n\r");)
+ /* qla1280_print(
+ "\n\rqla1280_isr: response packet data\n\r");
+ qla1280_dump_buffer((caddr_t)pkt,
+ RESPONSE_ENTRY_SIZE); */
+ }
+ }
+ else
+ {
+ qla1280_print("qla1280_isr: ha->rsp_ring_index = ");
+ qla1280_output_number((uint32_t)ha->rsp_ring_index, 16);
+ qla1280_print(" mailbox[5] = ");
+ qla1280_output_number((uint32_t)mailbox[5], 16);
+ qla1280_print(
+ "\n\rqla1280_isr: response packet data\n\r");
+ qla1280_dump_buffer((caddr_t)pkt, RESPONSE_ENTRY_SIZE);
+ }
+#endif
+ 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);
+
+ /* Release interrupt specific lock */
+ QLA1280_INTR_UNLOCK(ha);
+
+ 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;
+ }
+
+ /* Acquire interrupt specific lock */
+ QLA1280_INTR_LOCK(ha);
+ }
+#endif
+ }
+ }
+ else
+ {
+ ha->flags.isp_abort_needed = TRUE;
+#ifdef QL_DEBUG_LEVEL_2
+ qla1280_print("qla1280_isr: Response pointer Error\n");
+#endif
+ }
+ }
+
+ LEAVE("qla1280_isr");
+}
+
+/*
+ * qla1280_rst_aen
+ * Processes asynchronous reset.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ */
+STATIC void
+qla1280_rst_aen(scsi_qla_host_t *ha)
+{
+#if QL1280_TARGET_MODE_SUPPORT
+ notify_entry_t nentry;
+#endif
+ uint8_t b;
+
+#ifdef QL_DEBUG_LEVEL_3
+ ENTER("qla1280_rst_aen");
+#endif
+
+ 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 (b = 0; b < ha->ports && !ha->flags.reset_marker; b++)
+ {
+ if (ha->bus_settings[b].reset_marker)
+ {
+ ha->bus_settings[b].reset_marker = FALSE;
+ qla1280_marker(ha, b, 0, 0, MK_SYNC_ALL);
+
+ if (!ha->flags.reset_marker)
+ {
+#if QL1280_TARGET_MODE_SUPPORT
+ /* Issue notify acknowledgement command. */
+ bzero((caddr_t)&nentry, sizeof(notify_entry_t));
+
+ nentry.initiator_id = nentry.target_id = b ?
+ ha->bus_settings[b].id | BIT_7 :
+ ha->bus_settings[b].id;
+ qla1280_notify_entry(ha, &nentry);
+#endif
+
+ /* Asynchronous event notification */
+ }
+ }
+ }
+ }
+ }
+
+#ifdef QL_DEBUG_LEVEL_3
+ LEAVE("qla1280_rst_aen");
+#endif
+}
+
+#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(scsi_qla_host_t *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;
+
+#ifdef QL_DEBUG_LEVEL_3
+ qla1280_print("qla1280_atio_entry: entered\n\r");
+#endif
+
+ 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 */
+#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3)
+ qla1280_print("qla1280_atio_entry: Path invalid\n\r");
+#endif
+ break;
+ case 0x14: /* Target Bus Phase Sequence Failure */
+#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3)
+ qla1280_print(
+ "qla1280_atio_entry: Target Bus Phase Sequence Failure\n\r");
+#endif
+ if (pkt->status & BIT_7)
+ {
+ BCOPY((caddr_t)&pkt->sense_data, sense_ptr,TARGET_SENSE_SIZE);
+ }
+ else
+ {
+ bzero(sense_ptr, 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 |= (uint32_t)OF_SSTS | (uint32_t)OF_NO_DATA;
+ if (ha->flags.enable_64bit_addressing)
+ qla1280_64bit_continue_io(ha, pkt, 0, 0);
+ else
+ qla1280_32bit_continue_io(ha, pkt, 0, 0);
+ break;
+ case 0x16: /* Requested Capability Not Available */
+#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3)
+ qla1280_print(
+ "qla1280_atio_entry: Target Bus Phase Sequence Failure\n\r");
+#endif
+ break;
+ case 0x17: /* Bus Device Reset Message Received */
+#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3)
+ qla1280_print(
+ "qla1280_atio_entry: Target Bus Phase Sequence Failure\n\r");
+#endif
+ 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:
+#ifdef QL_DEBUG_LEVEL_3
+ qla1280_print("qla1280_atio_entry: SS_TEST\n\r");
+#endif
+ bzero(sense_ptr, 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 |= (uint32_t)OF_SSTS |
+ (uint32_t)OF_NO_DATA;
+ break;
+ case SS_REQSEN:
+#ifdef QL_DEBUG_LEVEL_3
+ qla1280_print("qla1280_atio_entry: SS_REQSEN\n\r");
+#endif
+ 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 |= (uint32_t)OF_SSTS |
+ (uint32_t)OF_DATA_IN;
+ break;
+ case SS_INQUIR:
+#ifdef QL_DEBUG_LEVEL_3
+ qla1280_print("qla1280_atio_entry: SS_INQUIR\n\r");
+#endif
+ bzero(sense_ptr, 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 |= (uint32_t)OF_SSTS |
+ (uint32_t)OF_DATA_IN;
+ break;
+ case SM_WRDB:
+ bzero(sense_ptr, 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:
+#ifdef QL_DEBUG_LEVEL_3
+ qla1280_print("qla1280_atio_entry: SM_WRDB, RW_BUF_HDATA\n\r");
+#endif
+ if (len > TARGET_DATA_SIZE + 4)
+ {
+#ifdef QL_DEBUG_LEVEL_2
+ qla1280_print("qla1280_atio_entry: SM_WRDB, length > buffer size\n\r");
+#endif
+ *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 |= (uint32_t)OF_SSTS |
+ (uint32_t)OF_NO_DATA;
+ len = 0;
+ }
+ else if (len)
+ {
+ pkt->scsi_status = S_GOOD;
+ pkt->option_flags |= (uint32_t)OF_SSTS |
+ (uint32_t)OF_DATA_OUT;
+#ifdef QL_DEBUG_LEVEL_3
+ qla1280_print("qla1280_atio_entry: Issuing SDI_TARMOD_WRCOMP\n\r");
+#endif
+ sdi_xaen(SDI_TARMOD_WRCOMP, ha->cntlr,
+ pkt->target_id, pkt->lun, 0, offset);
+ }
+ else
+ {
+#ifdef QL_DEBUG_LEVEL_2
+ qla1280_print("qla1280_atio_entry: SM_WRDB, zero length\n\r");
+#endif
+ pkt->scsi_status = S_GOOD;
+ pkt->option_flags |= (uint32_t)OF_SSTS |
+ (uint32_t)OF_NO_DATA;
+ }
+
+ break;
+ case RW_BUF_DATA:
+#ifdef QL_DEBUG_LEVEL_3
+ qla1280_print("qla1280_atio_entry: SM_WRDB, RW_BUF_DATA\n\r");
+#endif
+ *a64 += offset + TARGET_DATA_OFFSET;
+ if (pkt->cdb[2] != 0 || *a64 >= *end_a64 ||
+ *a64 + len > *end_a64)
+ {
+#ifdef QL_DEBUG_LEVEL_2
+ qla1280_print("qla1280_atio_entry: SM_WRDB, RW_BUF_DATA BAD\n\r");
+ qla1280_print("buf_id=");
+ qla1280_output_number((uint32_t)pkt->cdb[2], 16);
+ qla1280_print(", offset=");
+ qla1280_output_number((uint32_t)offset, 16);
+ qla1280_print(", length=");
+ qla1280_output_number((uint32_t)len, 16);
+ qla1280_print("\n\r");
+#endif
+ *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 |= (uint32_t)OF_SSTS |
+ (uint32_t)OF_NO_DATA;
+ }
+ else if (len)
+ {
+ pkt->scsi_status = S_GOOD;
+ pkt->option_flags |= (uint32_t)OF_SSTS |
+ (uint32_t)OF_DATA_OUT;
+#ifdef QL_DEBUG_LEVEL_3
+ qla1280_print("qla1280_atio_entry: Issuing SDI_TARMOD_WRCOMP\n\r");
+#endif
+ sdi_xaen(SDI_TARMOD_WRCOMP, ha->cntlr,
+ pkt->target_id, pkt->lun, 0, offset);
+ }
+ else
+ {
+#ifdef QL_DEBUG_LEVEL_2
+ qla1280_print("qla1280_atio_entry: SM_WRDB, zero length\n\r");
+#endif
+ pkt->scsi_status = S_GOOD;
+ pkt->option_flags |= (uint32_t)OF_SSTS |
+ (uint32_t)OF_NO_DATA;
+ }
+ break;
+ default:
+#ifdef QL_DEBUG_LEVEL_2
+ qla1280_print("qla1280_atio_entry: SM_WRDB unknown mode\n\r");
+#endif
+ *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 |= (uint32_t)OF_SSTS |
+ (uint32_t)OF_NO_DATA;
+ break;
+ }
+ break;
+ case SM_RDDB:
+ bzero(sense_ptr, 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:
+#ifdef QL_DEBUG_LEVEL_3
+ qla1280_print("qla1280_atio_entry: SM_RDDB, RW_BUF_HDATA\n\r");
+#endif
+ if (len)
+ {
+ ha->tbuf->hdr[0] = 0;
+ ha->tbuf->hdr[1] =
+ (uint8_t)(TARGET_DATA_SIZE >> 16);
+ ha->tbuf->hdr[2] =
+ (uint8_t)(TARGET_DATA_SIZE >> 8);
+ ha->tbuf->hdr[3] = (uint8_t)TARGET_DATA_SIZE;
+ if (len > TARGET_DATA_SIZE + 4)
+ len = TARGET_DATA_SIZE + 4;
+ pkt->scsi_status = S_GOOD;
+ pkt->option_flags |= (uint32_t)OF_SSTS |
+ (uint32_t)OF_DATA_IN;
+ }
+ else
+ {
+#ifdef QL_DEBUG_LEVEL_2
+ qla1280_print("qla1280_atio_entry: SM_RDDB, zero length\n\r");
+#endif
+ pkt->scsi_status = S_GOOD;
+ pkt->option_flags |= (uint32_t)OF_SSTS |
+ (uint32_t)OF_NO_DATA;
+ }
+ break;
+ case RW_BUF_DATA:
+#ifdef QL_DEBUG_LEVEL_3
+ qla1280_print("qla1280_atio_entry: SM_RDDB, RW_BUF_DATA\n\r");
+#endif
+ *a64 += offset + TARGET_DATA_OFFSET;
+ if (pkt->cdb[2] != 0 || *a64 >= *end_a64)
+ {
+#ifdef QL_DEBUG_LEVEL_2
+ qla1280_print("qla1280_atio_entry: SM_RDDB, RW_BUF_DATA BAD\n\r");
+ qla1280_print("buf_id=");
+ qla1280_output_number((uint32_t)pkt->cdb[2], 16);
+ qla1280_print(", offset=");
+ qla1280_output_number((uint32_t)offset, 16);
+ qla1280_print("\n\r");
+#endif
+ *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 |= (uint32_t)OF_SSTS |
+ (uint32_t)OF_NO_DATA;
+ }
+ else
+ {
+ if (*a64 + len > *end_a64)
+ len = *end_a64 - *a64;
+ if (len)
+ {
+ pkt->scsi_status = S_GOOD;
+ pkt->option_flags |= (uint32_t)OF_SSTS |
+ (uint32_t)OF_DATA_IN;
+ }
+ else
+ {
+#ifdef QL_DEBUG_LEVEL_2
+ qla1280_print("qla1280_atio_entry: SM_RDDB, zero length\n\r");
+#endif
+ pkt->scsi_status = S_GOOD;
+ pkt->option_flags |= (uint32_t)OF_SSTS |
+ (uint32_t)OF_NO_DATA;
+ }
+ }
+ break;
+ case RW_BUF_DESC:
+#ifdef QL_DEBUG_LEVEL_3
+ qla1280_print("qla1280_atio_entry: SM_RDDB, RW_BUF_DESC\n\r");
+#endif
+ 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] =
+ (uint8_t)(TARGET_DATA_SIZE >> 16);
+ ha->tbuf->hdr[2] =
+ (uint8_t)(TARGET_DATA_SIZE >> 8);
+ ha->tbuf->hdr[3] =
+ (uint8_t)TARGET_DATA_SIZE;
+ }
+ pkt->scsi_status = S_GOOD;
+ pkt->option_flags |= (uint32_t)OF_SSTS |
+ (uint32_t)OF_DATA_IN;
+ }
+ else
+ {
+#ifdef QL_DEBUG_LEVEL_2
+ qla1280_print("qla1280_atio_entry: SM_RDDB, zero length\n\r");
+#endif
+ pkt->scsi_status = S_GOOD;
+ pkt->option_flags |= (uint32_t)OF_SSTS |
+ (uint32_t)OF_NO_DATA;
+ }
+ break;
+ default:
+#ifdef QL_DEBUG_LEVEL_2
+ qla1280_print("qla1280_atio_entry: SM_RDDB unknown mode\n\r");
+#endif
+ *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 |= (uint32_t)OF_SSTS |
+ (uint32_t)OF_NO_DATA;
+ break;
+ }
+ break;
+ default:
+#ifdef QL_DEBUG_LEVEL_2
+ qla1280_print("qla1280_atio_entry: Unknown SCSI command\n\r");
+ qla1280_dump_buffer((caddr_t)&pkt->cdb[0], pkt->cdb_len);
+#endif
+ bzero(sense_ptr, 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 |= (uint32_t)OF_SSTS |
+ (uint32_t)OF_NO_DATA;
+ break;
+ }
+ if (ha->flags.enable_64bit_addressing)
+ qla1280_64bit_continue_io(ha, pkt, len, (paddr32_t *)&phy_addr);
+ else
+ qla1280_32bit_continue_io(ha, pkt, len, (paddr32_t *)&phy_addr);
+ break;
+ default:
+ break;
+ }
+
+#ifdef QL_DEBUG_LEVEL_3
+ qla1280_print("qla1280_atio_entry: exiting normally\n\r");
+#endif
+}
+
+/*
+ * qla1280_notify_entry
+ * Processes received ISP immediate notify entry.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ * pkt = entry pointer.
+ */
+STATIC void
+qla1280_notify_entry(scsi_qla_host_t *ha, notify_entry_t *pkt)
+{
+#ifdef QL_DEBUG_LEVEL_3
+ qla1280_print("qla1280_notify_entry: entered\n\r");
+#endif
+
+ /* Acknowledge immediate notify */
+ qla1280_notify_ack(ha, pkt);
+
+ /* Issue notify entry to increment resource count */
+ qla1280_immed_notify(ha, pkt);
+
+#ifdef QL_DEBUG_LEVEL_3
+ qla1280_print("qla1280_notify_entry: exiting normally\n\r");
+#endif
+}
+
+#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(scsi_qla_host_t *ha, sts_entry_t *pkt, srb_t **done_q_first,
+ srb_t **done_q_last)
+{
+ uint32_t b, t, l;
+ uint8_t sense_sz = 0;
+ srb_t *sp;
+ scsi_lu_t *q;
+ Scsi_Cmnd *cp;
+
+#ifdef QL_DEBUG_LEVEL_3
+ ENTER("qla1280_status_entry");
+#endif
+
+ /* 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;
+
+ cp = sp->cmd;
+ /* Generate LU queue on cntrl, target, LUN */
+ b = SCSI_BUS_32(cp);
+ t = SCSI_TCN_32(cp);
+ l = SCSI_LUN_32(cp);
+ q = LU_Q(ha, b, t, l);
+ if( pkt->comp_status || pkt->scsi_status )
+ {
+ DEBUG(qla1280_print( "scsi: comp_status = ");)
+ DEBUG(qla1280_output_number((uint32_t)pkt->comp_status,16);)
+ DEBUG(qla1280_print( ", ");)
+ DEBUG(qla1280_print( " scsi_status = ");)
+ DEBUG(qla1280_output_number((uint32_t)pkt->scsi_status,16);)
+ DEBUG(qla1280_print( "\n\r");)
+ DEBUG(qla1280_print(", handle = ");)
+ DEBUG(qla1280_output_number((uint32_t)pkt->handle, 16);)
+ DEBUG(qla1280_print("\n\r");)
+ }
+
+ /* Target busy */
+ if ( pkt->scsi_status & SS_BUSY_CONDITION &&
+ pkt->scsi_status != SS_RESERVE_CONFLICT )
+ {
+ CMD_RESULT(cp) = (int) (DID_BUS_BUSY << 16) |
+ (pkt->scsi_status & 0xff);
+ }
+ else
+ {
+
+ /* Save ISP completion status */
+ CMD_RESULT(cp) = qla1280_return_status( pkt, cp );
+
+ if (pkt->scsi_status & SS_CHECK_CONDITION)
+ {
+ BZERO(cp->sense_buffer, CMD_SNSLEN(cp));
+ if (pkt->comp_status != CS_ARS_FAILED)
+ {
+ if ( pkt->req_sense_length < CMD_SNSLEN(cp) )
+ sense_sz = pkt->req_sense_length;
+ else
+ sense_sz = CMD_SNSLEN(cp) - 1;
+
+ BCOPY((caddr_t)&pkt->req_sense_data, cp->sense_buffer, sense_sz);
+
+ }
+#ifdef QL_DEBUG_LEVEL_2
+ DEBUG(qla1280_print(
+ "qla1280_status_entry: Check condition Sense data, b");)
+ DEBUG(qla1280_output_number((uint32_t)b, 10);)
+ DEBUG(qla1280_print("t");)
+ DEBUG(qla1280_output_number((uint32_t)t, 10);)
+ DEBUG(qla1280_print("d");)
+ DEBUG(qla1280_output_number((uint32_t)l, 10);)
+ DEBUG(qla1280_print("\n\r");)
+ DEBUG(if (sense_sz))
+ DEBUG(qla1280_dump_buffer(cp->sense_buffer, sense_sz);)
+#endif
+ }
+ }
+ /* Place command on done queue. */
+ qla1280_done_q_put(sp, done_q_first, done_q_last);
+ }
+ else
+ {
+#ifdef QL_DEBUG_LEVEL_2
+ qla1280_print("qla1280_status_entry: ISP Invalid handle\n\r");
+#endif
+ printk(KERN_WARNING "qla1280: Status Entry invalid handle\n");
+ ha->flags.isp_abort_needed = TRUE;
+ }
+#ifdef QL_DEBUG_LEVEL_3
+ LEAVE("qla1280_status_entry");
+#endif
+}
+
+/*
+ * 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(scsi_qla_host_t *ha, response_t *pkt, srb_t **done_q_first,
+ srb_t **done_q_last)
+{
+ srb_t *sp;
+
+#ifdef QL_DEBUG_LEVEL_3
+ ENTER("qla1280_error_entry");
+#endif
+
+#ifdef QL_DEBUG_LEVEL_2
+ if (pkt->entry_status & BIT_3)
+ qla1280_print("qla1280_error_entry: BAD PAYLOAD flag error\n\r");
+ else if (pkt->entry_status & BIT_2)
+ qla1280_print("qla1280_error_entry: BAD HEADER flag error\n\r");
+ else if (pkt->entry_status & BIT_1)
+ qla1280_print("qla1280_error_entry: FULL flag error\n\r");
+ else
+ qla1280_print("qla1280_error_entry: UNKNOWN flag error\n\r");
+#endif
+
+ /* 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) = (int) DID_ERROR << 16;
+ }
+ else if (pkt->entry_status & BIT_1 ) /* FULL flag */
+ {
+ CMD_RESULT(sp->cmd) = (int) DID_BUS_BUSY << 16;
+ }
+ else
+ {
+ /* Set error status. */
+ CMD_RESULT(sp->cmd) =(int) DID_ERROR << 16;
+ }
+ /* Place command on done queue. */
+ qla1280_done_q_put(sp, done_q_first, done_q_last);
+ }
+#if QLA1280_64BIT_SUPPORT
+ else if (pkt->entry_type == COMMAND_A64_TYPE)
+ {
+#ifdef QL_DEBUG_LEVEL_2
+ qla1280_print("qla1280_error_entry: ISP Invalid handle\n\r");
+#endif
+ printk(KERN_WARNING "!qla1280: Error Entry invalid handle");
+ ha->flags.isp_abort_needed = TRUE;
+ }
+#endif
+
+#ifdef QL_DEBUG_LEVEL_3
+ LEAVE("qla1280_error_entry");
+#endif
+}
+
+/*
+ * qla1280_abort_isp
+ * Resets ISP and aborts all outstanding commands.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ *
+ * Returns:
+ * 0 = success
+ */
+STATIC uint8_t
+qla1280_abort_isp(scsi_qla_host_t *ha)
+{
+ device_reg_t *reg = ha->iobase;
+ uint8_t status = 0;
+ uint16_t cnt;
+ srb_t *sp;
+ scsi_lu_t *q;
+ uint32_t b, t, l;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+ unsigned long cpu_flags = 0;
+#endif
+
+#ifdef QL_DEBUG_LEVEL_3
+ ENTER("qla1280_abort_isp");
+#endif
+
+ DRIVER_LOCK
+ ha->flags.isp_abort_needed = FALSE;
+ if (!ha->flags.abort_isp_active && ha->flags.online)
+ {
+ ha->flags.abort_isp_active = TRUE;
+
+ /* Disable ISP interrupts. */
+ WRT_REG_WORD(®->ictrl, 0);
+
+ /* 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 */
+ b = SCSI_BUS_32(sp->cmd);
+ t = SCSI_TCN_32(sp->cmd);
+ l = SCSI_LUN_32(sp->cmd);
+
+ q = (scsi_lu_t *)LU_Q(ha, b, t, l);
+
+ /* 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 &= ~(SRB_SENT | SRB_TIMEOUT); */
+ 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 (b = 0; b < ha->ports; b++)
+ {
+ qla1280_bus_reset(ha, b);
+ }
+ do
+ {
+ /* Issue marker command. */
+ ha->flags.reset_marker = FALSE;
+ for (b = 0; b < ha->ports; b++)
+ {
+ ha->bus_settings[b].reset_marker = FALSE;
+ qla1280_marker(ha, b, 0, 0, MK_SYNC_ALL);
+ }
+ }while (ha->flags.reset_marker);
+
+ /* Enable host adapter target mode. */
+ for (b = 0; b < ha->ports; b++)
+ {
+ if (!(status = qla1280_enable_tgt(ha, b)))
+ {
+ for (cnt = 0; cnt < MAX_LUNS; cnt++)
+ {
+ /* qla1280_enable_lun(ha, b, cnt); */
+ qla1280_poll(ha);
+ }
+ }
+ else
+ break;
+ }
+
+ if (!status)
+ {
+ /* Enable ISP interrupts. */
+ WRT_REG_WORD(®->ictrl, ISP_EN_INT + ISP_EN_RISC);
+ 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);
+
+#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3)
+ qla1280_print("qla1280_abort_isp: **** FAILED ****\n\r");
+#endif
+ }
+#ifdef QL_DEBUG_LEVEL_3
+ else
+ LEAVE("qla1280_abort_isp");
+#endif
+ DRIVER_UNLOCK
+
+ return(status);
+}
+
+/*
+ * qla1280_restart_queues
+ * Restart all device queues.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ */
+STATIC void
+qla1280_restart_queues(scsi_qla_host_t *ha)
+{
+ scsi_lu_t *q;
+ uint32_t b, t, l;
+
+#ifdef QL_DEBUG_LEVEL_3
+ ENTER("qla1280_restart_queues");
+#endif
+
+ for (b = 0; b < ha->ports; b++)
+ for (t = 0; t < MAX_TARGETS; t++)
+ for (l = 0; l < MAX_LUNS; l++)
+ {
+ q = (scsi_lu_t *) LU_Q(ha, b, t, l);
+ if (q != NULL)
+ {
+ /* Acquire LU queue specific lock */
+ QLA1280_SCSILU_LOCK(q);
+
+ if (q->q_first)
+ qla1280_next(ha, q, b);
+ else
+ /* Release LU queue specific lock */
+ QLA1280_SCSILU_UNLOCK(q);
+ }
+ }
+#ifdef QL_DEBUG_LEVEL_3
+ qla1280_print("qla1280_restart_queues: exiting normally\n");
+#endif
+}
+
+/*
+ * qla1280_abort_queue_single
+ * Abort all commands on a device queues.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ */
+STATIC void qla1280_abort_queue_single(scsi_qla_host_t *ha,uint32_t b,uint32_t t,uint32_t l,uint32_t stat)
+{
+ scsi_lu_t *q;
+ srb_t *sp, *sp_next;
+
+ ENTER("qla1280_abort_queue_single");
+ q = (scsi_lu_t * )LU_Q(ha, b, t, l);
+ if (q != NULL)
+ {
+ /* Acquire LU queue specific lock */
+ QLA1280_SCSILU_LOCK(q);
+
+ sp = q->q_first;
+ q->q_first = q->q_last = NULL;
+
+ QLA1280_SCSILU_UNLOCK(q);
+
+ while (sp)
+ {
+ sp_next = sp->s_next;
+ CMD_RESULT(sp->cmd) = stat;
+ qla1280_done_q_put(sp, (srb_t **)&ha->done_q_first, (srb_t **)&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(scsi_qla_host_t *ha)
+{
+ uint32_t b, t, l;
+
+ ENTER("qla1280_abort_queues");
+
+ for (b = 0; b < ha->ports; b++)
+ for (t = 0; t < MAX_TARGETS; t++)
+ for (l = 0; l < MAX_LUNS; l++)
+ qla1280_abort_queue_single(ha,b,t,l,DID_RESET);
+
+ LEAVE("qla1280_abort_queues");
+}
+
+/*
+ * qla1280_debounce_register
+ * Debounce register.
+ *
+ * Input:
+ * port = register address.
+ *
+ * Returns:
+ * register value.
+ */
+STATIC uint16_t
+qla1280_debounce_register(volatile uint16_t *addr)
+{
+ volatile uint16_t ret;
+ volatile uint16_t ret2;
+
+ do
+ {
+ ret = RD_REG_WORD(addr);
+ ret2 = RD_REG_WORD(addr);
+ }while (ret != ret2);
+
+ return(ret);
+}
+
+
+/*
+ * Declarations for load module
+ */
+#ifdef MODULE
+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
+int qla1280_check_for_dead_scsi_bus(scsi_qla_host_t *ha, srb_t *sp)
+{
+ uint16_t config_reg, scsi_control;
+ device_reg_t *reg = ha->iobase;
+ uint32_t b;
+ Scsi_Cmnd *cp;
+
+ /*
+ * If SCSI Bus is Dead because of bad termination,
+ * we will return a status of Selection timeout.
+ */
+
+ cp = sp->cmd;
+ b = SCSI_BUS_32(cp);
+ if (ha->bus_settings[b].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)
+ {
+ CMD_RESULT(cp) = DID_NO_CONNECT << 16;
+ CMD_HANDLE(cp) = (unsigned char *) 0;
+ /* ha->actthreads--; */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+ sti();
+ (*(cp)->scsi_done)(cp);
+ cli();
+#else
+ (*(cp)->scsi_done)(cp);
+#endif
+ return(TRUE); /* bus is dead */
+ }
+ else
+ {
+ ha->bus_settings[b].scsi_bus_dead = FALSE;
+ ha->bus_settings[b].failed_reset_count= 0;
+ }
+ }
+ return(FALSE); /* bus is not dead */
+}
+
+STATIC uint8_t
+qla12160_set_target_parameters(scsi_qla_host_t *ha, uint32_t b, uint32_t t, uint32_t l, nvram160_t *nv)
+{
+ uint16_t mb[MAILBOX_REGISTER_COUNT];
+
+ /* Set Target Parameters. */
+ mb[0] = MBC_SET_TARGET_PARAMETERS;
+ mb[1] = (uint16_t)(b ? t | BIT_7 :t);
+ mb[1] <<= 8;
+ mb[2] = nv->bus[b].target[t].parameter.c << 8;
+ mb[2] |= TP_AUTO_REQUEST_SENSE;
+ mb[2] &= ~TP_STOP_QUEUE;
+ mb[2] |= (nv->bus[b].target[t].flags.enable_ppr << 5);
+ mb[3] = nv->bus[b].target[t].flags.sync_offset << 8;
+ mb[3] |= nv->bus[b].target[t].sync_period;
+
+ mb[6] = nv->bus[b].target[t].flags.ppr_options << 8;
+ mb[6] |= nv->bus[b].target[t].flags.ppr_bus_width;
+ return( qla1280_mailbox_command(ha, BIT_6|BIT_3|BIT_2|BIT_1|BIT_0, &mb[0]) ) ;
+}
+
+STATIC void
+qla12160_get_target_parameters(scsi_qla_host_t *ha, uint32_t b, uint32_t t, uint32_t l)
+{
+ uint16_t mb[MAILBOX_REGISTER_COUNT];
+
+ mb[0] = MBC_GET_TARGET_PARAMETERS;
+ mb[1] = (uint16_t)(b ? t | BIT_7 :t);
+ 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(%d:%d:%d:%d): Synchronous tranfer at period %d, offset %d. \n",
+ (int)ha->host_no, b, t, l, (mb[3] &0xff), (mb[3] >> 8));
+
+ if ( (mb[2] & BIT_5) && ((mb[6] >> 8) & 0xff) >= 2 )
+ printk(KERN_INFO "scsi(%d:%d:%d:%d): Dual Transition enabled.\n",
+ (int)ha->host_no, b, t, l);
+}
+
+
+#ifdef QL_DEBUG_ROUTINES
+/****************************************************************************/
+/* Driver Debug Functions. */
+/****************************************************************************/
+
+/*
+ * Get byte from I/O port
+ */
+STATIC uint8_t
+qla1280_getbyte(uint8_t *port)
+{
+ uint8_t ret;
+
+#if MEMORY_MAPPED_IO
+ ret = *port;
+#else
+ ret = inb((int)port);
+#endif
+
+ if (ql_debug_print)
+ {
+ qla1280_print("qla1280_getbyte: address = ");
+ qla1280_output_number((uint32_t)port, 16);
+ qla1280_print(" data = 0x");
+ qla1280_output_number((uint32_t)ret, 16);
+ qla1280_print("\n\r");
+ }
+
+ return(ret);
+}
+
+/*
+ * Get word from I/O port
+ */
+STATIC uint16_t
+qla1280_getword(uint16_t *port)
+{
+ uint16_t ret;
+
+#if MEMORY_MAPPED_IO
+ ret = *port;
+#else
+ ret = inw((int)port);
+#endif
+
+ if (ql_debug_print)
+ {
+ qla1280_print("qla1280_getword: address = ");
+ qla1280_output_number((uint32_t)port, 16);
+ qla1280_print(" data = 0x");
+ qla1280_output_number((uint32_t)ret, 16);
+ qla1280_print("\n\r");
+ }
+
+ return(ret);
+}
+
+/*
+ * Get double word from I/O port
+ */
+STATIC uint32_t
+qla1280_getdword(uint32_t *port)
+{
+ uint32_t ret;
+
+#if MEMORY_MAPPED_IO
+ ret = *port;
+#else
+ ret = inl((int)port);
+#endif
+
+ if (ql_debug_print)
+ {
+ qla1280_print("qla1280_getdword: address = ");
+ qla1280_output_number((uint32_t)port, 16);
+ qla1280_print(" data = 0x");
+ qla1280_output_number((uint32_t)ret, 16);
+ qla1280_print("\n\r");
+ }
+
+ return(ret);
+}
+
+/*
+ * Send byte to I/O port
+ */
+STATIC void
+qla1280_putbyte(uint8_t *port, uint8_t data)
+{
+#if MEMORY_MAPPED_IO
+ *port = data;
+#else
+ outb(data, (int)port);
+#endif
+
+ if (ql_debug_print)
+ {
+ qla1280_print("qla1280_putbyte: address = ");
+ qla1280_output_number((uint32_t)port, 16);
+ qla1280_print(" data = 0x");
+ qla1280_output_number((uint32_t)data, 16);
+ qla1280_print("\n\r");
+ }
+}
+
+/*
+ * Send word to I/O port
+ */
+STATIC void
+qla1280_putword(uint16_t *port, uint16_t data)
+{
+#if MEMORY_MAPPED_IO
+ *port = data;
+#else
+#ifdef _LINUX_IOPORTS
+ outw(data, (int)port);
+#else
+ outw((int)port, data);
+#endif
+#endif
+
+ if (ql_debug_print)
+ {
+ qla1280_print("qla1280_putword: address = ");
+ qla1280_output_number((uint32_t)port, 16);
+ qla1280_print(" data = 0x");
+ qla1280_output_number((uint32_t)data, 16);
+ qla1280_print("\n\r");
+ }
+}
+
+/*
+ * Send double word to I/O port
+ */
+STATIC void
+qla1280_putdword(uint32_t *port, uint32_t data)
+{
+#if MEMORY_MAPPED_IO
+ *port = data;
+#else
+#ifdef _LINUX_IOPORTS
+ outl(data,(int)port);
+#else
+ outl((int)port, data);
+#endif
+#endif
+
+ if (ql_debug_print)
+ {
+ qla1280_print("qla1280_putdword: address = ");
+ qla1280_output_number((uint32_t)port, 16);
+ qla1280_print(" data = 0x");
+ qla1280_output_number((uint32_t)data, 16);
+ qla1280_print("\n\r");
+ }
+}
+
+/*
+ * Dummy function to prevent warnings for
+ * declared and unused debug functions
+ */
+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);
+}
+
+/*
+ * Out character to COM2 port.
+ * PORT must be at standard address for COM2 = 0x2F8,
+ * or COM1 = 0x3F8
+ */
+#define OUTB(addr,data) outb((data),(addr))
+
+STATIC void
+qla1280_putc(uint8_t c)
+{
+#ifdef QL_DEBUG_CONSOLE
+ printk("%c", c);
+#else
+ int com_addr = 0x2f8;
+ int hardware_flow_control = 1;
+ int software_flow_control = 0;
+ uint8_t data;
+
+ /* Wait for transmitter holding and shift registers for empty. */
+ do
+ {
+ data = inb(com_addr+5);
+ }while (!(data & BIT_6));
+
+ /*
+ * Set BAUD rate for COM2 to 19200 (0x6)
+ */
+
+ /* Select rate divisor. */
+ OUTB(com_addr+3, 0x83);
+
+ /* BAUD rate divisor LSB. */
+ OUTB(com_addr, 0xc); /* 0xC = 9600 baud */
+
+ /* BAUD rate divisor MSB. */
+ OUTB(com_addr+1, 0);
+
+ /* Set No parity, 8 bits, 1 stop bit and
+ select interrupt enable register. */
+ OUTB(com_addr+3, 3);
+
+ /* Disable interrupts. */
+ OUTB(com_addr+1, 0);
+
+ /* Set data terminal ready and request to send */
+ OUTB(com_addr+4,3);
+
+ if (hardware_flow_control)
+ {
+ /* Wait for clear-to-send and data-set-ready */
+ do
+ {
+ data = inb(com_addr+6) & (BIT_5 + BIT_4);
+ }while (data != (BIT_5 + BIT_4));
+ }
+ else if (software_flow_control)
+ {
+ /* Test for data ready. */
+ data = inb(com_addr+5);
+ if (data & BIT_0)
+ {
+ /* If XOFF */
+ data = inb(com_addr);
+ if (data == '\023')
+ {
+ /* Wait for XON */
+ do
+ {
+ /* Wait for char */
+ do
+ {
+ data = inb(com_addr+5);
+ }while (!(data & BIT_0));
+ data = inb(com_addr);
+ }while (data != '\021');
+ }
+ }
+ }
+
+ /* Output character. */
+ OUTB(com_addr, c);
+#endif
+}
+
+/*
+ * Out NULL terminated string to COM port.
+ */
+STATIC void
+qla1280_print(caddr_t s)
+{
+ if (ql_debug_print)
+ {
+#ifdef QL_DEBUG_CONSOLE
+ printk("%s",s);
+#else
+ /* Output string. */
+ while (*s)
+ qla1280_putc(*s++);
+#endif
+ }
+}
+
+/*
+ * Output long number to COM port.
+ */
+STATIC void
+qla1280_output_number(uint32_t n, uint8_t base)
+{
+ int8_t str[12];
+ int8_t *s = &str[11];
+ int8_t output = 0;
+ int8_t hex = FALSE;
+
+ if (ql_debug_print)
+ {
+ if (base == 10 || base == 16)
+ {
+ if (base == 16 && n > 9)
+ hex = TRUE;
+
+ *s = 0;
+ do
+ {
+ s--;
+ *s = n % base;
+ if (*s > 9)
+ *s += 55;
+ else
+ *s += '0';
+ n /= base;
+ }while (n);
+
+ for (; *s; s++)
+ {
+ if (*s != '0')
+ output = 1;
+ if (output)
+ qla1280_putc(*s);
+ }
+ if (!output)
+ qla1280_putc(*--s);
+
+ if (hex)
+ qla1280_putc('h');
+ }
+ }
+}
+
+STATIC void
+qla1280_dump_buffer(caddr_t b, uint32_t size)
+{
+ uint32_t cnt;
+ uint8_t c;
+
+ if (ql_debug_print)
+ {
+ qla1280_print(
+ " 0 1 2 3 4 5 6 7 8 9 Ah Bh Ch Dh Eh Fh\n\r");
+ qla1280_print(
+ "---------------------------------------------------------------\n\r");
+
+ for (cnt = 0; cnt < size; )
+ {
+ c = *b++;
+ if (c < 16)
+ qla1280_putc(' ');
+ qla1280_output_number((uint32_t)c, 16);
+ cnt++;
+ if (!(cnt % 16))
+ qla1280_print("\n\r");
+ else if (c < 10)
+ qla1280_print(" ");
+ else
+ qla1280_putc(' ');
+ }
+ if (cnt % 16)
+ qla1280_print("\n\r");
+ }
+}
+/**************************************************************************
+ * ql1280_print_scsi_cmd
+ *
+ **************************************************************************/
+void qla1280_print_scsi_cmd(Scsi_Cmnd *cmd)
+{
+ scsi_qla_host_t *ha;
+ struct Scsi_Host *host = cmd->host;
+ srb_t *sp;
+ /* struct scatterlist *sg; */
+
+ int i;
+ ha = (scsi_qla_host_t *) host->hostdata;
+
+ ql_debug_print = 1;
+ sp = (srb_t *) CMD_SP(cmd);
+ sprintf(debug_buff,"SCSI Command @= 0x%p, Handle=0x%p\n\r", cmd, CMD_HANDLE(cmd));
+ qla1280_print(debug_buff);
+ sprintf(debug_buff," chan=%d, target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n\r",
+ cmd->channel, cmd->target, cmd->lun, cmd->cmd_len);
+ qla1280_print(debug_buff);
+ qla1280_print(" CDB = ");
+ for (i = 0; i < cmd->cmd_len; i++)
+ {
+ sprintf(debug_buff,"0x%02x ", cmd->cmnd[i]);
+ qla1280_print(debug_buff);
+ }
+ sprintf(debug_buff," seg_cnt =%d\n\r",cmd->use_sg);
+ qla1280_print(debug_buff);
+ sprintf(debug_buff," request buffer=0x%p, request buffer len=0x%x\n\r",cmd->request_buffer,cmd->request_bufflen);
+ qla1280_print(debug_buff);
+ /* if( cmd->use_sg )
+ {
+ sg = (struct scatterlist *) cmd->request_buffer;
+ qla1280_print(" SG buffer: \n\r");
+ qla1280_dump_buffer((caddr_t)sg, (cmd->use_sg*sizeof(struct scatterlist)) );
+ } */
+ sprintf(debug_buff," tag=%d, flags=0x%x, transfersize=0x%x \n\r",
+ cmd->tag, cmd->flags,cmd->transfersize );
+ qla1280_print(debug_buff);
+ sprintf(debug_buff," Pid=%d, SP=0x%p\n\r", (int)cmd->pid, CMD_SP(cmd));
+ qla1280_print(debug_buff);
+ sprintf(debug_buff," r_start=0x%lx, u_start=0x%lx\n\r",sp->r_start,sp->u_start);
+ qla1280_print(debug_buff);
+ sprintf(debug_buff," underflow size = 0x%x, direction=0x%x, req.cmd=0x%x \n\r", cmd->underflow, sp->dir,cmd->request.cmd);
+ qla1280_print(debug_buff);
+}
+/**************************************************************************
+ * ql1280_dump_device
+ *
+ **************************************************************************/
+void
+ql1280_dump_device(scsi_qla_host_t *ha)
+{
+
+ Scsi_Cmnd *cp;
+ srb_t *sp;
+ int i;
+ qla1280_print("Outstanding Commands on controller:\n\r");
+ 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(cp);
+ }
+
+}
+#endif
+
+#ifdef QLA1280_UNUSED
+/**************************************************************************
+ * ql1280_dump_regs
+ *
+ **************************************************************************/
+static void qla1280_dump_regs(struct Scsi_Host *host)
+{
+ printk("Mailbox registers:\n");
+ printk("qla1280 : mbox 0 0x%04x \n", inw(host->io_port + 0x70));
+ printk("qla1280 : mbox 1 0x%04x \n", inw(host->io_port + 0x72));
+ printk("qla1280 : mbox 2 0x%04x \n", inw(host->io_port + 0x74));
+ printk("qla1280 : mbox 3 0x%04x \n", inw(host->io_port + 0x76));
+ printk("qla1280 : mbox 4 0x%04x \n", inw(host->io_port + 0x78));
+ printk("qla1280 : mbox 5 0x%04x \n", inw(host->io_port + 0x7a));
+}
+#endif
+
+
+
+#if STOP_ON_ERROR
+/**************************************************************************
+ * ql1280_panic
+ *
+ **************************************************************************/
+static void qla1280_panic(char *cp, struct Scsi_Host *host)
+{
+ scsi_qla_host_t *ha;
+ long *fp;
+
+ ha = (scsi_qla_host_t *) host->hostdata;
+ printk("qla1280 - PANIC: %s\n",cp);
+ printk("Current time=0x%lx\n", jiffies);
+ printk("Number of pending commands =0x%lx\n", ha->actthreads);
+ printk("Number of SCSI queued commands =0x%lx\n", ha->qthreads);
+ printk("Number of free entries = (%d)\n",ha->req_q_cnt);
+ printk("Request Queue @ 0x%lx, Response Queue @ 0x%lx\n",
+ ha->request_dma,
+ ha->response_dma);
+ printk("Request In Ptr %d\n", ha->req_ring_index );
+ fp = (long *) &ha->flags;
+ printk("HA flags =0x%lx\n", *fp);
+ DEBUG2(ql_debug_print = 1;)
+ /* DEBUG2(ql1280_dump_device((scsi_qla_host_t *) host->hostdata)); */
+#ifdef QLA1280_UNUSED
+ qla1280_dump_regs(host);
+#endif
+ sti();
+ panic("Ooops");
+ /* cli();
+ for(;;)
+ {
+ barrier();
+ sti();
+ }
+ */
+}
+#endif
+
+#ifdef QLA1280_UNUSED
+static void qla1280_set_flags(char * s)
+{
+}
+#endif
+
+/**************************************************************************
+ * 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;
+
+#ifdef QLA1280_UNUSED
+ static struct
+ {
+ const char *name;
+ int siz;
+ void (*func)();
+ int arg;
+ } options[] =
+ {
+ { "dump_regs", 9, &qla1280_dump_regs, 0
+ },
+ { "verbose", 7, &qla1280_set_flags, 0x1
+ },
+ { "", 0, NULL, 0
+ }
+ };
+#endif
+
+ printk("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("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 );
+}
+
+/*
+ * 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-indent-level: 2
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -2
+ * c-argdecl-indent: 2
+ * c-label-offset: -2
+ * c-continued-statement-offset: 2
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
+
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)