diff options
Diffstat (limited to 'drivers/scsi/qla2xxx')
-rw-r--r-- | drivers/scsi/qla2xxx/Kconfig | 3 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_attr.c | 36 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_dbg.c | 124 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_dbg.h | 23 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_def.h | 78 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_dfs.c | 2 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_fw.h | 173 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_gbl.h | 33 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_gs.c | 16 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_init.c | 192 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_inline.h | 87 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_iocb.c | 5 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_isr.c | 223 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_mbx.c | 318 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_mid.c | 30 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 443 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_settings.h | 16 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_sup.c | 315 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_version.h | 6 |
19 files changed, 1266 insertions, 857 deletions
diff --git a/drivers/scsi/qla2xxx/Kconfig b/drivers/scsi/qla2xxx/Kconfig index 8c865b9e02b5..6208d562890d 100644 --- a/drivers/scsi/qla2xxx/Kconfig +++ b/drivers/scsi/qla2xxx/Kconfig @@ -16,7 +16,8 @@ config SCSI_QLA_FC 22xx ql2200_fw.bin 2300, 2312, 6312 ql2300_fw.bin 2322, 6322 ql2322_fw.bin - 24xx ql2400_fw.bin + 24xx, 54xx ql2400_fw.bin + 25xx ql2500_fw.bin Upon request, the driver caches the firmware image until the driver is unloaded. diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 4894dc886b62..413d8cd6a324 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -849,20 +849,20 @@ static void qla2x00_get_host_speed(struct Scsi_Host *shost) { scsi_qla_host_t *ha = to_qla_parent(shost_priv(shost)); - uint32_t speed = 0; + u32 speed = FC_PORTSPEED_UNKNOWN; switch (ha->link_data_rate) { case PORT_SPEED_1GB: - speed = 1; + speed = FC_PORTSPEED_1GBIT; break; case PORT_SPEED_2GB: - speed = 2; + speed = FC_PORTSPEED_2GBIT; break; case PORT_SPEED_4GB: - speed = 4; + speed = FC_PORTSPEED_4GBIT; break; case PORT_SPEED_8GB: - speed = 8; + speed = FC_PORTSPEED_8GBIT; break; } fc_host_speed(shost) = speed; @@ -900,7 +900,8 @@ qla2x00_get_starget_node_name(struct scsi_target *starget) u64 node_name = 0; list_for_each_entry(fcport, &ha->fcports, list) { - if (starget->id == fcport->os_target_id) { + if (fcport->rport && + starget->id == fcport->rport->scsi_target_id) { node_name = wwn_to_u64(fcport->node_name); break; } @@ -918,7 +919,8 @@ qla2x00_get_starget_port_name(struct scsi_target *starget) u64 port_name = 0; list_for_each_entry(fcport, &ha->fcports, list) { - if (starget->id == fcport->os_target_id) { + if (fcport->rport && + starget->id == fcport->rport->scsi_target_id) { port_name = wwn_to_u64(fcport->port_name); break; } @@ -936,7 +938,8 @@ qla2x00_get_starget_port_id(struct scsi_target *starget) uint32_t port_id = ~0U; list_for_each_entry(fcport, &ha->fcports, list) { - if (starget->id == fcport->os_target_id) { + if (fcport->rport && + starget->id == fcport->rport->scsi_target_id) { port_id = fcport->d_id.b.domain << 16 | fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa; break; @@ -1196,6 +1199,7 @@ struct fc_function_template qla2xxx_transport_functions = { .show_host_node_name = 1, .show_host_port_name = 1, .show_host_supported_classes = 1, + .show_host_supported_speeds = 1, .get_host_port_id = qla2x00_get_host_port_id, .show_host_port_id = 1, @@ -1276,9 +1280,23 @@ struct fc_function_template qla2xxx_transport_vport_functions = { void qla2x00_init_host_attr(scsi_qla_host_t *ha) { + u32 speed = FC_PORTSPEED_UNKNOWN; + fc_host_node_name(ha->host) = wwn_to_u64(ha->node_name); fc_host_port_name(ha->host) = wwn_to_u64(ha->port_name); fc_host_supported_classes(ha->host) = FC_COS_CLASS3; fc_host_max_npiv_vports(ha->host) = ha->max_npiv_vports;; fc_host_npiv_vports_inuse(ha->host) = ha->cur_vport_count; + + if (IS_QLA25XX(ha)) + speed = FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT | + FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT; + else if (IS_QLA24XX_TYPE(ha)) + speed = FC_PORTSPEED_4GBIT | FC_PORTSPEED_2GBIT | + FC_PORTSPEED_1GBIT; + else if (IS_QLA23XX(ha)) + speed = FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT; + else + speed = FC_PORTSPEED_1GBIT; + fc_host_supported_speeds(ha->host) = speed; } diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index d88e98c476b0..9d12d9f26209 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -1410,125 +1410,3 @@ qla2x00_dump_buffer(uint8_t * b, uint32_t size) if (cnt % 16) printk("\n"); } - -/************************************************************************** - * qla2x00_print_scsi_cmd - * Dumps out info about the scsi cmd and srb. - * Input - * cmd : struct scsi_cmnd - **************************************************************************/ -void -qla2x00_print_scsi_cmd(struct scsi_cmnd * cmd) -{ - int i; - struct scsi_qla_host *ha; - srb_t *sp; - - ha = shost_priv(cmd->device->host); - - sp = (srb_t *) cmd->SCp.ptr; - printk("SCSI Command @=0x%p, Handle=0x%p\n", cmd, cmd->host_scribble); - printk(" chan=0x%02x, target=0x%02x, lun=0x%02x, cmd_len=0x%02x\n", - cmd->device->channel, cmd->device->id, cmd->device->lun, - cmd->cmd_len); - printk(" CDB: "); - for (i = 0; i < cmd->cmd_len; i++) { - printk("0x%02x ", cmd->cmnd[i]); - } - printk("\n seg_cnt=%d, allowed=%d, retries=%d\n", - scsi_sg_count(cmd), cmd->allowed, cmd->retries); - printk(" request buffer=0x%p, request buffer len=0x%x\n", - scsi_sglist(cmd), scsi_bufflen(cmd)); - printk(" tag=%d, transfersize=0x%x\n", - cmd->tag, cmd->transfersize); - printk(" serial_number=%lx, SP=%p\n", cmd->serial_number, sp); - printk(" data direction=%d\n", cmd->sc_data_direction); - - if (!sp) - return; - - printk(" sp flags=0x%x\n", sp->flags); -} - -#if defined(QL_DEBUG_ROUTINES) -/* - * qla2x00_formatted_dump_buffer - * Prints string plus buffer. - * - * Input: - * string = Null terminated string (no newline at end). - * buffer = buffer address. - * wd_size = word size 8, 16, 32 or 64 bits - * count = number of words. - */ -void -qla2x00_formatted_dump_buffer(char *string, uint8_t * buffer, - uint8_t wd_size, uint32_t count) -{ - uint32_t cnt; - uint16_t *buf16; - uint32_t *buf32; - - if (strcmp(string, "") != 0) - printk("%s\n",string); - - switch (wd_size) { - case 8: - printk(" 0 1 2 3 4 5 6 7 " - "8 9 Ah Bh Ch Dh Eh Fh\n"); - printk("-----------------------------------------" - "-------------------------------------\n"); - - for (cnt = 1; cnt <= count; cnt++, buffer++) { - printk("%02x",*buffer); - if (cnt % 16 == 0) - printk("\n"); - else - printk(" "); - } - if (cnt % 16 != 0) - printk("\n"); - break; - case 16: - printk(" 0 2 4 6 8 Ah " - " Ch Eh\n"); - printk("-----------------------------------------" - "-------------\n"); - - buf16 = (uint16_t *) buffer; - for (cnt = 1; cnt <= count; cnt++, buf16++) { - printk("%4x",*buf16); - - if (cnt % 8 == 0) - printk("\n"); - else if (*buf16 < 10) - printk(" "); - else - printk(" "); - } - if (cnt % 8 != 0) - printk("\n"); - break; - case 32: - printk(" 0 4 8 Ch\n"); - printk("------------------------------------------\n"); - - buf32 = (uint32_t *) buffer; - for (cnt = 1; cnt <= count; cnt++, buf32++) { - printk("%8x", *buf32); - - if (cnt % 4 == 0) - printk("\n"); - else if (*buf32 < 10) - printk(" "); - else - printk(" "); - } - if (cnt % 4 != 0) - printk("\n"); - break; - default: - break; - } -} -#endif diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index 524598afc81c..2e9c0c097f5e 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -22,19 +22,7 @@ /* #define QL_DEBUG_LEVEL_13 */ /* Output fdmi function trace msgs */ /* #define QL_DEBUG_LEVEL_14 */ /* Output RSCN trace msgs */ /* #define QL_DEBUG_LEVEL_15 */ /* Output NPIV trace msgs */ -/* - * Local Macro Definitions. - */ -#if defined(QL_DEBUG_LEVEL_1) || defined(QL_DEBUG_LEVEL_2) || \ - defined(QL_DEBUG_LEVEL_3) || defined(QL_DEBUG_LEVEL_4) || \ - defined(QL_DEBUG_LEVEL_5) || defined(QL_DEBUG_LEVEL_6) || \ - defined(QL_DEBUG_LEVEL_7) || defined(QL_DEBUG_LEVEL_8) || \ - defined(QL_DEBUG_LEVEL_9) || defined(QL_DEBUG_LEVEL_10) || \ - defined(QL_DEBUG_LEVEL_11) || defined(QL_DEBUG_LEVEL_12) || \ - defined(QL_DEBUG_LEVEL_13) || defined(QL_DEBUG_LEVEL_14) || \ - defined(QL_DEBUG_LEVEL_15) - #define QL_DEBUG_ROUTINES -#endif +/* #define QL_DEBUG_LEVEL_16 */ /* Output ISP84XX trace msgs */ /* * Macros use for debugging the driver. @@ -54,6 +42,7 @@ #define DEBUG2_9_10(x) do { if (ql2xextended_error_logging) { x; } } while (0) #define DEBUG2_11(x) do { if (ql2xextended_error_logging) { x; } } while (0) #define DEBUG2_13(x) do { if (ql2xextended_error_logging) { x; } } while (0) +#define DEBUG2_16(x) do { if (ql2xextended_error_logging) { x; } } while (0) #if defined(QL_DEBUG_LEVEL_3) #define DEBUG3(x) do {x;} while (0) @@ -133,6 +122,12 @@ #define DEBUG15(x) do {} while (0) #endif +#if defined(QL_DEBUG_LEVEL_16) +#define DEBUG16(x) do {x;} while (0) +#else +#define DEBUG16(x) do {} while (0) +#endif + /* * Firmware Dump structure definition */ diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 3750319f4968..094d95f0764c 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -24,6 +24,7 @@ #include <linux/workqueue.h> #include <linux/firmware.h> #include <linux/aer.h> +#include <linux/mutex.h> #include <asm/semaphore.h> #include <scsi/scsi.h> @@ -192,9 +193,6 @@ typedef struct srb { uint16_t flags; - /* Single transfer DMA context */ - dma_addr_t dma_handle; - uint32_t request_sense_length; uint8_t *request_sense_ptr; } srb_t; @@ -1542,8 +1540,6 @@ typedef struct fc_port { atomic_t state; uint32_t flags; - unsigned int os_target_id; - int port_login_retry_count; int login_retry; atomic_t port_down_timer; @@ -1613,6 +1609,7 @@ typedef struct fc_port { #define CT_ACCEPT_RESPONSE 0x8002 #define CT_REASON_INVALID_COMMAND_CODE 0x01 #define CT_REASON_CANNOT_PERFORM 0x09 +#define CT_REASON_COMMAND_UNSUPPORTED 0x0b #define CT_EXPL_ALREADY_REGISTERED 0x10 #define NS_N_PORT_TYPE 0x01 @@ -2063,7 +2060,8 @@ struct isp_operations { void (*disable_intrs) (struct scsi_qla_host *); int (*abort_command) (struct scsi_qla_host *, srb_t *); - int (*abort_target) (struct fc_port *); + int (*target_reset) (struct fc_port *, unsigned int); + int (*lun_reset) (struct fc_port *, unsigned int); int (*fabric_login) (struct scsi_qla_host *, uint16_t, uint8_t, uint8_t, uint8_t, uint16_t *, uint8_t); int (*fabric_logout) (struct scsi_qla_host *, uint16_t, uint8_t, @@ -2117,6 +2115,46 @@ struct qla_msix_entry { #define WATCH_INTERVAL 1 /* number of seconds */ +/* Work events. */ +enum qla_work_type { + QLA_EVT_AEN, + QLA_EVT_HWE_LOG, +}; + + +struct qla_work_evt { + struct list_head list; + enum qla_work_type type; + u32 flags; +#define QLA_EVT_FLAG_FREE 0x1 + + union { + struct { + enum fc_host_event_code code; + u32 data; + } aen; + struct { + uint16_t code; + uint16_t d1, d2, d3; + } hwe; + } u; +}; + +struct qla_chip_state_84xx { + struct list_head list; + struct kref kref; + + void *bus; + spinlock_t access_lock; + struct mutex fw_update_mutex; + uint32_t fw_update; + uint32_t op_fw_version; + uint32_t op_fw_size; + uint32_t op_fw_seq_size; + uint32_t diag_fw_version; + uint32_t gold_fw_version; +}; + /* * Linux Host Adapter structure */ @@ -2155,6 +2193,7 @@ typedef struct scsi_qla_host { uint32_t vsan_enabled :1; uint32_t npiv_supported :1; uint32_t fce_enabled :1; + uint32_t hw_event_marker_found :1; } flags; atomic_t loop_state; @@ -2204,6 +2243,7 @@ typedef struct scsi_qla_host { #define DFLG_NO_CABLE BIT_4 #define PCI_DEVICE_ID_QLOGIC_ISP2532 0x2532 +#define PCI_DEVICE_ID_QLOGIC_ISP8432 0x8432 uint32_t device_type; #define DT_ISP2100 BIT_0 #define DT_ISP2200 BIT_1 @@ -2217,7 +2257,8 @@ typedef struct scsi_qla_host { #define DT_ISP5422 BIT_9 #define DT_ISP5432 BIT_10 #define DT_ISP2532 BIT_11 -#define DT_ISP_LAST (DT_ISP2532 << 1) +#define DT_ISP8432 BIT_12 +#define DT_ISP_LAST (DT_ISP8432 << 1) #define DT_IIDMA BIT_26 #define DT_FWI2 BIT_27 @@ -2239,12 +2280,16 @@ typedef struct scsi_qla_host { #define IS_QLA5422(ha) (DT_MASK(ha) & DT_ISP5422) #define IS_QLA5432(ha) (DT_MASK(ha) & DT_ISP5432) #define IS_QLA2532(ha) (DT_MASK(ha) & DT_ISP2532) +#define IS_QLA8432(ha) (DT_MASK(ha) & DT_ISP8432) #define IS_QLA23XX(ha) (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA2322(ha) || \ IS_QLA6312(ha) || IS_QLA6322(ha)) #define IS_QLA24XX(ha) (IS_QLA2422(ha) || IS_QLA2432(ha)) #define IS_QLA54XX(ha) (IS_QLA5422(ha) || IS_QLA5432(ha)) #define IS_QLA25XX(ha) (IS_QLA2532(ha)) +#define IS_QLA84XX(ha) (IS_QLA8432(ha)) +#define IS_QLA24XX_TYPE(ha) (IS_QLA24XX(ha) || IS_QLA54XX(ha) || \ + IS_QLA84XX(ha)) #define IS_IIDMA_CAPABLE(ha) ((ha)->device_type & DT_IIDMA) #define IS_FWI2_CAPABLE(ha) ((ha)->device_type & DT_FWI2) @@ -2356,6 +2401,8 @@ typedef struct scsi_qla_host { uint32_t login_retry_count; int max_q_depth; + struct list_head work_list; + /* Fibre Channel Device List. */ struct list_head fcports; @@ -2423,8 +2470,6 @@ typedef struct scsi_qla_host { #define MBX_TIMEDOUT BIT_5 #define MBX_ACCESS_TIMEDOUT BIT_6 - mbx_cmd_t mc; - /* Basic firmware related information. */ uint16_t fw_major_version; uint16_t fw_minor_version; @@ -2458,6 +2503,10 @@ typedef struct scsi_qla_host { uint64_t fce_wr, fce_rd; struct mutex fce_mutex; + uint32_t hw_event_start; + uint32_t hw_event_ptr; + uint32_t hw_event_pause_errors; + uint8_t host_str[16]; uint32_t pci_attr; uint16_t chip_revision; @@ -2493,6 +2542,13 @@ typedef struct scsi_qla_host { uint8_t fcode_revision[16]; uint32_t fw_revision[4]; + uint16_t fdt_odd_index; + uint32_t fdt_wrt_disable; + uint32_t fdt_erase_cmd; + uint32_t fdt_block_size; + uint32_t fdt_unprotect_sec_cmd; + uint32_t fdt_protect_sec_cmd; + /* Needed for BEACON */ uint16_t beacon_blink_led; uint8_t beacon_color_state; @@ -2538,6 +2594,8 @@ typedef struct scsi_qla_host { #define VP_ERR_ADAP_NORESOURCES 5 uint16_t max_npiv_vports; /* 63 or 125 per topoloty */ int cur_vport_count; + + struct qla_chip_state_84xx *cs84xx; } scsi_qla_host_t; diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c index 2cd899bfe84b..561a4411719d 100644 --- a/drivers/scsi/qla2xxx/qla_dfs.c +++ b/drivers/scsi/qla2xxx/qla_dfs.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index 9337e138ed63..078f2a15f40b 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -719,7 +719,7 @@ struct tsk_mgmt_entry { uint16_t timeout; /* Command timeout. */ - uint8_t lun[8]; /* FCP LUN (BE). */ + struct scsi_lun lun; /* FCP LUN (BE). */ uint32_t control_flags; /* Control Flags. */ #define TCF_NOTMCMD_TO_TARGET BIT_31 @@ -793,7 +793,19 @@ struct device_reg_24xx { #define FA_VPD_NVRAM_ADDR 0x48000 #define FA_FEATURE_ADDR 0x4C000 #define FA_FLASH_DESCR_ADDR 0x50000 -#define FA_HW_EVENT_ADDR 0x54000 +#define FA_HW_EVENT0_ADDR 0x54000 +#define FA_HW_EVENT1_ADDR 0x54200 +#define FA_HW_EVENT_SIZE 0x200 +#define FA_HW_EVENT_ENTRY_SIZE 4 +/* + * Flash Error Log Event Codes. + */ +#define HW_EVENT_RESET_ERR 0xF00B +#define HW_EVENT_ISP_ERR 0xF020 +#define HW_EVENT_PARITY_ERR 0xF022 +#define HW_EVENT_NVRAM_CHKSUM_ERR 0xF023 +#define HW_EVENT_FLASH_FW_ERR 0xF024 + #define FA_BOOT_LOG_ADDR 0x58000 #define FA_FW_DUMP0_ADDR 0x60000 #define FA_FW_DUMP1_ADDR 0x70000 @@ -1174,4 +1186,159 @@ struct vf_evfp_entry_24xx { }; /* END MID Support ***********************************************************/ + +/* Flash Description Table ***************************************************/ + +struct qla_fdt_layout { + uint8_t sig[4]; + uint16_t version; + uint16_t len; + uint16_t checksum; + uint8_t unused1[2]; + uint8_t model[16]; + uint16_t man_id; + uint16_t id; + uint8_t flags; + uint8_t erase_cmd; + uint8_t alt_erase_cmd; + uint8_t wrt_enable_cmd; + uint8_t wrt_enable_bits; + uint8_t wrt_sts_reg_cmd; + uint8_t unprotect_sec_cmd; + uint8_t read_man_id_cmd; + uint32_t block_size; + uint32_t alt_block_size; + uint32_t flash_size; + uint32_t wrt_enable_data; + uint8_t read_id_addr_len; + uint8_t wrt_disable_bits; + uint8_t read_dev_id_len; + uint8_t chip_erase_cmd; + uint16_t read_timeout; + uint8_t protect_sec_cmd; + uint8_t unused2[65]; +}; + +/* 84XX Support **************************************************************/ + +#define MBA_ISP84XX_ALERT 0x800f /* Alert Notification. */ +#define A84_PANIC_RECOVERY 0x1 +#define A84_OP_LOGIN_COMPLETE 0x2 +#define A84_DIAG_LOGIN_COMPLETE 0x3 +#define A84_GOLD_LOGIN_COMPLETE 0x4 + +#define MBC_ISP84XX_RESET 0x3a /* Reset. */ + +#define FSTATE_REMOTE_FC_DOWN BIT_0 +#define FSTATE_NSL_LINK_DOWN BIT_1 +#define FSTATE_IS_DIAG_FW BIT_2 +#define FSTATE_LOGGED_IN BIT_3 +#define FSTATE_WAITING_FOR_VERIFY BIT_4 + +#define VERIFY_CHIP_IOCB_TYPE 0x1B +struct verify_chip_entry_84xx { + uint8_t entry_type; + uint8_t entry_count; + uint8_t sys_defined; + uint8_t entry_status; + + uint32_t handle; + + uint16_t options; +#define VCO_DONT_UPDATE_FW BIT_0 +#define VCO_FORCE_UPDATE BIT_1 +#define VCO_DONT_RESET_UPDATE BIT_2 +#define VCO_DIAG_FW BIT_3 +#define VCO_END_OF_DATA BIT_14 +#define VCO_ENABLE_DSD BIT_15 + + uint16_t reserved_1; + + uint16_t data_seg_cnt; + uint16_t reserved_2[3]; + + uint32_t fw_ver; + uint32_t exchange_address; + + uint32_t reserved_3[3]; + uint32_t fw_size; + uint32_t fw_seq_size; + uint32_t relative_offset; + + uint32_t dseg_address[2]; + uint32_t dseg_length; +}; + +struct verify_chip_rsp_84xx { + uint8_t entry_type; + uint8_t entry_count; + uint8_t sys_defined; + uint8_t entry_status; + + uint32_t handle; + + uint16_t comp_status; +#define CS_VCS_CHIP_FAILURE 0x3 +#define CS_VCS_BAD_EXCHANGE 0x8 +#define CS_VCS_SEQ_COMPLETEi 0x40 + + uint16_t failure_code; +#define VFC_CHECKSUM_ERROR 0x1 +#define VFC_INVALID_LEN 0x2 +#define VFC_ALREADY_IN_PROGRESS 0x8 + + uint16_t reserved_1[4]; + + uint32_t fw_ver; + uint32_t exchange_address; + + uint32_t reserved_2[6]; +}; + +#define ACCESS_CHIP_IOCB_TYPE 0x2B +struct access_chip_84xx { + uint8_t entry_type; + uint8_t entry_count; + uint8_t sys_defined; + uint8_t entry_status; + + uint32_t handle; + + uint16_t options; +#define ACO_DUMP_MEMORY 0x0 +#define ACO_LOAD_MEMORY 0x1 +#define ACO_CHANGE_CONFIG_PARAM 0x2 +#define ACO_REQUEST_INFO 0x3 + + uint16_t reserved1; + + uint16_t dseg_count; + uint16_t reserved2[3]; + + uint32_t parameter1; + uint32_t parameter2; + uint32_t parameter3; + + uint32_t reserved3[3]; + uint32_t total_byte_cnt; + uint32_t reserved4; + + uint32_t dseg_address[2]; + uint32_t dseg_length; +}; + +struct access_chip_rsp_84xx { + uint8_t entry_type; + uint8_t entry_count; + uint8_t sys_defined; + uint8_t entry_status; + + uint32_t handle; + + uint16_t comp_status; + uint16_t failure_code; + uint32_t residual_count; + + uint32_t reserved[12]; +}; #endif diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 193f688ec3d7..a9571c214a9e 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -38,9 +38,6 @@ extern int qla2x00_loop_resync(scsi_qla_host_t *); extern int qla2x00_fabric_login(scsi_qla_host_t *, fc_port_t *, uint16_t *); extern int qla2x00_local_device_login(scsi_qla_host_t *, fc_port_t *); -extern void qla2x00_restart_queues(scsi_qla_host_t *, uint8_t); - -extern void qla2x00_rescan_fcports(scsi_qla_host_t *); extern void qla2x00_update_fcports(scsi_qla_host_t *); extern int qla2x00_abort_isp(scsi_qla_host_t *); @@ -50,6 +47,8 @@ extern void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *); extern void qla2x00_alloc_fw_dump(scsi_qla_host_t *); extern void qla2x00_try_to_stop_firmware(scsi_qla_host_t *); +extern void qla84xx_put_chip(struct scsi_qla_host *); + /* * Global Data in qla_os.c source file. */ @@ -67,6 +66,10 @@ extern int num_hosts; extern int qla2x00_loop_reset(scsi_qla_host_t *); extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); +extern int qla2x00_post_aen_work(struct scsi_qla_host *, enum + fc_host_event_code, u32); +extern int qla2x00_post_hwe_work(struct scsi_qla_host *, uint16_t , uint16_t, + uint16_t, uint16_t); /* * Global Functions in qla_mid.c source file. @@ -149,12 +152,17 @@ extern int qla2x00_issue_iocb(scsi_qla_host_t *, void *, dma_addr_t, size_t); extern int +qla2x00_issue_iocb_timeout(scsi_qla_host_t *, void *, dma_addr_t, size_t, + uint32_t); + +extern int qla2x00_abort_command(scsi_qla_host_t *, srb_t *); -#if USE_ABORT_TGT extern int -qla2x00_abort_target(fc_port_t *); -#endif +qla2x00_abort_target(struct fc_port *, unsigned int); + +extern int +qla2x00_lun_reset(struct fc_port *, unsigned int); extern int qla2x00_get_adapter_id(scsi_qla_host_t *, uint16_t *, uint8_t *, uint8_t *, @@ -220,7 +228,8 @@ qla24xx_get_isp_stats(scsi_qla_host_t *, struct link_statistics *, dma_addr_t); extern int qla24xx_abort_command(scsi_qla_host_t *, srb_t *); -extern int qla24xx_abort_target(fc_port_t *); +extern int qla24xx_abort_target(struct fc_port *, unsigned int); +extern int qla24xx_lun_reset(struct fc_port *, unsigned int); extern int qla2x00_set_serdes_params(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t); @@ -246,6 +255,8 @@ qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t); extern int qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *); +extern int qla84xx_verify_chip(struct scsi_qla_host *, uint16_t *); + /* * Global Function Prototypes in qla_isr.c source file. */ @@ -298,6 +309,11 @@ extern uint8_t *qla25xx_read_optrom_data(struct scsi_qla_host *, uint8_t *, extern int qla2x00_get_flash_version(scsi_qla_host_t *, void *); extern int qla24xx_get_flash_version(scsi_qla_host_t *, void *); +extern int qla2xxx_hw_event_log(scsi_qla_host_t *, uint16_t , uint16_t, + uint16_t, uint16_t); + +extern void qla2xxx_get_flash_info(scsi_qla_host_t *); + /* * Global Function Prototypes in qla_dbg.c source file. */ @@ -307,7 +323,6 @@ extern void qla24xx_fw_dump(scsi_qla_host_t *, int); extern void qla25xx_fw_dump(scsi_qla_host_t *, int); extern void qla2x00_dump_regs(scsi_qla_host_t *); extern void qla2x00_dump_buffer(uint8_t *, uint32_t); -extern void qla2x00_print_scsi_cmd(struct scsi_cmnd *); /* * Global Function Prototypes in qla_gs.c source file. diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index c1808763d40e..750d7ef83aae 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -1,17 +1,11 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ #include "qla_def.h" -static inline struct ct_sns_req * -qla2x00_prep_ct_req(struct ct_sns_req *, uint16_t, uint16_t); - -static inline struct sns_cmd_pkt * -qla2x00_prep_sns_cmd(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t); - static int qla2x00_sns_ga_nxt(scsi_qla_host_t *, fc_port_t *); static int qla2x00_sns_gid_pt(scsi_qla_host_t *, sw_info_t *); static int qla2x00_sns_gpn_id(scsi_qla_host_t *, sw_info_t *); @@ -1538,7 +1532,7 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha) eiter->a.sup_speed = __constant_cpu_to_be32( FDMI_PORT_SPEED_1GB|FDMI_PORT_SPEED_2GB| FDMI_PORT_SPEED_4GB|FDMI_PORT_SPEED_8GB); - else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) + else if (IS_QLA24XX_TYPE(ha)) eiter->a.sup_speed = __constant_cpu_to_be32( FDMI_PORT_SPEED_1GB|FDMI_PORT_SPEED_2GB| FDMI_PORT_SPEED_4GB); @@ -1847,8 +1841,10 @@ qla2x00_gpsc(scsi_qla_host_t *ha, sw_info_t *list) "GPSC")) != QLA_SUCCESS) { /* FM command unsupported? */ if (rval == QLA_INVALID_COMMAND && - ct_rsp->header.reason_code == - CT_REASON_INVALID_COMMAND_CODE) { + (ct_rsp->header.reason_code == + CT_REASON_INVALID_COMMAND_CODE || + ct_rsp->header.reason_code == + CT_REASON_COMMAND_UNSUPPORTED)) { DEBUG2(printk("scsi(%ld): GPSC command " "unsupported, disabling query...\n", ha->host_no)); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 364be7d06875..01e26087c1dd 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -15,14 +15,6 @@ #include <asm/prom.h> #endif -/* XXX(hch): this is ugly, but we don't want to pull in exioctl.h */ -#ifndef EXT_IS_LUN_BIT_SET -#define EXT_IS_LUN_BIT_SET(P,L) \ - (((P)->mask[L/8] & (0x80 >> (L%8)))?1:0) -#define EXT_SET_LUN_BIT(P,L) \ - ((P)->mask[L/8] |= (0x80 >> (L%8))) -#endif - /* * QLogic ISP2x00 Hardware Support Function Prototypes. */ @@ -45,6 +37,9 @@ static int qla2x00_restart_isp(scsi_qla_host_t *); static int qla2x00_find_new_loop_id(scsi_qla_host_t *ha, fc_port_t *dev); +static struct qla_chip_state_84xx *qla84xx_get_chip(struct scsi_qla_host *); +static int qla84xx_init_chip(scsi_qla_host_t *); + /****************************************************************************/ /* QLogic ISP2x00 Hardware Support Functions. */ /****************************************************************************/ @@ -114,6 +109,15 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha) rval = qla2x00_setup_chip(ha); if (rval) return (rval); + qla2xxx_get_flash_info(ha); + } + if (IS_QLA84XX(ha)) { + ha->cs84xx = qla84xx_get_chip(ha); + if (!ha->cs84xx) { + qla_printk(KERN_ERR, ha, + "Unable to configure ISP84XX.\n"); + return QLA_FUNCTION_FAILED; + } } rval = qla2x00_init_rings(ha); @@ -500,6 +504,7 @@ qla2x00_reset_chip(scsi_qla_host_t *ha) static inline void qla24xx_reset_risc(scsi_qla_host_t *ha) { + int hw_evt = 0; unsigned long flags = 0; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; uint32_t cnt, d2; @@ -528,6 +533,8 @@ qla24xx_reset_risc(scsi_qla_host_t *ha) d2 = (uint32_t) RD_REG_WORD(®->mailbox0); barrier(); } + if (cnt == 0) + hw_evt = 1; /* Wait for soft-reset to complete. */ d2 = RD_REG_DWORD(®->ctrl_status); @@ -536,6 +543,10 @@ qla24xx_reset_risc(scsi_qla_host_t *ha) d2 = RD_REG_DWORD(®->ctrl_status); barrier(); } + if (cnt == 0 || hw_evt) + qla2xxx_hw_event_log(ha, HW_EVENT_RESET_ERR, + RD_REG_WORD(®->mailbox1), RD_REG_WORD(®->mailbox2), + RD_REG_WORD(®->mailbox3)); WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_RESET); RD_REG_DWORD(®->hccr); @@ -1243,10 +1254,10 @@ static int qla2x00_fw_ready(scsi_qla_host_t *ha) { int rval; - unsigned long wtime, mtime; + unsigned long wtime, mtime, cs84xx_time; uint16_t min_wait; /* Minimum wait time if loop is down */ uint16_t wait_time; /* Wait time if loop is coming ready */ - uint16_t fw_state; + uint16_t state[3]; rval = QLA_SUCCESS; @@ -1275,12 +1286,34 @@ qla2x00_fw_ready(scsi_qla_host_t *ha) ha->host_no)); do { - rval = qla2x00_get_firmware_state(ha, &fw_state); + rval = qla2x00_get_firmware_state(ha, state); if (rval == QLA_SUCCESS) { - if (fw_state < FSTATE_LOSS_OF_SYNC) { + if (state[0] < FSTATE_LOSS_OF_SYNC) { ha->device_flags &= ~DFLG_NO_CABLE; } - if (fw_state == FSTATE_READY) { + if (IS_QLA84XX(ha) && state[0] != FSTATE_READY) { + DEBUG16(printk("scsi(%ld): fw_state=%x " + "84xx=%x.\n", ha->host_no, state[0], + state[2])); + if ((state[2] & FSTATE_LOGGED_IN) && + (state[2] & FSTATE_WAITING_FOR_VERIFY)) { + DEBUG16(printk("scsi(%ld): Sending " + "verify iocb.\n", ha->host_no)); + + cs84xx_time = jiffies; + rval = qla84xx_init_chip(ha); + if (rval != QLA_SUCCESS) + break; + + /* Add time taken to initialize. */ + cs84xx_time = jiffies - cs84xx_time; + wtime += cs84xx_time; + mtime += cs84xx_time; + DEBUG16(printk("scsi(%ld): Increasing " + "wait time by %ld. New time %ld\n", + ha->host_no, cs84xx_time, wtime)); + } + } else if (state[0] == FSTATE_READY) { DEBUG(printk("scsi(%ld): F/W Ready - OK \n", ha->host_no)); @@ -1294,7 +1327,7 @@ qla2x00_fw_ready(scsi_qla_host_t *ha) rval = QLA_FUNCTION_FAILED; if (atomic_read(&ha->loop_down_timer) && - fw_state != FSTATE_READY) { + state[0] != FSTATE_READY) { /* Loop down. Timeout on min_wait for states * other than Wait for Login. */ @@ -1319,11 +1352,11 @@ qla2x00_fw_ready(scsi_qla_host_t *ha) msleep(500); DEBUG3(printk("scsi(%ld): fw_state=%x curr time=%lx.\n", - ha->host_no, fw_state, jiffies)); + ha->host_no, state[0], jiffies)); } while (1); DEBUG(printk("scsi(%ld): fw_state=%x curr time=%lx.\n", - ha->host_no, fw_state, jiffies)); + ha->host_no, state[0], jiffies)); if (rval) { DEBUG2_3(printk("scsi(%ld): Firmware ready **** FAILED ****.\n", @@ -1555,6 +1588,10 @@ qla2x00_nvram_config(scsi_qla_host_t *ha) qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet " "invalid -- WWPN) defaults.\n"); + if (chksum) + qla2xxx_hw_event_log(ha, HW_EVENT_NVRAM_CHKSUM_ERR, 0, + MSW(chksum), LSW(chksum)); + /* * Set default initialization control block. */ @@ -2165,20 +2202,6 @@ cleanup_allocation: } static void -qla2x00_probe_for_all_luns(scsi_qla_host_t *ha) -{ - fc_port_t *fcport; - - qla2x00_mark_all_devices_lost(ha, 0); - list_for_each_entry(fcport, &ha->fcports, list) { - if (fcport->port_type != FCT_TARGET) - continue; - - qla2x00_update_fcport(ha, fcport); - } -} - -static void qla2x00_iidma_fcport(scsi_qla_host_t *ha, fc_port_t *fcport) { #define LS_UNKNOWN 2 @@ -2251,10 +2274,6 @@ qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport) if (fcport->port_type == FCT_TARGET) rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET; fc_remote_port_rolechg(rport, rport_ids.roles); - - if (rport->scsi_target_id != -1 && - rport->scsi_target_id < ha->host->max_id) - fcport->os_target_id = rport->scsi_target_id; } /* @@ -2434,7 +2453,8 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha) if (fcport->loop_id == FC_NO_LOOP_ID) { fcport->loop_id = next_loopid; - rval = qla2x00_find_new_loop_id(ha, fcport); + rval = qla2x00_find_new_loop_id( + to_qla_parent(ha), fcport); if (rval != QLA_SUCCESS) { /* Ran out of IDs to use */ break; @@ -2459,7 +2479,8 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha) /* Find a new loop ID to use. */ fcport->loop_id = next_loopid; - rval = qla2x00_find_new_loop_id(ha, fcport); + rval = qla2x00_find_new_loop_id(to_qla_parent(ha), + fcport); if (rval != QLA_SUCCESS) { /* Ran out of IDs to use */ break; @@ -3193,25 +3214,6 @@ qla2x00_loop_resync(scsi_qla_host_t *ha) } void -qla2x00_rescan_fcports(scsi_qla_host_t *ha) -{ - int rescan_done; - fc_port_t *fcport; - - rescan_done = 0; - list_for_each_entry(fcport, &ha->fcports, list) { - if ((fcport->flags & FCF_RESCAN_NEEDED) == 0) - continue; - - qla2x00_update_fcport(ha, fcport); - fcport->flags &= ~FCF_RESCAN_NEEDED; - - rescan_done = 1; - } - qla2x00_probe_for_all_luns(ha); -} - -void qla2x00_update_fcports(scsi_qla_host_t *ha) { fc_port_t *fcport; @@ -4044,16 +4046,16 @@ qla24xx_configure_vhba(scsi_qla_host_t *ha) if (!ha->parent) return -EINVAL; - rval = qla2x00_fw_ready(ha); + rval = qla2x00_fw_ready(ha->parent); if (rval == QLA_SUCCESS) { clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); - qla2x00_marker(ha, 0, 0, MK_SYNC_ALL); + qla2x00_marker(ha->parent, 0, 0, MK_SYNC_ALL); } ha->flags.management_server_logged_in = 0; /* Login to SNS first */ - qla24xx_login_fabric(ha, NPH_SNS, 0xff, 0xff, 0xfc, + qla24xx_login_fabric(ha->parent, NPH_SNS, 0xff, 0xff, 0xfc, mb, BIT_1); if (mb[0] != MBS_COMMAND_COMPLETE) { DEBUG15(qla_printk(KERN_INFO, ha, @@ -4067,7 +4069,77 @@ qla24xx_configure_vhba(scsi_qla_host_t *ha) atomic_set(&ha->loop_state, LOOP_UP); set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags); - rval = qla2x00_loop_resync(ha); + rval = qla2x00_loop_resync(ha->parent); return rval; } + +/* 84XX Support **************************************************************/ + +static LIST_HEAD(qla_cs84xx_list); +static DEFINE_MUTEX(qla_cs84xx_mutex); + +static struct qla_chip_state_84xx * +qla84xx_get_chip(struct scsi_qla_host *ha) +{ + struct qla_chip_state_84xx *cs84xx; + + mutex_lock(&qla_cs84xx_mutex); + + /* Find any shared 84xx chip. */ + list_for_each_entry(cs84xx, &qla_cs84xx_list, list) { + if (cs84xx->bus == ha->pdev->bus) { + kref_get(&cs84xx->kref); + goto done; + } + } + + cs84xx = kzalloc(sizeof(*cs84xx), GFP_KERNEL); + if (!cs84xx) + goto done; + + kref_init(&cs84xx->kref); + spin_lock_init(&cs84xx->access_lock); + mutex_init(&cs84xx->fw_update_mutex); + cs84xx->bus = ha->pdev->bus; + + list_add_tail(&cs84xx->list, &qla_cs84xx_list); +done: + mutex_unlock(&qla_cs84xx_mutex); + return cs84xx; +} + +static void +__qla84xx_chip_release(struct kref *kref) +{ + struct qla_chip_state_84xx *cs84xx = + container_of(kref, struct qla_chip_state_84xx, kref); + + mutex_lock(&qla_cs84xx_mutex); + list_del(&cs84xx->list); + mutex_unlock(&qla_cs84xx_mutex); + kfree(cs84xx); +} + +void +qla84xx_put_chip(struct scsi_qla_host *ha) +{ + if (ha->cs84xx) + kref_put(&ha->cs84xx->kref, __qla84xx_chip_release); +} + +static int +qla84xx_init_chip(scsi_qla_host_t *ha) +{ + int rval; + uint16_t status[2]; + + mutex_lock(&ha->cs84xx->fw_update_mutex); + + rval = qla84xx_verify_chip(ha, status); + + mutex_unlock(&ha->cs84xx->fw_update_mutex); + + return rval != QLA_SUCCESS || status[0] ? QLA_FUNCTION_FAILED: + QLA_SUCCESS; +} diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index 5d1a3f7c408f..e9bae27737d1 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -1,11 +1,10 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ -static __inline__ uint16_t qla2x00_debounce_register(volatile uint16_t __iomem *); /* * qla2x00_debounce_register * Debounce register. @@ -32,94 +31,12 @@ qla2x00_debounce_register(volatile uint16_t __iomem *addr) return (first); } -static __inline__ int qla2x00_normalize_dma_addr( - dma_addr_t *e_addr, uint32_t *e_len, - dma_addr_t *ne_addr, uint32_t *ne_len); - -/** - * qla2x00_normalize_dma_addr() - Normalize an DMA address. - * @e_addr: Raw DMA address - * @e_len: Raw DMA length - * @ne_addr: Normalized second DMA address - * @ne_len: Normalized second DMA length - * - * If the address does not span a 4GB page boundary, the contents of @ne_addr - * and @ne_len are undefined. @e_len is updated to reflect a normalization. - * - * Example: - * - * ffffabc0ffffeeee (e_addr) start of DMA address - * 0000000020000000 (e_len) length of DMA transfer - * ffffabc11fffeeed end of DMA transfer - * - * Is the 4GB boundary crossed? - * - * ffffabc0ffffeeee (e_addr) - * ffffabc11fffeeed (e_addr + e_len - 1) - * 00000001e0000003 ((e_addr ^ (e_addr + e_len - 1)) - * 0000000100000000 ((e_addr ^ (e_addr + e_len - 1)) & ~(0xffffffff) - * - * Compute start of second DMA segment: - * - * ffffabc0ffffeeee (e_addr) - * ffffabc1ffffeeee (0x100000000 + e_addr) - * ffffabc100000000 (0x100000000 + e_addr) & ~(0xffffffff) - * ffffabc100000000 (ne_addr) - * - * Compute length of second DMA segment: - * - * 00000000ffffeeee (e_addr & 0xffffffff) - * 0000000000001112 (0x100000000 - (e_addr & 0xffffffff)) - * 000000001fffeeee (e_len - (0x100000000 - (e_addr & 0xffffffff)) - * 000000001fffeeee (ne_len) - * - * Adjust length of first DMA segment - * - * 0000000020000000 (e_len) - * 0000000000001112 (e_len - ne_len) - * 0000000000001112 (e_len) - * - * Returns non-zero if the specified address was normalized, else zero. - */ -static __inline__ int -qla2x00_normalize_dma_addr( - dma_addr_t *e_addr, uint32_t *e_len, - dma_addr_t *ne_addr, uint32_t *ne_len) -{ - int normalized; - - normalized = 0; - if ((*e_addr ^ (*e_addr + *e_len - 1)) & ~(0xFFFFFFFFULL)) { - /* Compute normalized crossed address and len */ - *ne_addr = (0x100000000ULL + *e_addr) & ~(0xFFFFFFFFULL); - *ne_len = *e_len - (0x100000000ULL - (*e_addr & 0xFFFFFFFFULL)); - *e_len -= *ne_len; - - normalized++; - } - return (normalized); -} - -static __inline__ void qla2x00_poll(scsi_qla_host_t *); static inline void qla2x00_poll(scsi_qla_host_t *ha) { ha->isp_ops->intr_handler(0, ha); } -static __inline__ void qla2x00_check_fabric_devices(scsi_qla_host_t *); -/* - * This routine will wait for fabric devices for - * the reset delay. - */ -static __inline__ void qla2x00_check_fabric_devices(scsi_qla_host_t *ha) -{ - uint16_t fw_state; - - qla2x00_get_firmware_state(ha, &fw_state); -} - -static __inline__ scsi_qla_host_t * to_qla_parent(scsi_qla_host_t *); static __inline__ scsi_qla_host_t * to_qla_parent(scsi_qla_host_t *ha) { @@ -152,7 +69,6 @@ qla2x00_issue_marker(scsi_qla_host_t *ha, int ha_locked) return (QLA_SUCCESS); } -static inline uint8_t *host_to_fcp_swap(uint8_t *, uint32_t); static inline uint8_t * host_to_fcp_swap(uint8_t *fcp, uint32_t bsize) { @@ -166,7 +82,6 @@ host_to_fcp_swap(uint8_t *fcp, uint32_t bsize) return fcp; } -static inline int qla2x00_is_reserved_id(scsi_qla_host_t *, uint16_t); static inline int qla2x00_is_reserved_id(scsi_qla_host_t *ha, uint16_t loop_id) { diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 024c662ec34d..5489d5024673 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -11,9 +11,6 @@ #include <scsi/scsi_tcq.h> -static inline uint16_t qla2x00_get_cmd_direction(struct scsi_cmnd *cmd); -static inline cont_entry_t *qla2x00_prep_cont_type0_iocb(scsi_qla_host_t *); -static inline cont_a64_entry_t *qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *); static request_t *qla2x00_req_pkt(scsi_qla_host_t *ha); static void qla2x00_isp_cmd(scsi_qla_host_t *ha); diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index f0337036c7bb..285479b62d8f 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -14,9 +14,6 @@ static void qla2x00_process_completed_request(struct scsi_qla_host *, uint32_t); static void qla2x00_status_entry(scsi_qla_host_t *, void *); static void qla2x00_status_cont_entry(scsi_qla_host_t *, sts_cont_entry_t *); static void qla2x00_error_entry(scsi_qla_host_t *, sts_entry_t *); -static void qla2x00_ms_entry(scsi_qla_host_t *, ms_iocb_entry_t *); - -static void qla24xx_ms_entry(scsi_qla_host_t *, struct ct_entry_24xx *); /** * qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200. @@ -33,7 +30,6 @@ qla2100_intr_handler(int irq, void *dev_id) scsi_qla_host_t *ha; struct device_reg_2xxx __iomem *reg; int status; - unsigned long flags; unsigned long iter; uint16_t hccr; uint16_t mb[4]; @@ -48,7 +44,7 @@ qla2100_intr_handler(int irq, void *dev_id) reg = &ha->iobase->isp; status = 0; - spin_lock_irqsave(&ha->hardware_lock, flags); + spin_lock(&ha->hardware_lock); for (iter = 50; iter--; ) { hccr = RD_REG_WORD(®->hccr); if (hccr & HCCR_RISC_PAUSE) { @@ -99,7 +95,7 @@ qla2100_intr_handler(int irq, void *dev_id) RD_REG_WORD(®->hccr); } } - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_unlock(&ha->hardware_lock); if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && (status & MBX_INTERRUPT) && ha->flags.mbox_int) { @@ -125,7 +121,6 @@ qla2300_intr_handler(int irq, void *dev_id) scsi_qla_host_t *ha; struct device_reg_2xxx __iomem *reg; int status; - unsigned long flags; unsigned long iter; uint32_t stat; uint16_t hccr; @@ -141,7 +136,7 @@ qla2300_intr_handler(int irq, void *dev_id) reg = &ha->iobase->isp; status = 0; - spin_lock_irqsave(&ha->hardware_lock, flags); + spin_lock(&ha->hardware_lock); for (iter = 50; iter--; ) { stat = RD_REG_DWORD(®->u.isp2300.host_status); if (stat & HSR_RISC_PAUSED) { @@ -211,7 +206,7 @@ qla2300_intr_handler(int irq, void *dev_id) WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); RD_REG_WORD_RELAXED(®->hccr); } - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_unlock(&ha->hardware_lock); if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && (status & MBX_INTERRUPT) && ha->flags.mbox_int) { @@ -276,6 +271,9 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; uint32_t rscn_entry, host_pid; uint8_t rscn_queue_index; + unsigned long flags; + scsi_qla_host_t *vha; + int i; /* Setup to process RIO completion. */ handle_cnt = 0; @@ -351,6 +349,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n", mb[1], mb[2], mb[3]); + qla2x00_post_hwe_work(ha, mb[0], mb[1], mb[2], mb[3]); ha->isp_ops->fw_dump(ha, 1); if (IS_FWI2_CAPABLE(ha)) { @@ -375,6 +374,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) ha->host_no)); qla_printk(KERN_WARNING, ha, "ISP Request Transfer Error.\n"); + qla2x00_post_hwe_work(ha, mb[0], mb[1], mb[2], mb[3]); set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); break; @@ -383,6 +383,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) ha->host_no)); qla_printk(KERN_WARNING, ha, "ISP Response Transfer Error.\n"); + qla2x00_post_hwe_work(ha, mb[0], mb[1], mb[2], mb[3]); set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); break; @@ -410,6 +411,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags); ha->flags.management_server_logged_in = 0; + qla2x00_post_aen_work(ha, FCH_EVT_LIP, mb[1]); break; case MBA_LOOP_UP: /* Loop Up Event */ @@ -429,12 +431,14 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) link_speed); ha->flags.management_server_logged_in = 0; + qla2x00_post_aen_work(ha, FCH_EVT_LINKUP, ha->link_data_rate); break; case MBA_LOOP_DOWN: /* Loop Down Event */ - DEBUG2(printk("scsi(%ld): Asynchronous LOOP DOWN (%x).\n", - ha->host_no, mb[1])); - qla_printk(KERN_INFO, ha, "LOOP DOWN detected (%x).\n", mb[1]); + DEBUG2(printk("scsi(%ld): Asynchronous LOOP DOWN " + "(%x %x %x).\n", ha->host_no, mb[1], mb[2], mb[3])); + qla_printk(KERN_INFO, ha, "LOOP DOWN detected (%x %x %x).\n", + mb[1], mb[2], mb[3]); if (atomic_read(&ha->loop_state) != LOOP_DOWN) { atomic_set(&ha->loop_state, LOOP_DOWN); @@ -452,6 +456,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) ha->link_data_rate = PORT_SPEED_UNKNOWN; if (ql2xfdmienable) set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags); + qla2x00_post_aen_work(ha, FCH_EVT_LINKDOWN, 0); break; case MBA_LIP_RESET: /* LIP reset occurred */ @@ -475,6 +480,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) ha->operating_mode = LOOP; ha->flags.management_server_logged_in = 0; + qla2x00_post_aen_work(ha, FCH_EVT_LIPRESET, mb[1]); break; case MBA_POINT_TO_POINT: /* Point-to-Point */ @@ -538,6 +544,18 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) break; case MBA_PORT_UPDATE: /* Port database update */ + if ((ha->flags.npiv_supported) && (ha->num_vhosts)) { + for_each_mapped_vp_idx(ha, i) { + list_for_each_entry(vha, &ha->vp_list, + vp_list) { + if ((mb[3] & 0xff) + == vha->vp_idx) { + ha = vha; + break; + } + } + } + } /* * If PORT UPDATE is global (recieved LIP_OCCURED/LIP_RESET * event etc. earlier indicating loop is down) then process @@ -572,12 +590,18 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) break; case MBA_RSCN_UPDATE: /* State Change Registration */ - /* Check if the Vport has issued a SCR */ - if (ha->parent && test_bit(VP_SCR_NEEDED, &ha->vp_flags)) - break; - /* Only handle SCNs for our Vport index. */ - if (ha->flags.npiv_supported && ha->vp_idx != mb[3]) - break; + if ((ha->flags.npiv_supported) && (ha->num_vhosts)) { + for_each_mapped_vp_idx(ha, i) { + list_for_each_entry(vha, &ha->vp_list, + vp_list) { + if ((mb[3] & 0xff) + == vha->vp_idx) { + ha = vha; + break; + } + } + } + } DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n", ha->host_no)); @@ -612,6 +636,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); set_bit(RSCN_UPDATE, &ha->dpc_flags); + qla2x00_post_aen_work(ha, FCH_EVT_RSCN, rscn_entry); break; /* case MBA_RIO_RESPONSE: */ @@ -637,6 +662,42 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) DEBUG2(printk("scsi(%ld): Trace Notification -- %04x %04x.\n", ha->host_no, mb[1], mb[2])); break; + + case MBA_ISP84XX_ALERT: + DEBUG2(printk("scsi(%ld): ISP84XX Alert Notification -- " + "%04x %04x %04x\n", ha->host_no, mb[1], mb[2], mb[3])); + + spin_lock_irqsave(&ha->cs84xx->access_lock, flags); + switch (mb[1]) { + case A84_PANIC_RECOVERY: + qla_printk(KERN_INFO, ha, "Alert 84XX: panic recovery " + "%04x %04x\n", mb[2], mb[3]); + break; + case A84_OP_LOGIN_COMPLETE: + ha->cs84xx->op_fw_version = mb[3] << 16 | mb[2]; + DEBUG2(qla_printk(KERN_INFO, ha, "Alert 84XX:" + "firmware version %x\n", ha->cs84xx->op_fw_version)); + break; + case A84_DIAG_LOGIN_COMPLETE: + ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2]; + DEBUG2(qla_printk(KERN_INFO, ha, "Alert 84XX:" + "diagnostic firmware version %x\n", + ha->cs84xx->diag_fw_version)); + break; + case A84_GOLD_LOGIN_COMPLETE: + ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2]; + ha->cs84xx->fw_update = 1; + DEBUG2(qla_printk(KERN_INFO, ha, "Alert 84XX: gold " + "firmware version %x\n", + ha->cs84xx->gold_fw_version)); + break; + default: + qla_printk(KERN_ERR, ha, + "Alert 84xx: Invalid Alert %04x %04x %04x\n", + mb[1], mb[2], mb[3]); + } + spin_unlock_irqrestore(&ha->cs84xx->access_lock, flags); + break; } if (!ha->parent && ha->num_vhosts) @@ -803,9 +864,6 @@ qla2x00_process_response_queue(struct scsi_qla_host *ha) case STATUS_CONT_TYPE: qla2x00_status_cont_entry(ha, (sts_cont_entry_t *)pkt); break; - case MS_IOCB_TYPE: - qla2x00_ms_entry(ha, (ms_iocb_entry_t *)pkt); - break; default: /* Type Not Supported. */ DEBUG4(printk(KERN_WARNING @@ -1340,44 +1398,6 @@ qla2x00_error_entry(scsi_qla_host_t *ha, sts_entry_t *pkt) } /** - * qla2x00_ms_entry() - Process a Management Server entry. - * @ha: SCSI driver HA context - * @index: Response queue out pointer - */ -static void -qla2x00_ms_entry(scsi_qla_host_t *ha, ms_iocb_entry_t *pkt) -{ - srb_t *sp; - - DEBUG3(printk("%s(%ld): pkt=%p pkthandle=%d.\n", - __func__, ha->host_no, pkt, pkt->handle1)); - - /* Validate handle. */ - if (pkt->handle1 < MAX_OUTSTANDING_COMMANDS) - sp = ha->outstanding_cmds[pkt->handle1]; - else - sp = NULL; - - if (sp == NULL) { - DEBUG2(printk("scsi(%ld): MS entry - invalid handle\n", - ha->host_no)); - qla_printk(KERN_WARNING, ha, "MS entry - invalid handle\n"); - - set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); - return; - } - - CMD_COMPL_STATUS(sp->cmd) = le16_to_cpu(pkt->status); - CMD_ENTRY_STATUS(sp->cmd) = pkt->entry_status; - - /* Free outstanding command slot. */ - ha->outstanding_cmds[pkt->handle1] = NULL; - - qla2x00_sp_compl(ha, sp); -} - - -/** * qla24xx_mbx_completion() - Process mailbox command completions. * @ha: SCSI driver HA context * @mb0: Mailbox0 register @@ -1449,9 +1469,6 @@ qla24xx_process_response_queue(struct scsi_qla_host *ha) case STATUS_CONT_TYPE: qla2x00_status_cont_entry(ha, (sts_cont_entry_t *)pkt); break; - case MS_IOCB_TYPE: - qla24xx_ms_entry(ha, (struct ct_entry_24xx *)pkt); - break; case VP_RPT_ID_IOCB_TYPE: qla24xx_report_id_acquisition(ha, (struct vp_rpt_id_entry_24xx *)pkt); @@ -1533,7 +1550,6 @@ qla24xx_intr_handler(int irq, void *dev_id) scsi_qla_host_t *ha; struct device_reg_24xx __iomem *reg; int status; - unsigned long flags; unsigned long iter; uint32_t stat; uint32_t hccr; @@ -1549,13 +1565,19 @@ qla24xx_intr_handler(int irq, void *dev_id) reg = &ha->iobase->isp24; status = 0; - spin_lock_irqsave(&ha->hardware_lock, flags); + spin_lock(&ha->hardware_lock); for (iter = 50; iter--; ) { stat = RD_REG_DWORD(®->host_status); if (stat & HSRX_RISC_PAUSED) { if (pci_channel_offline(ha->pdev)) break; + if (ha->hw_event_pause_errors == 0) + qla2x00_post_hwe_work(ha, HW_EVENT_PARITY_ERR, + 0, MSW(stat), LSW(stat)); + else if (ha->hw_event_pause_errors < 0xffffffff) + ha->hw_event_pause_errors++; + hccr = RD_REG_DWORD(®->hccr); qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, " @@ -1597,7 +1619,7 @@ qla24xx_intr_handler(int irq, void *dev_id) WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); RD_REG_DWORD_RELAXED(®->hccr); } - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_unlock(&ha->hardware_lock); if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && (status & MBX_INTERRUPT) && ha->flags.mbox_int) { @@ -1608,66 +1630,21 @@ qla24xx_intr_handler(int irq, void *dev_id) return IRQ_HANDLED; } -/** - * qla24xx_ms_entry() - Process a Management Server entry. - * @ha: SCSI driver HA context - * @index: Response queue out pointer - */ -static void -qla24xx_ms_entry(scsi_qla_host_t *ha, struct ct_entry_24xx *pkt) -{ - srb_t *sp; - - DEBUG3(printk("%s(%ld): pkt=%p pkthandle=%d.\n", - __func__, ha->host_no, pkt, pkt->handle)); - - DEBUG9(printk("%s: ct pkt dump:\n", __func__)); - DEBUG9(qla2x00_dump_buffer((void *)pkt, sizeof(struct ct_entry_24xx))); - - /* Validate handle. */ - if (pkt->handle < MAX_OUTSTANDING_COMMANDS) - sp = ha->outstanding_cmds[pkt->handle]; - else - sp = NULL; - - if (sp == NULL) { - DEBUG2(printk("scsi(%ld): MS entry - invalid handle\n", - ha->host_no)); - DEBUG10(printk("scsi(%ld): MS entry - invalid handle\n", - ha->host_no)); - qla_printk(KERN_WARNING, ha, "MS entry - invalid handle %d\n", - pkt->handle); - - set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); - return; - } - - CMD_COMPL_STATUS(sp->cmd) = le16_to_cpu(pkt->comp_status); - CMD_ENTRY_STATUS(sp->cmd) = pkt->entry_status; - - /* Free outstanding command slot. */ - ha->outstanding_cmds[pkt->handle] = NULL; - - qla2x00_sp_compl(ha, sp); -} - static irqreturn_t qla24xx_msix_rsp_q(int irq, void *dev_id) { scsi_qla_host_t *ha; struct device_reg_24xx __iomem *reg; - unsigned long flags; ha = dev_id; reg = &ha->iobase->isp24; - spin_lock_irqsave(&ha->hardware_lock, flags); + spin_lock(&ha->hardware_lock); qla24xx_process_response_queue(ha); - WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_unlock(&ha->hardware_lock); return IRQ_HANDLED; } @@ -1678,7 +1655,6 @@ qla24xx_msix_default(int irq, void *dev_id) scsi_qla_host_t *ha; struct device_reg_24xx __iomem *reg; int status; - unsigned long flags; uint32_t stat; uint32_t hccr; uint16_t mb[4]; @@ -1687,13 +1663,19 @@ qla24xx_msix_default(int irq, void *dev_id) reg = &ha->iobase->isp24; status = 0; - spin_lock_irqsave(&ha->hardware_lock, flags); + spin_lock(&ha->hardware_lock); do { stat = RD_REG_DWORD(®->host_status); if (stat & HSRX_RISC_PAUSED) { if (pci_channel_offline(ha->pdev)) break; + if (ha->hw_event_pause_errors == 0) + qla2x00_post_hwe_work(ha, HW_EVENT_PARITY_ERR, + 0, MSW(stat), LSW(stat)); + else if (ha->hw_event_pause_errors < 0xffffffff) + ha->hw_event_pause_errors++; + hccr = RD_REG_DWORD(®->hccr); qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, " @@ -1734,7 +1716,7 @@ qla24xx_msix_default(int irq, void *dev_id) } WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); } while (0); - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_unlock(&ha->hardware_lock); if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && (status & MBX_INTERRUPT) && ha->flags.mbox_int) { @@ -1821,10 +1803,9 @@ qla2x00_request_irqs(scsi_qla_host_t *ha) { int ret; device_reg_t __iomem *reg = ha->iobase; - unsigned long flags; /* If possible, enable MSI-X. */ - if (!IS_QLA2432(ha) && !IS_QLA2532(ha)) + if (!IS_QLA2432(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha)) goto skip_msix; if (IS_QLA2432(ha) && (ha->chip_revision < QLA_MSIX_CHIP_REV_24XX || @@ -1859,7 +1840,7 @@ qla2x00_request_irqs(scsi_qla_host_t *ha) "MSI-X: Falling back-to INTa mode -- %d.\n", ret); skip_msix: - if (!IS_QLA24XX(ha) && !IS_QLA2532(ha)) + if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha)) goto skip_msi; ret = pci_enable_msi(ha->pdev); @@ -1882,7 +1863,7 @@ skip_msi: clear_risc_ints: ha->isp_ops->disable_intrs(ha); - spin_lock_irqsave(&ha->hardware_lock, flags); + spin_lock_irq(&ha->hardware_lock); if (IS_FWI2_CAPABLE(ha)) { WRT_REG_DWORD(®->isp24.hccr, HCCRX_CLR_HOST_INT); WRT_REG_DWORD(®->isp24.hccr, HCCRX_CLR_RISC_INT); @@ -1891,7 +1872,7 @@ clear_risc_ints: WRT_REG_WORD(®->isp.hccr, HCCR_CLR_RISC_INT); WRT_REG_WORD(®->isp.hccr, HCCR_CLR_HOST_INT); } - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_unlock_irq(&ha->hardware_lock); ha->isp_ops->enable_intrs(ha); fail: diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index bb103580e1ba..7d0a8a4c7719 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -310,7 +310,7 @@ qla2x00_load_ram(scsi_qla_host_t *ha, dma_addr_t req_dma, uint32_t risc_addr, } mcp->in_mb = MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -367,7 +367,7 @@ qla2x00_execute_fw(scsi_qla_host_t *ha, uint32_t risc_addr) } } - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -417,7 +417,7 @@ qla2x00_get_fw_version(scsi_qla_host_t *ha, uint16_t *major, uint16_t *minor, mcp->out_mb = MBX_0; mcp->in_mb = MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; mcp->flags = 0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; rval = qla2x00_mailbox_command(ha, mcp); /* Return mailbox data. */ @@ -466,7 +466,7 @@ qla2x00_get_fw_options(scsi_qla_host_t *ha, uint16_t *fwopts) mcp->mb[0] = MBC_GET_FIRMWARE_OPTION; mcp->out_mb = MBX_0; mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -524,7 +524,7 @@ qla2x00_set_fw_options(scsi_qla_host_t *ha, uint16_t *fwopts) mcp->mb[12] = 0; /* Undocumented, but used */ mcp->out_mb |= MBX_12|MBX_11|MBX_10; } - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -576,7 +576,7 @@ qla2x00_mbx_reg_test(scsi_qla_host_t *ha) mcp->mb[7] = 0x2525; mcp->out_mb = MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; mcp->in_mb = MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -587,6 +587,14 @@ qla2x00_mbx_reg_test(scsi_qla_host_t *ha) if (mcp->mb[5] != 0xA5A5 || mcp->mb[6] != 0x5A5A || mcp->mb[7] != 0x2525) rval = QLA_FUNCTION_FAILED; + if (rval == QLA_FUNCTION_FAILED) { + struct device_reg_24xx __iomem *reg = + &ha->iobase->isp24; + + qla2xxx_hw_event_log(ha, HW_EVENT_ISP_ERR, 0, + LSW(RD_REG_DWORD(®->hccr)), + LSW(RD_REG_DWORD(®->istatus))); + } } if (rval != QLA_SUCCESS) { @@ -640,7 +648,7 @@ qla2x00_verify_checksum(scsi_qla_host_t *ha, uint32_t risc_addr) mcp->in_mb |= MBX_1; } - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -674,8 +682,8 @@ qla2x00_verify_checksum(scsi_qla_host_t *ha, uint32_t risc_addr) * Kernel context. */ int -qla2x00_issue_iocb(scsi_qla_host_t *ha, void* buffer, dma_addr_t phys_addr, - size_t size) +qla2x00_issue_iocb_timeout(scsi_qla_host_t *ha, void *buffer, + dma_addr_t phys_addr, size_t size, uint32_t tov) { int rval; mbx_cmd_t mc; @@ -689,7 +697,7 @@ qla2x00_issue_iocb(scsi_qla_host_t *ha, void* buffer, dma_addr_t phys_addr, mcp->mb[7] = LSW(MSD(phys_addr)); mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; mcp->in_mb = MBX_2|MBX_0; - mcp->tov = 30; + mcp->tov = tov; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -710,6 +718,14 @@ qla2x00_issue_iocb(scsi_qla_host_t *ha, void* buffer, dma_addr_t phys_addr, return rval; } +int +qla2x00_issue_iocb(scsi_qla_host_t *ha, void *buffer, dma_addr_t phys_addr, + size_t size) +{ + return qla2x00_issue_iocb_timeout(ha, buffer, phys_addr, size, + MBX_TOV_SECONDS); +} + /* * qla2x00_abort_command * Abort command aborts a specified IOCB. @@ -760,7 +776,7 @@ qla2x00_abort_command(scsi_qla_host_t *ha, srb_t *sp) mcp->mb[6] = (uint16_t)sp->cmd->device->lun; mcp->out_mb = MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; mcp->in_mb = MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -776,36 +792,20 @@ qla2x00_abort_command(scsi_qla_host_t *ha, srb_t *sp) return rval; } -#if USE_ABORT_TGT -/* - * qla2x00_abort_target - * Issue abort target mailbox command. - * - * Input: - * ha = adapter block pointer. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ int -qla2x00_abort_target(fc_port_t *fcport) +qla2x00_abort_target(struct fc_port *fcport, unsigned int l) { - int rval; + int rval, rval2; mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; scsi_qla_host_t *ha; - if (fcport == NULL) - return 0; - DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no)); + l = l; ha = fcport->ha; mcp->mb[0] = MBC_ABORT_TARGET; - mcp->out_mb = MBX_2|MBX_1|MBX_0; + mcp->out_mb = MBX_9|MBX_2|MBX_1|MBX_0; if (HAS_EXTENDED_IDS(ha)) { mcp->mb[1] = fcport->loop_id; mcp->mb[10] = 0; @@ -814,27 +814,70 @@ qla2x00_abort_target(fc_port_t *fcport) mcp->mb[1] = fcport->loop_id << 8; } mcp->mb[2] = ha->loop_reset_delay; + mcp->mb[9] = ha->vp_idx; mcp->in_mb = MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__, + ha->host_no, rval)); + } - /* Issue marker command. */ - ha->marker_needed = 1; + /* Issue marker IOCB. */ + rval2 = qla2x00_marker(ha, fcport->loop_id, 0, MK_SYNC_ID); + if (rval2 != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed to issue Marker IOCB " + "(%x).\n", __func__, ha->host_no, rval2)); + } else { + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); + } + + return rval; +} + +int +qla2x00_lun_reset(struct fc_port *fcport, unsigned int l) +{ + int rval, rval2; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + scsi_qla_host_t *ha; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no)); + + ha = fcport->ha; + mcp->mb[0] = MBC_LUN_RESET; + mcp->out_mb = MBX_9|MBX_3|MBX_2|MBX_1|MBX_0; + if (HAS_EXTENDED_IDS(ha)) + mcp->mb[1] = fcport->loop_id; + else + mcp->mb[1] = fcport->loop_id << 8; + mcp->mb[2] = l; + mcp->mb[3] = 0; + mcp->mb[9] = ha->vp_idx; + mcp->in_mb = MBX_0; + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); if (rval != QLA_SUCCESS) { - DEBUG2_3_11(printk("qla2x00_abort_target(%ld): failed=%x.\n", + DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__, ha->host_no, rval)); + } + + /* Issue marker IOCB. */ + rval2 = qla2x00_marker(ha, fcport->loop_id, l, MK_SYNC_ID_LUN); + if (rval2 != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed to issue Marker IOCB " + "(%x).\n", __func__, ha->host_no, rval2)); } else { - /*EMPTY*/ - DEBUG11(printk("qla2x00_abort_target(%ld): done.\n", - ha->host_no)); + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); } return rval; } -#endif /* * qla2x00_get_adapter_id @@ -871,7 +914,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa, mcp->mb[9] = ha->vp_idx; mcp->out_mb = MBX_9|MBX_0; mcp->in_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); if (mcp->mb[0] == MBS_COMMAND_ERROR) @@ -928,7 +971,7 @@ qla2x00_get_retry_cnt(scsi_qla_host_t *ha, uint8_t *retry_cnt, uint8_t *tov, mcp->mb[0] = MBC_GET_RETRY_COUNT; mcp->out_mb = MBX_0; mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -995,7 +1038,7 @@ qla2x00_init_firmware(scsi_qla_host_t *ha, uint16_t size) mcp->in_mb = MBX_5|MBX_4|MBX_0; mcp->buf_size = size; mcp->flags = MBX_DMA_OUT; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; rval = qla2x00_mailbox_command(ha, mcp); if (rval != QLA_SUCCESS) { @@ -1173,7 +1216,7 @@ gpd_error_out: * Kernel context. */ int -qla2x00_get_firmware_state(scsi_qla_host_t *ha, uint16_t *dptr) +qla2x00_get_firmware_state(scsi_qla_host_t *ha, uint16_t *states) { int rval; mbx_cmd_t mc; @@ -1184,13 +1227,15 @@ qla2x00_get_firmware_state(scsi_qla_host_t *ha, uint16_t *dptr) mcp->mb[0] = MBC_GET_FIRMWARE_STATE; mcp->out_mb = MBX_0; - mcp->in_mb = MBX_2|MBX_1|MBX_0; - mcp->tov = 30; + mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); - /* Return firmware state. */ - *dptr = mcp->mb[1]; + /* Return firmware states. */ + states[0] = mcp->mb[1]; + states[1] = mcp->mb[2]; + states[2] = mcp->mb[3]; if (rval != QLA_SUCCESS) { /*EMPTY*/ @@ -1246,7 +1291,7 @@ qla2x00_get_port_name(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t *name, } mcp->in_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -1318,7 +1363,7 @@ qla2x00_lip_reset(scsi_qla_host_t *ha) mcp->mb[3] = 0; } mcp->in_mb = MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -1743,7 +1788,7 @@ qla2x00_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, } mcp->in_mb = MBX_1|MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -1791,7 +1836,7 @@ qla2x00_full_login_lip(scsi_qla_host_t *ha) mcp->mb[3] = 0; mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0; mcp->in_mb = MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -1852,7 +1897,7 @@ qla2x00_get_id_list(scsi_qla_host_t *ha, void *id_list, dma_addr_t id_list_dma, mcp->out_mb |= MBX_6|MBX_3|MBX_2|MBX_1; } mcp->in_mb = MBX_1|MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -1896,7 +1941,7 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *ha, uint16_t *cur_xchg_cnt, mcp->mb[0] = MBC_GET_RESOURCE_COUNTS; mcp->out_mb = MBX_0; mcp->in_mb = MBX_11|MBX_10|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -2036,7 +2081,7 @@ qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id, mcp->mb[1] = loop_id << 8; mcp->out_mb |= MBX_1; } - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = IOCTL_CMD; rval = qla2x00_mailbox_command(ha, mcp); @@ -2082,7 +2127,7 @@ qla24xx_get_isp_stats(scsi_qla_host_t *ha, struct link_statistics *stats, mcp->mb[10] = 0; mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0; mcp->in_mb = MBX_2|MBX_1|MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = IOCTL_CMD; rval = qla2x00_mailbox_command(ha, mcp); @@ -2180,17 +2225,15 @@ struct tsk_mgmt_cmd { } p; }; -int -qla24xx_abort_target(fc_port_t *fcport) +static int +__qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport, + unsigned int l) { - int rval; + int rval, rval2; struct tsk_mgmt_cmd *tsk; dma_addr_t tsk_dma; scsi_qla_host_t *ha, *pha; - if (fcport == NULL) - return 0; - DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no)); ha = fcport->ha; @@ -2207,47 +2250,61 @@ qla24xx_abort_target(fc_port_t *fcport) tsk->p.tsk.entry_count = 1; tsk->p.tsk.nport_handle = cpu_to_le16(fcport->loop_id); tsk->p.tsk.timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); - tsk->p.tsk.control_flags = __constant_cpu_to_le32(TCF_TARGET_RESET); + tsk->p.tsk.control_flags = cpu_to_le32(type); tsk->p.tsk.port_id[0] = fcport->d_id.b.al_pa; tsk->p.tsk.port_id[1] = fcport->d_id.b.area; tsk->p.tsk.port_id[2] = fcport->d_id.b.domain; tsk->p.tsk.vp_index = fcport->vp_idx; + if (type == TCF_LUN_RESET) { + int_to_scsilun(l, &tsk->p.tsk.lun); + host_to_fcp_swap((uint8_t *)&tsk->p.tsk.lun, + sizeof(tsk->p.tsk.lun)); + } rval = qla2x00_issue_iocb(ha, tsk, tsk_dma, 0); if (rval != QLA_SUCCESS) { - DEBUG2_3_11(printk("%s(%ld): failed to issue Target Reset IOCB " - "(%x).\n", __func__, ha->host_no, rval)); - goto atarget_done; + DEBUG2_3_11(printk("%s(%ld): failed to issue %s Reset IOCB " + "(%x).\n", __func__, ha->host_no, name, rval)); } else if (tsk->p.sts.entry_status != 0) { DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB " "-- error status (%x).\n", __func__, ha->host_no, tsk->p.sts.entry_status)); rval = QLA_FUNCTION_FAILED; - goto atarget_done; } else if (tsk->p.sts.comp_status != __constant_cpu_to_le16(CS_COMPLETE)) { DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB " "-- completion status (%x).\n", __func__, ha->host_no, le16_to_cpu(tsk->p.sts.comp_status))); rval = QLA_FUNCTION_FAILED; - goto atarget_done; } /* Issue marker IOCB. */ - rval = qla2x00_marker(ha, fcport->loop_id, 0, MK_SYNC_ID); - if (rval != QLA_SUCCESS) { + rval2 = qla2x00_marker(ha, fcport->loop_id, l, + type == TCF_LUN_RESET ? MK_SYNC_ID_LUN: MK_SYNC_ID); + if (rval2 != QLA_SUCCESS) { DEBUG2_3_11(printk("%s(%ld): failed to issue Marker IOCB " - "(%x).\n", __func__, ha->host_no, rval)); + "(%x).\n", __func__, ha->host_no, rval2)); } else { DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); } -atarget_done: dma_pool_free(pha->s_dma_pool, tsk, tsk_dma); return rval; } +int +qla24xx_abort_target(struct fc_port *fcport, unsigned int l) +{ + return __qla24xx_issue_tmf("Target", TCF_TARGET_RESET, fcport, l); +} + +int +qla24xx_lun_reset(struct fc_port *fcport, unsigned int l) +{ + return __qla24xx_issue_tmf("Lun", TCF_LUN_RESET, fcport, l); +} + #if 0 int @@ -2304,7 +2361,7 @@ qla2x00_set_serdes_params(scsi_qla_host_t *ha, uint16_t sw_em_1g, mcp->mb[4] = sw_em_4g | BIT_15; mcp->out_mb = MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; mcp->in_mb = MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -2372,7 +2429,7 @@ qla2x00_enable_eft_trace(scsi_qla_host_t *ha, dma_addr_t eft_dma, mcp->mb[7] = TC_AEN_DISABLE; mcp->out_mb = MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; mcp->in_mb = MBX_1|MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); if (rval != QLA_SUCCESS) { @@ -2401,7 +2458,7 @@ qla2x00_disable_eft_trace(scsi_qla_host_t *ha) mcp->mb[1] = TC_EFT_DISABLE; mcp->out_mb = MBX_1|MBX_0; mcp->in_mb = MBX_1|MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); if (rval != QLA_SUCCESS) { @@ -2441,7 +2498,7 @@ qla2x00_enable_fce_trace(scsi_qla_host_t *ha, dma_addr_t fce_dma, mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2| MBX_1|MBX_0; mcp->in_mb = MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); if (rval != QLA_SUCCESS) { @@ -2477,7 +2534,7 @@ qla2x00_disable_fce_trace(scsi_qla_host_t *ha, uint64_t *wr, uint64_t *rd) mcp->out_mb = MBX_2|MBX_1|MBX_0; mcp->in_mb = MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2| MBX_1|MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); if (rval != QLA_SUCCESS) { @@ -2525,7 +2582,7 @@ qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr, mcp->mb[10] = 0; mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; mcp->in_mb = MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -2559,7 +2616,7 @@ qla2x00_set_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id, mcp->mb[4] = mcp->mb[5] = 0; mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_1|MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -2877,7 +2934,7 @@ qla2x00_dump_ram(scsi_qla_host_t *ha, dma_addr_t req_dma, uint32_t addr, } mcp->in_mb = MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -2890,3 +2947,104 @@ qla2x00_dump_ram(scsi_qla_host_t *ha, dma_addr_t req_dma, uint32_t addr, return rval; } + +/* 84XX Support **************************************************************/ + +struct cs84xx_mgmt_cmd { + union { + struct verify_chip_entry_84xx req; + struct verify_chip_rsp_84xx rsp; + } p; +}; + +int +qla84xx_verify_chip(struct scsi_qla_host *ha, uint16_t *status) +{ + int rval, retry; + struct cs84xx_mgmt_cmd *mn; + dma_addr_t mn_dma; + uint16_t options; + unsigned long flags; + + DEBUG16(printk("%s(%ld): entered.\n", __func__, ha->host_no)); + + mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma); + if (mn == NULL) { + DEBUG2_3(printk("%s(%ld): failed to allocate Verify ISP84XX " + "IOCB.\n", __func__, ha->host_no)); + return QLA_MEMORY_ALLOC_FAILED; + } + + /* Force Update? */ + options = ha->cs84xx->fw_update ? VCO_FORCE_UPDATE : 0; + /* Diagnostic firmware? */ + /* options |= MENLO_DIAG_FW; */ + /* We update the firmware with only one data sequence. */ + options |= VCO_END_OF_DATA; + + retry = 0; + do { + memset(mn, 0, sizeof(*mn)); + mn->p.req.entry_type = VERIFY_CHIP_IOCB_TYPE; + mn->p.req.entry_count = 1; + mn->p.req.options = cpu_to_le16(options); + + DEBUG16(printk("%s(%ld): Dump of Verify Request.\n", __func__, + ha->host_no)); + DEBUG16(qla2x00_dump_buffer((uint8_t *)mn, + sizeof(*mn))); + + rval = qla2x00_issue_iocb_timeout(ha, mn, mn_dma, 0, 120); + if (rval != QLA_SUCCESS) { + DEBUG2_16(printk("%s(%ld): failed to issue Verify " + "IOCB (%x).\n", __func__, ha->host_no, rval)); + goto verify_done; + } + + DEBUG16(printk("%s(%ld): Dump of Verify Response.\n", __func__, + ha->host_no)); + DEBUG16(qla2x00_dump_buffer((uint8_t *)mn, + sizeof(*mn))); + + status[0] = le16_to_cpu(mn->p.rsp.comp_status); + status[1] = status[0] == CS_VCS_CHIP_FAILURE ? + le16_to_cpu(mn->p.rsp.failure_code) : 0; + DEBUG2_16(printk("%s(%ld): cs=%x fc=%x\n", __func__, + ha->host_no, status[0], status[1])); + + if (status[0] != CS_COMPLETE) { + rval = QLA_FUNCTION_FAILED; + if (!(options & VCO_DONT_UPDATE_FW)) { + DEBUG2_16(printk("%s(%ld): Firmware update " + "failed. Retrying without update " + "firmware.\n", __func__, ha->host_no)); + options |= VCO_DONT_UPDATE_FW; + options &= ~VCO_FORCE_UPDATE; + retry = 1; + } + } else { + DEBUG2_16(printk("%s(%ld): firmware updated to %x.\n", + __func__, ha->host_no, + le32_to_cpu(mn->p.rsp.fw_ver))); + + /* NOTE: we only update OP firmware. */ + spin_lock_irqsave(&ha->cs84xx->access_lock, flags); + ha->cs84xx->op_fw_version = + le32_to_cpu(mn->p.rsp.fw_ver); + spin_unlock_irqrestore(&ha->cs84xx->access_lock, + flags); + } + } while (retry); + +verify_done: + dma_pool_free(ha->s_dma_pool, mn, mn_dma); + + if (rval != QLA_SUCCESS) { + DEBUG2_16(printk("%s(%ld): failed=%x.\n", __func__, + ha->host_no, rval)); + } else { + DEBUG16(printk("%s(%ld): done.\n", __func__, ha->host_no)); + } + + return rval; +} diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index cf784cdafb01..f2b04979e5f0 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -1,20 +1,8 @@ /* - * QLOGIC LINUX SOFTWARE - * - * QLogic ISP2x00 device driver for Linux 2.6.x - * Copyright (C) 2003-2005 QLogic Corporation - * (www.qlogic.com) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. + * QLogic Fibre Channel HBA Driver + * Copyright (c) 2003-2008 QLogic Corporation * + * See LICENSE.qla2xxx for copyright and licensing details. */ #include "qla_def.h" @@ -28,8 +16,6 @@ #include <scsi/scsicam.h> #include <linux/delay.h> -void qla2x00_vp_stop_timer(scsi_qla_host_t *); - void qla2x00_vp_stop_timer(scsi_qla_host_t *vha) { @@ -268,9 +254,17 @@ qla2x00_vp_abort_isp(scsi_qla_host_t *vha) static int qla2x00_do_dpc_vp(scsi_qla_host_t *vha) { + scsi_qla_host_t *ha = vha->parent; + if (test_and_clear_bit(VP_IDX_ACQUIRED, &vha->vp_flags)) { /* VP acquired. complete port configuration */ - qla24xx_configure_vp(vha); + if (atomic_read(&ha->loop_state) == LOOP_READY) { + qla24xx_configure_vp(vha); + } else { + set_bit(VP_IDX_ACQUIRED, &vha->vp_flags); + set_bit(VP_DPC_NEEDED, &ha->dpc_flags); + } + return 0; } diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 3c1b43356adb..8b33b163b1d4 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -26,9 +26,6 @@ char qla2x00_version_str[40]; */ static struct kmem_cache *srb_cachep; -/* - * Ioctl related information. - */ int num_hosts; int ql2xlogintimeout = 20; module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR); @@ -103,9 +100,9 @@ static int qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *)); static int qla2xxx_eh_abort(struct scsi_cmnd *); static int qla2xxx_eh_device_reset(struct scsi_cmnd *); +static int qla2xxx_eh_target_reset(struct scsi_cmnd *); static int qla2xxx_eh_bus_reset(struct scsi_cmnd *); static int qla2xxx_eh_host_reset(struct scsi_cmnd *); -static int qla2x00_device_reset(scsi_qla_host_t *, fc_port_t *); static int qla2x00_change_queue_depth(struct scsi_device *, int); static int qla2x00_change_queue_type(struct scsi_device *, int); @@ -117,6 +114,7 @@ static struct scsi_host_template qla2x00_driver_template = { .eh_abort_handler = qla2xxx_eh_abort, .eh_device_reset_handler = qla2xxx_eh_device_reset, + .eh_target_reset_handler = qla2xxx_eh_target_reset, .eh_bus_reset_handler = qla2xxx_eh_bus_reset, .eh_host_reset_handler = qla2xxx_eh_host_reset, @@ -148,6 +146,7 @@ struct scsi_host_template qla24xx_driver_template = { .eh_abort_handler = qla2xxx_eh_abort, .eh_device_reset_handler = qla2xxx_eh_device_reset, + .eh_target_reset_handler = qla2xxx_eh_target_reset, .eh_bus_reset_handler = qla2xxx_eh_bus_reset, .eh_host_reset_handler = qla2xxx_eh_host_reset, @@ -253,9 +252,9 @@ qla24xx_pci_info_str(struct scsi_qla_host *ha, char *str) strcpy(str, "PCIe ("); if (lspeed == 1) - strcat(str, "2.5Gb/s "); + strcat(str, "2.5GT/s "); else if (lspeed == 2) - strcat(str, "5.0Gb/s "); + strcat(str, "5.0GT/s "); else strcat(str, "<unknown> "); snprintf(lwstr, sizeof(lwstr), "x%d)", lwidth); @@ -340,6 +339,8 @@ qla24xx_fw_version_str(struct scsi_qla_host *ha, char *str) strcat(str, "[T10 CRC] "); if (ha->fw_attributes & BIT_5) strcat(str, "[VI] "); + if (ha->fw_attributes & BIT_10) + strcat(str, "[84XX] "); if (ha->fw_attributes & BIT_13) strcat(str, "[Experimental]"); return str; @@ -570,8 +571,6 @@ qla2x00_wait_for_hba_online(scsi_qla_host_t *ha) else return_status = QLA_FUNCTION_FAILED; - DEBUG2(printk("%s return_status=%d\n",__func__,return_status)); - return (return_status); } @@ -685,7 +684,6 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) DEBUG2(printk("%s(%ld): aborting sp %p from RISC. pid=%ld.\n", __func__, ha->host_no, sp, serial)); - DEBUG3(qla2x00_print_scsi_cmd(cmd)); spin_unlock_irqrestore(&pha->hardware_lock, flags); if (ha->isp_ops->abort_command(ha, sp)) { @@ -719,190 +717,122 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) return ret; } -/************************************************************************** -* qla2x00_eh_wait_for_pending_target_commands -* -* Description: -* Waits for all the commands to come back from the specified target. -* -* Input: -* ha - pointer to scsi_qla_host structure. -* t - target -* Returns: -* Either SUCCESS or FAILED. -* -* Note: -**************************************************************************/ +enum nexus_wait_type { + WAIT_HOST = 0, + WAIT_TARGET, + WAIT_LUN, +}; + static int -qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t) +qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha, unsigned int t, + unsigned int l, enum nexus_wait_type type) { - int cnt; - int status; - srb_t *sp; - struct scsi_cmnd *cmd; + int cnt, match, status; + srb_t *sp; unsigned long flags; scsi_qla_host_t *pha = to_qla_parent(ha); - status = 0; - - /* - * Waiting for all commands for the designated target in the active - * array - */ - for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { - spin_lock_irqsave(&pha->hardware_lock, flags); + status = QLA_SUCCESS; + spin_lock_irqsave(&pha->hardware_lock, flags); + for (cnt = 1; status == QLA_SUCCESS && cnt < MAX_OUTSTANDING_COMMANDS; + cnt++) { sp = pha->outstanding_cmds[cnt]; - if (sp) { - cmd = sp->cmd; - spin_unlock_irqrestore(&pha->hardware_lock, flags); - if (cmd->device->id == t && - ha->vp_idx == sp->ha->vp_idx) { - if (!qla2x00_eh_wait_on_command(ha, cmd)) { - status = 1; - break; - } - } - } else { - spin_unlock_irqrestore(&pha->hardware_lock, flags); + if (!sp) + continue; + if (ha->vp_idx != sp->ha->vp_idx) + continue; + match = 0; + switch (type) { + case WAIT_HOST: + match = 1; + break; + case WAIT_TARGET: + match = sp->cmd->device->id == t; + break; + case WAIT_LUN: + match = (sp->cmd->device->id == t && + sp->cmd->device->lun == l); + break; } + if (!match) + continue; + + spin_unlock_irqrestore(&pha->hardware_lock, flags); + status = qla2x00_eh_wait_on_command(ha, sp->cmd); + spin_lock_irqsave(&pha->hardware_lock, flags); } - return (status); + spin_unlock_irqrestore(&pha->hardware_lock, flags); + + return status; } +static char *reset_errors[] = { + "HBA not online", + "HBA not ready", + "Task management failed", + "Waiting for command completions", +}; -/************************************************************************** -* qla2xxx_eh_device_reset -* -* Description: -* The device reset function will reset the target and abort any -* executing commands. -* -* NOTE: The use of SP is undefined within this context. Do *NOT* -* attempt to use this value, even if you determine it is -* non-null. -* -* Input: -* cmd = Linux SCSI command packet of the command that cause the -* bus device reset. -* -* Returns: -* SUCCESS/FAILURE (defined as macro in scsi.h). -* -**************************************************************************/ static int -qla2xxx_eh_device_reset(struct scsi_cmnd *cmd) +__qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type, + struct scsi_cmnd *cmd, int (*do_reset)(struct fc_port *, unsigned int)) { scsi_qla_host_t *ha = shost_priv(cmd->device->host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; - int ret = FAILED; - unsigned int id, lun; - unsigned long serial; + int err; qla2x00_block_error_handler(cmd); - id = cmd->device->id; - lun = cmd->device->lun; - serial = cmd->serial_number; - if (!fcport) - return ret; + return FAILED; - qla_printk(KERN_INFO, ha, - "scsi(%ld:%d:%d): DEVICE RESET ISSUED.\n", ha->host_no, id, lun); + qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): %s RESET ISSUED.\n", + ha->host_no, cmd->device->id, cmd->device->lun, name); + err = 0; if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS) - goto eh_dev_reset_done; - - if (qla2x00_wait_for_loop_ready(ha) == QLA_SUCCESS) { - if (qla2x00_device_reset(ha, fcport) == 0) - ret = SUCCESS; - -#if defined(LOGOUT_AFTER_DEVICE_RESET) - if (ret == SUCCESS) { - if (fcport->flags & FC_FABRIC_DEVICE) { - ha->isp_ops->fabric_logout(ha, fcport->loop_id); - qla2x00_mark_device_lost(ha, fcport, 0, 0); - } - } -#endif - } else { - DEBUG2(printk(KERN_INFO - "%s failed: loop not ready\n",__func__)); - } - - if (ret == FAILED) { - DEBUG3(printk("%s(%ld): device reset failed\n", - __func__, ha->host_no)); - qla_printk(KERN_INFO, ha, "%s: device reset failed\n", - __func__); + goto eh_reset_failed; + err = 1; + if (qla2x00_wait_for_loop_ready(ha) != QLA_SUCCESS) + goto eh_reset_failed; + err = 2; + if (do_reset(fcport, cmd->device->lun) != QLA_SUCCESS) + goto eh_reset_failed; + err = 3; + if (qla2x00_eh_wait_for_pending_commands(ha, cmd->device->id, + cmd->device->lun, type) != QLA_SUCCESS) + goto eh_reset_failed; + + qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): %s RESET SUCCEEDED.\n", + ha->host_no, cmd->device->id, cmd->device->lun, name); + + return SUCCESS; + + eh_reset_failed: + qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): %s RESET FAILED: %s.\n", + ha->host_no, cmd->device->id, cmd->device->lun, name, + reset_errors[err]); + return FAILED; +} - goto eh_dev_reset_done; - } +static int +qla2xxx_eh_device_reset(struct scsi_cmnd *cmd) +{ + scsi_qla_host_t *ha = shost_priv(cmd->device->host); - /* Flush outstanding commands. */ - if (qla2x00_eh_wait_for_pending_target_commands(ha, id)) - ret = FAILED; - if (ret == FAILED) { - DEBUG3(printk("%s(%ld): failed while waiting for commands\n", - __func__, ha->host_no)); - qla_printk(KERN_INFO, ha, - "%s: failed while waiting for commands\n", __func__); - } else - qla_printk(KERN_INFO, ha, - "scsi(%ld:%d:%d): DEVICE RESET SUCCEEDED.\n", ha->host_no, - id, lun); - eh_dev_reset_done: - return ret; + return __qla2xxx_eh_generic_reset("DEVICE", WAIT_LUN, cmd, + ha->isp_ops->lun_reset); } -/************************************************************************** -* qla2x00_eh_wait_for_pending_commands -* -* Description: -* Waits for all the commands to come back from the specified host. -* -* Input: -* ha - pointer to scsi_qla_host structure. -* -* Returns: -* 1 : SUCCESS -* 0 : FAILED -* -* Note: -**************************************************************************/ static int -qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha) +qla2xxx_eh_target_reset(struct scsi_cmnd *cmd) { - int cnt; - int status; - srb_t *sp; - struct scsi_cmnd *cmd; - unsigned long flags; - - status = 1; + scsi_qla_host_t *ha = shost_priv(cmd->device->host); - /* - * Waiting for all commands for the designated target in the active - * array - */ - for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { - spin_lock_irqsave(&ha->hardware_lock, flags); - sp = ha->outstanding_cmds[cnt]; - if (sp) { - cmd = sp->cmd; - spin_unlock_irqrestore(&ha->hardware_lock, flags); - status = qla2x00_eh_wait_on_command(ha, cmd); - if (status == 0) - break; - } - else { - spin_unlock_irqrestore(&ha->hardware_lock, flags); - } - } - return (status); + return __qla2xxx_eh_generic_reset("TARGET", WAIT_TARGET, cmd, + ha->isp_ops->target_reset); } - /************************************************************************** * qla2xxx_eh_bus_reset * @@ -953,7 +883,8 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd) goto eh_bus_reset_done; /* Flush outstanding commands. */ - if (!qla2x00_eh_wait_for_pending_commands(pha)) + if (qla2x00_eh_wait_for_pending_commands(pha, 0, 0, WAIT_HOST) != + QLA_SUCCESS) ret = FAILED; eh_bus_reset_done: @@ -1024,7 +955,8 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) clear_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags); /* Waiting for our command in done_queue to be returned to OS.*/ - if (qla2x00_eh_wait_for_pending_commands(pha)) + if (qla2x00_eh_wait_for_pending_commands(pha, 0, 0, WAIT_HOST) == + QLA_SUCCESS) ret = SUCCESS; if (ha->parent) @@ -1080,7 +1012,7 @@ qla2x00_loop_reset(scsi_qla_host_t *ha) if (fcport->port_type != FCT_TARGET) continue; - ret = qla2x00_device_reset(ha, fcport); + ret = ha->isp_ops->target_reset(fcport, 0); if (ret != QLA_SUCCESS) { DEBUG2_3(printk("%s(%ld): bus_reset failed: " "target_reset=%d d_id=%x.\n", __func__, @@ -1095,26 +1027,6 @@ qla2x00_loop_reset(scsi_qla_host_t *ha) return QLA_SUCCESS; } -/* - * qla2x00_device_reset - * Issue bus device reset message to the target. - * - * Input: - * ha = adapter block pointer. - * t = SCSI ID. - * TARGET_QUEUE_LOCK must be released. - * ADAPTER_STATE_LOCK must be released. - * - * Context: - * Kernel context. - */ -static int -qla2x00_device_reset(scsi_qla_host_t *ha, fc_port_t *reset_fcport) -{ - /* Abort Target command will clear Reservation */ - return ha->isp_ops->abort_target(reset_fcport); -} - void qla2x00_abort_all_cmds(scsi_qla_host_t *ha, int res) { @@ -1292,7 +1204,8 @@ static struct isp_operations qla2100_isp_ops = { .enable_intrs = qla2x00_enable_intrs, .disable_intrs = qla2x00_disable_intrs, .abort_command = qla2x00_abort_command, - .abort_target = qla2x00_abort_target, + .target_reset = qla2x00_abort_target, + .lun_reset = qla2x00_lun_reset, .fabric_login = qla2x00_login_fabric, .fabric_logout = qla2x00_fabric_logout, .calc_req_entries = qla2x00_calc_iocbs_32, @@ -1325,7 +1238,8 @@ static struct isp_operations qla2300_isp_ops = { .enable_intrs = qla2x00_enable_intrs, .disable_intrs = qla2x00_disable_intrs, .abort_command = qla2x00_abort_command, - .abort_target = qla2x00_abort_target, + .target_reset = qla2x00_abort_target, + .lun_reset = qla2x00_lun_reset, .fabric_login = qla2x00_login_fabric, .fabric_logout = qla2x00_fabric_logout, .calc_req_entries = qla2x00_calc_iocbs_32, @@ -1358,7 +1272,8 @@ static struct isp_operations qla24xx_isp_ops = { .enable_intrs = qla24xx_enable_intrs, .disable_intrs = qla24xx_disable_intrs, .abort_command = qla24xx_abort_command, - .abort_target = qla24xx_abort_target, + .target_reset = qla24xx_abort_target, + .lun_reset = qla24xx_lun_reset, .fabric_login = qla24xx_login_fabric, .fabric_logout = qla24xx_fabric_logout, .calc_req_entries = NULL, @@ -1391,7 +1306,8 @@ static struct isp_operations qla25xx_isp_ops = { .enable_intrs = qla24xx_enable_intrs, .disable_intrs = qla24xx_disable_intrs, .abort_command = qla24xx_abort_command, - .abort_target = qla24xx_abort_target, + .target_reset = qla24xx_abort_target, + .lun_reset = qla24xx_lun_reset, .fabric_login = qla24xx_login_fabric, .fabric_logout = qla24xx_fabric_logout, .calc_req_entries = NULL, @@ -1464,6 +1380,13 @@ qla2x00_set_isp_flags(scsi_qla_host_t *ha) ha->device_type |= DT_IIDMA; ha->fw_srisc_address = RISC_START_ADDRESS_2400; break; + case PCI_DEVICE_ID_QLOGIC_ISP8432: + ha->device_type |= DT_ISP8432; + ha->device_type |= DT_ZIO_SUPPORTED; + ha->device_type |= DT_FWI2; + ha->device_type |= DT_IIDMA; + ha->fw_srisc_address = RISC_START_ADDRESS_2400; + break; case PCI_DEVICE_ID_QLOGIC_ISP5422: ha->device_type |= DT_ISP5422; ha->device_type |= DT_FWI2; @@ -1587,6 +1510,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) sht = &qla2x00_driver_template; if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 || pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432 || + pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8432 || pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5422 || pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5432 || pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532) { @@ -1677,7 +1601,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) if (IS_QLA2322(ha) || IS_QLA6322(ha)) ha->optrom_size = OPTROM_SIZE_2322; ha->isp_ops = &qla2300_isp_ops; - } else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { + } else if (IS_QLA24XX_TYPE(ha)) { host->max_id = MAX_TARGETS_2200; ha->mbx_count = MAILBOX_REGISTER_COUNT; ha->request_q_length = REQUEST_ENTRY_CNT_24XX; @@ -1699,6 +1623,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->gid_list_info_size = 8; ha->optrom_size = OPTROM_SIZE_25XX; ha->isp_ops = &qla25xx_isp_ops; + ha->hw_event_start = PCI_FUNC(pdev->devfn) ? + FA_HW_EVENT1_ADDR: FA_HW_EVENT0_ADDR; } host->can_queue = ha->request_q_length + 128; @@ -1713,6 +1639,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) INIT_LIST_HEAD(&ha->list); INIT_LIST_HEAD(&ha->fcports); INIT_LIST_HEAD(&ha->vp_list); + INIT_LIST_HEAD(&ha->work_list); set_bit(0, (unsigned long *) ha->vp_idx_map); @@ -1819,6 +1746,8 @@ qla2x00_remove_one(struct pci_dev *pdev) qla2x00_dfs_remove(ha); + qla84xx_put_chip(ha); + qla2x00_free_sysfs_attr(ha); fc_remove_host(ha->host); @@ -2206,6 +2135,97 @@ qla2x00_mem_free(scsi_qla_host_t *ha) kfree(ha->nvram); } +struct qla_work_evt * +qla2x00_alloc_work(struct scsi_qla_host *ha, enum qla_work_type type, + int locked) +{ + struct qla_work_evt *e; + + e = kzalloc(sizeof(struct qla_work_evt), locked ? GFP_ATOMIC: + GFP_KERNEL); + if (!e) + return NULL; + + INIT_LIST_HEAD(&e->list); + e->type = type; + e->flags = QLA_EVT_FLAG_FREE; + return e; +} + +int +qla2x00_post_work(struct scsi_qla_host *ha, struct qla_work_evt *e, int locked) +{ + unsigned long flags; + + if (!locked) + spin_lock_irqsave(&ha->hardware_lock, flags); + list_add_tail(&e->list, &ha->work_list); + qla2xxx_wake_dpc(ha); + if (!locked) + spin_unlock_irqrestore(&ha->hardware_lock, flags); + return QLA_SUCCESS; +} + +int +qla2x00_post_aen_work(struct scsi_qla_host *ha, enum fc_host_event_code code, + u32 data) +{ + struct qla_work_evt *e; + + e = qla2x00_alloc_work(ha, QLA_EVT_AEN, 1); + if (!e) + return QLA_FUNCTION_FAILED; + + e->u.aen.code = code; + e->u.aen.data = data; + return qla2x00_post_work(ha, e, 1); +} + +int +qla2x00_post_hwe_work(struct scsi_qla_host *ha, uint16_t code, uint16_t d1, + uint16_t d2, uint16_t d3) +{ + struct qla_work_evt *e; + + e = qla2x00_alloc_work(ha, QLA_EVT_HWE_LOG, 1); + if (!e) + return QLA_FUNCTION_FAILED; + + e->u.hwe.code = code; + e->u.hwe.d1 = d1; + e->u.hwe.d2 = d2; + e->u.hwe.d3 = d3; + return qla2x00_post_work(ha, e, 1); +} + +static void +qla2x00_do_work(struct scsi_qla_host *ha) +{ + struct qla_work_evt *e; + + spin_lock_irq(&ha->hardware_lock); + while (!list_empty(&ha->work_list)) { + e = list_entry(ha->work_list.next, struct qla_work_evt, list); + list_del_init(&e->list); + spin_unlock_irq(&ha->hardware_lock); + + switch (e->type) { + case QLA_EVT_AEN: + fc_host_post_event(ha->host, fc_get_event_number(), + e->u.aen.code, e->u.aen.data); + break; + case QLA_EVT_HWE_LOG: + qla2xxx_hw_event_log(ha, e->u.hwe.code, e->u.hwe.d1, + e->u.hwe.d2, e->u.hwe.d3); + break; + } + if (e->flags & QLA_EVT_FLAG_FREE) + kfree(e); + spin_lock_irq(&ha->hardware_lock); + } + spin_unlock_irq(&ha->hardware_lock); +} + /************************************************************************** * qla2x00_do_dpc * This kernel thread is a task that is schedule by the interrupt handler @@ -2257,6 +2277,8 @@ qla2x00_do_dpc(void *data) continue; } + qla2x00_do_work(ha); + if (test_and_clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) { DEBUG(printk("scsi(%ld): dpc: sched " @@ -2291,12 +2313,6 @@ qla2x00_do_dpc(void *data) if (test_and_clear_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags)) qla2x00_update_fcports(ha); - if (test_and_clear_bit(LOOP_RESET_NEEDED, &ha->dpc_flags)) { - DEBUG(printk("scsi(%ld): dpc: sched loop_reset()\n", - ha->host_no)); - qla2x00_loop_reset(ha); - } - if (test_and_clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) && (!(test_and_set_bit(RESET_ACTIVE, &ha->dpc_flags)))) { @@ -2367,19 +2383,6 @@ qla2x00_do_dpc(void *data) ha->host_no)); } - if ((test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags)) && - atomic_read(&ha->loop_state) != LOOP_DOWN) { - - clear_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags); - DEBUG(printk("scsi(%ld): qla2x00_login_retry()\n", - ha->host_no)); - - set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); - - DEBUG(printk("scsi(%ld): qla2x00_login_retry - end\n", - ha->host_no)); - } - if (test_and_clear_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) { DEBUG(printk("scsi(%ld): qla2x00_loop_resync()\n", @@ -2397,18 +2400,6 @@ qla2x00_do_dpc(void *data) ha->host_no)); } - if (test_and_clear_bit(FCPORT_RESCAN_NEEDED, &ha->dpc_flags)) { - - DEBUG(printk("scsi(%ld): Rescan flagged fcports...\n", - ha->host_no)); - - qla2x00_rescan_fcports(ha); - - DEBUG(printk("scsi(%ld): Rescan flagged fcports..." - "end.\n", - ha->host_no)); - } - if (!ha->interrupts_on) ha->isp_ops->enable_intrs(ha); @@ -2586,7 +2577,8 @@ qla2x00_timer(scsi_qla_host_t *ha) set_bit(RESTART_QUEUES_NEEDED, &ha->dpc_flags); start_dpc++; - if (!(ha->device_flags & DFLG_NO_CABLE)) { + if (!(ha->device_flags & DFLG_NO_CABLE) && + !ha->parent) { DEBUG(printk("scsi(%ld): Loop down - " "aborting ISP.\n", ha->host_no)); @@ -2610,10 +2602,8 @@ qla2x00_timer(scsi_qla_host_t *ha) /* Schedule the DPC routine if needed */ if ((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) || test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) || - test_bit(LOOP_RESET_NEEDED, &ha->dpc_flags) || test_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags) || start_dpc || - test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags) || test_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) || test_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags) || test_bit(VP_DPC_NEEDED, &ha->dpc_flags) || @@ -2665,7 +2655,7 @@ qla2x00_request_firmware(scsi_qla_host_t *ha) blob = &qla_fw_blobs[FW_ISP2300]; } else if (IS_QLA2322(ha) || IS_QLA6322(ha)) { blob = &qla_fw_blobs[FW_ISP2322]; - } else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { + } else if (IS_QLA24XX_TYPE(ha)) { blob = &qla_fw_blobs[FW_ISP24XX]; } else if (IS_QLA25XX(ha)) { blob = &qla_fw_blobs[FW_ISP25XX]; @@ -2815,6 +2805,7 @@ static struct pci_device_id qla2xxx_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP6322) }, { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2422) }, { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2432) }, + { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8432) }, { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5422) }, { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5432) }, { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2532) }, diff --git a/drivers/scsi/qla2xxx/qla_settings.h b/drivers/scsi/qla2xxx/qla_settings.h index 249e4d90fdc5..2801c2664b40 100644 --- a/drivers/scsi/qla2xxx/qla_settings.h +++ b/drivers/scsi/qla2xxx/qla_settings.h @@ -1,26 +1,12 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ -/* - * Compile time Options: - * 0 - Disable and 1 - Enable - */ -#define DEBUG_QLA2100 0 /* For Debug of qla2x00 */ - -#define USE_ABORT_TGT 1 /* Use Abort Target mbx cmd */ - #define MAX_RETRIES_OF_ISP_ABORT 5 /* Max time to wait for the loop to be in LOOP_READY state */ #define MAX_LOOP_TIMEOUT (60 * 5) -/* - * Some vendor subsystems do not recover properly after a device reset. Define - * the following to force a logout after a successful device reset. - */ -#undef LOGOUT_AFTER_DEVICE_RESET - #include "qla_version.h" diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 26822c8807ee..1728ab3ccb20 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -543,79 +543,174 @@ qla24xx_get_flash_manufacturer(scsi_qla_host_t *ha, uint8_t *man_id, } } -static int -qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, - uint32_t dwords) +void +qla2xxx_get_flash_info(scsi_qla_host_t *ha) { - int ret; - uint32_t liter, miter; - uint32_t sec_mask, rest_addr, conf_addr; - uint32_t fdata, findex, cnt; +#define FLASH_BLK_SIZE_32K 0x8000 +#define FLASH_BLK_SIZE_64K 0x10000 + uint16_t cnt, chksum; + uint16_t *wptr; + struct qla_fdt_layout *fdt; uint8_t man_id, flash_id; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - dma_addr_t optrom_dma; - void *optrom = NULL; - uint32_t *s, *d; - ret = QLA_SUCCESS; + if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha)) + return; - /* Prepare burst-capable write on supported ISPs. */ - if (IS_QLA25XX(ha) && !(faddr & 0xfff) && - dwords > OPTROM_BURST_DWORDS) { - optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, - &optrom_dma, GFP_KERNEL); - if (!optrom) { - qla_printk(KERN_DEBUG, ha, - "Unable to allocate memory for optrom burst write " - "(%x KB).\n", OPTROM_BURST_SIZE / 1024); - } + wptr = (uint16_t *)ha->request_ring; + fdt = (struct qla_fdt_layout *)ha->request_ring; + ha->isp_ops->read_optrom(ha, (uint8_t *)ha->request_ring, + FA_FLASH_DESCR_ADDR << 2, OPTROM_BURST_SIZE); + if (*wptr == __constant_cpu_to_le16(0xffff)) + goto no_flash_data; + if (fdt->sig[0] != 'Q' || fdt->sig[1] != 'L' || fdt->sig[2] != 'I' || + fdt->sig[3] != 'D') + goto no_flash_data; + + for (cnt = 0, chksum = 0; cnt < sizeof(struct qla_fdt_layout) >> 1; + cnt++) + chksum += le16_to_cpu(*wptr++); + if (chksum) { + DEBUG2(qla_printk(KERN_INFO, ha, "Inconsistent FDT detected: " + "checksum=0x%x id=%c version=0x%x.\n", chksum, fdt->sig[0], + le16_to_cpu(fdt->version))); + DEBUG9(qla2x00_dump_buffer((uint8_t *)fdt, sizeof(*fdt))); + goto no_flash_data; } - qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id); - DEBUG9(printk("%s(%ld): Flash man_id=%d flash_id=%d\n", __func__, - ha->host_no, man_id, flash_id)); + ha->fdt_odd_index = le16_to_cpu(fdt->man_id) == 0x1f; + ha->fdt_wrt_disable = fdt->wrt_disable_bits; + ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0300 | fdt->erase_cmd); + ha->fdt_block_size = le32_to_cpu(fdt->block_size); + if (fdt->unprotect_sec_cmd) { + ha->fdt_unprotect_sec_cmd = flash_conf_to_access_addr(0x0300 | + fdt->unprotect_sec_cmd); + ha->fdt_protect_sec_cmd = fdt->protect_sec_cmd ? + flash_conf_to_access_addr(0x0300 | fdt->protect_sec_cmd): + flash_conf_to_access_addr(0x0336); + } - conf_addr = flash_conf_to_access_addr(0x03d8); + DEBUG2(qla_printk(KERN_DEBUG, ha, "Flash[FDT]: (0x%x/0x%x) erase=0x%x " + "pro=%x upro=%x idx=%d wrtd=0x%x blk=0x%x.\n", + le16_to_cpu(fdt->man_id), le16_to_cpu(fdt->id), ha->fdt_erase_cmd, + ha->fdt_protect_sec_cmd, ha->fdt_unprotect_sec_cmd, + ha->fdt_odd_index, ha->fdt_wrt_disable, ha->fdt_block_size)); + return; + +no_flash_data: + qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id); + ha->fdt_wrt_disable = 0x9c; + ha->fdt_erase_cmd = flash_conf_to_access_addr(0x03d8); switch (man_id) { case 0xbf: /* STT flash. */ - if (flash_id == 0x8e) { - rest_addr = 0x3fff; - sec_mask = 0x7c000; - } else { - rest_addr = 0x1fff; - sec_mask = 0x7e000; - } + if (flash_id == 0x8e) + ha->fdt_block_size = FLASH_BLK_SIZE_64K; + else + ha->fdt_block_size = FLASH_BLK_SIZE_32K; + if (flash_id == 0x80) - conf_addr = flash_conf_to_access_addr(0x0352); + ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0352); break; case 0x13: /* ST M25P80. */ - rest_addr = 0x3fff; - sec_mask = 0x7c000; + ha->fdt_block_size = FLASH_BLK_SIZE_64K; break; - case 0x1f: // Atmel 26DF081A - rest_addr = 0x3fff; - sec_mask = 0x7c000; - conf_addr = flash_conf_to_access_addr(0x0320); + case 0x1f: /* Atmel 26DF081A. */ + ha->fdt_odd_index = 1; + ha->fdt_block_size = FLASH_BLK_SIZE_64K; + ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0320); + ha->fdt_unprotect_sec_cmd = flash_conf_to_access_addr(0x0339); + ha->fdt_protect_sec_cmd = flash_conf_to_access_addr(0x0336); break; default: /* Default to 64 kb sector size. */ - rest_addr = 0x3fff; - sec_mask = 0x7c000; + ha->fdt_block_size = FLASH_BLK_SIZE_64K; break; } + DEBUG2(qla_printk(KERN_DEBUG, ha, "Flash[MID]: (0x%x/0x%x) erase=0x%x " + "pro=%x upro=%x idx=%d wrtd=0x%x blk=0x%x.\n", man_id, flash_id, + ha->fdt_erase_cmd, ha->fdt_protect_sec_cmd, + ha->fdt_unprotect_sec_cmd, ha->fdt_odd_index, ha->fdt_wrt_disable, + ha->fdt_block_size)); +} + +static void +qla24xx_unprotect_flash(scsi_qla_host_t *ha) +{ + struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + /* Enable flash write. */ WRT_REG_DWORD(®->ctrl_status, RD_REG_DWORD(®->ctrl_status) | CSRX_FLASH_ENABLE); RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ + if (!ha->fdt_wrt_disable) + return; + /* Disable flash write-protection. */ qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0); /* Some flash parts need an additional zero-write to clear bits.*/ qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0); +} + +static void +qla24xx_protect_flash(scsi_qla_host_t *ha) +{ + uint32_t cnt; + struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + + if (!ha->fdt_wrt_disable) + goto skip_wrt_protect; + + /* Enable flash write-protection and wait for completion. */ + qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), + ha->fdt_wrt_disable); + for (cnt = 300; cnt && + qla24xx_read_flash_dword(ha, + flash_conf_to_access_addr(0x005)) & BIT_0; + cnt--) { + udelay(10); + } + +skip_wrt_protect: + /* Disable flash write. */ + WRT_REG_DWORD(®->ctrl_status, + RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE); + RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ +} + +static int +qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, + uint32_t dwords) +{ + int ret; + uint32_t liter, miter; + uint32_t sec_mask, rest_addr; + uint32_t fdata, findex; + dma_addr_t optrom_dma; + void *optrom = NULL; + uint32_t *s, *d; + + ret = QLA_SUCCESS; + + /* Prepare burst-capable write on supported ISPs. */ + if (IS_QLA25XX(ha) && !(faddr & 0xfff) && + dwords > OPTROM_BURST_DWORDS) { + optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, + &optrom_dma, GFP_KERNEL); + if (!optrom) { + qla_printk(KERN_DEBUG, ha, + "Unable to allocate memory for optrom burst write " + "(%x KB).\n", OPTROM_BURST_SIZE / 1024); + } + } + + rest_addr = (ha->fdt_block_size >> 2) - 1; + sec_mask = 0x80000 - (ha->fdt_block_size >> 2); + + qla24xx_unprotect_flash(ha); for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) { - if (man_id == 0x1f) { + if (ha->fdt_odd_index) { findex = faddr << 2; fdata = findex & sec_mask; } else { @@ -625,13 +720,13 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, /* Are we at the beginning of a sector? */ if ((findex & rest_addr) == 0) { - /* Do sector unprotect at 4K boundry for Atmel part. */ - if (man_id == 0x1f) + /* Do sector unprotect. */ + if (ha->fdt_unprotect_sec_cmd) qla24xx_write_flash_dword(ha, - flash_conf_to_access_addr(0x0339), + ha->fdt_unprotect_sec_cmd, (fdata & 0xff00) | ((fdata << 16) & 0xff0000) | ((fdata >> 16) & 0xff)); - ret = qla24xx_write_flash_dword(ha, conf_addr, + ret = qla24xx_write_flash_dword(ha, ha->fdt_erase_cmd, (fdata & 0xff00) |((fdata << 16) & 0xff0000) | ((fdata >> 16) & 0xff)); if (ret != QLA_SUCCESS) { @@ -681,28 +776,16 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, break; } - /* Do sector protect at 4K boundry for Atmel part. */ - if (man_id == 0x1f && + /* Do sector protect. */ + if (ha->fdt_unprotect_sec_cmd && ((faddr & rest_addr) == rest_addr)) qla24xx_write_flash_dword(ha, - flash_conf_to_access_addr(0x0336), + ha->fdt_protect_sec_cmd, (fdata & 0xff00) | ((fdata << 16) & 0xff0000) | ((fdata >> 16) & 0xff)); } - /* Enable flash write-protection and wait for completion. */ - qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0x9c); - for (cnt = 300; cnt && - qla24xx_read_flash_dword(ha, - flash_conf_to_access_addr(0x005)) & BIT_0; - cnt--) { - udelay(10); - } - - /* Disable flash write. */ - WRT_REG_DWORD(®->ctrl_status, - RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE); - RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ + qla24xx_protect_flash(ha); if (optrom) dma_free_coherent(&ha->pdev->dev, @@ -2221,3 +2304,107 @@ qla24xx_get_flash_version(scsi_qla_host_t *ha, void *mbuf) return ret; } + +static int +qla2xxx_hw_event_store(scsi_qla_host_t *ha, uint32_t *fdata) +{ + uint32_t d[2], faddr; + + /* Locate first empty entry. */ + for (;;) { + if (ha->hw_event_ptr >= + ha->hw_event_start + FA_HW_EVENT_SIZE) { + DEBUG2(qla_printk(KERN_WARNING, ha, + "HW event -- Log Full!\n")); + return QLA_MEMORY_ALLOC_FAILED; + } + + qla24xx_read_flash_data(ha, d, ha->hw_event_ptr, 2); + faddr = flash_data_to_access_addr(ha->hw_event_ptr); + ha->hw_event_ptr += FA_HW_EVENT_ENTRY_SIZE; + if (d[0] == __constant_cpu_to_le32(0xffffffff) && + d[1] == __constant_cpu_to_le32(0xffffffff)) { + qla24xx_unprotect_flash(ha); + + qla24xx_write_flash_dword(ha, faddr++, + cpu_to_le32(jiffies)); + qla24xx_write_flash_dword(ha, faddr++, 0); + qla24xx_write_flash_dword(ha, faddr++, *fdata++); + qla24xx_write_flash_dword(ha, faddr++, *fdata); + + qla24xx_protect_flash(ha); + break; + } + } + return QLA_SUCCESS; +} + +int +qla2xxx_hw_event_log(scsi_qla_host_t *ha, uint16_t code, uint16_t d1, + uint16_t d2, uint16_t d3) +{ +#define QMARK(a, b, c, d) \ + cpu_to_le32(LSB(a) << 24 | LSB(b) << 16 | LSB(c) << 8 | LSB(d)) + + int rval; + uint32_t marker[2], fdata[4]; + + if (ha->hw_event_start == 0) + return QLA_FUNCTION_FAILED; + + DEBUG2(qla_printk(KERN_WARNING, ha, + "HW event -- code=%x, d1=%x, d2=%x, d3=%x.\n", code, d1, d2, d3)); + + /* If marker not already found, locate or write. */ + if (!ha->flags.hw_event_marker_found) { + /* Create marker. */ + marker[0] = QMARK('L', ha->fw_major_version, + ha->fw_minor_version, ha->fw_subminor_version); + marker[1] = QMARK(QLA_DRIVER_MAJOR_VER, QLA_DRIVER_MINOR_VER, + QLA_DRIVER_PATCH_VER, QLA_DRIVER_BETA_VER); + + /* Locate marker. */ + ha->hw_event_ptr = ha->hw_event_start; + for (;;) { + qla24xx_read_flash_data(ha, fdata, ha->hw_event_ptr, + 4); + if (fdata[0] == __constant_cpu_to_le32(0xffffffff) && + fdata[1] == __constant_cpu_to_le32(0xffffffff)) + break; + ha->hw_event_ptr += FA_HW_EVENT_ENTRY_SIZE; + if (ha->hw_event_ptr >= + ha->hw_event_start + FA_HW_EVENT_SIZE) { + DEBUG2(qla_printk(KERN_WARNING, ha, + "HW event -- Log Full!\n")); + return QLA_MEMORY_ALLOC_FAILED; + } + if (fdata[2] == marker[0] && fdata[3] == marker[1]) { + ha->flags.hw_event_marker_found = 1; + break; + } + } + /* No marker, write it. */ + if (!ha->flags.hw_event_marker_found) { + rval = qla2xxx_hw_event_store(ha, marker); + if (rval != QLA_SUCCESS) { + DEBUG2(qla_printk(KERN_WARNING, ha, + "HW event -- Failed marker write=%x.!\n", + rval)); + return rval; + } + ha->flags.hw_event_marker_found = 1; + } + } + + /* Store error. */ + fdata[0] = cpu_to_le32(code << 16 | d1); + fdata[1] = cpu_to_le32(d2 << 16 | d3); + rval = qla2xxx_hw_event_store(ha, fdata); + if (rval != QLA_SUCCESS) { + DEBUG2(qla_printk(KERN_WARNING, ha, + "HW event -- Failed error write=%x.!\n", + rval)); + } + + return rval; +} diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index ea08a129fee9..f42f17acf2cf 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -1,15 +1,15 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ /* * Driver version */ -#define QLA2XXX_VERSION "8.02.00-k9" +#define QLA2XXX_VERSION "8.02.01-k1" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 2 -#define QLA_DRIVER_PATCH_VER 0 +#define QLA_DRIVER_PATCH_VER 1 #define QLA_DRIVER_BETA_VER 0 |