From: Hannes Reinecke Subject: qla4xxx driver fixes for SLES11 Date: Tue Oct 7 12:59:55 2008 +0200: References: bnc#432976 The upstream qla4xxx driver requires some fixes for SLES11. Signed-off-by: David Wagner Signed-off-by: Hannes Reinecke diff --git a/drivers/scsi/qla4xxx/Kconfig b/drivers/scsi/qla4xxx/Kconfig index 69cbff3..4eda26a 100644 --- a/drivers/scsi/qla4xxx/Kconfig +++ b/drivers/scsi/qla4xxx/Kconfig @@ -1,7 +1,7 @@ config SCSI_QLA_ISCSI tristate "QLogic ISP4XXX host adapter family support" - depends on PCI && SCSI && NET + depends on PCI && SCSI select SCSI_ISCSI_ATTRS ---help--- - This driver supports the QLogic 40xx (ISP4XXX) iSCSI host + This driver supports the QLogic 40xx (ISP4XXX) iSCSI host adapter family. diff --git a/drivers/scsi/qla4xxx/ql4_dbg.c b/drivers/scsi/qla4xxx/ql4_dbg.c index fcc184c..171a342 100644 --- a/drivers/scsi/qla4xxx/ql4_dbg.c +++ b/drivers/scsi/qla4xxx/ql4_dbg.c @@ -6,10 +6,162 @@ */ #include "ql4_def.h" +#include "ql4_version.h" #include "ql4_glbl.h" #include "ql4_dbg.h" #include "ql4_inline.h" +#include + +static void qla4xxx_print_srb_info(struct srb * srb) +{ + printk("%s: srb = 0x%p, flags=0x%02x\n", __func__, srb, srb->flags); + printk("%s: cmd = 0x%p, saved_dma_handle = 0x%lx\n", + __func__, srb->cmd, (unsigned long) srb->dma_handle); + printk("%s: fw_ddb_index = %d, lun = %d\n", + __func__, srb->fw_ddb_index, srb->cmd->device->lun); + printk("%s: iocb_tov = %d\n", + __func__, srb->iocb_tov); + printk("%s: cc_stat = 0x%x\n", __func__, srb->cc_stat); +} + +void qla4xxx_print_scsi_cmd(struct scsi_cmnd *cmd) +{ + printk("SCSI Command = 0x%p, Handle=0x%p\n", cmd, cmd->host_scribble); + printk(" b=%d, t=%02xh, l=%02xh, cmd_len = %02xh\n", + cmd->device->channel, cmd->device->id, cmd->device->lun, + cmd->cmd_len); + scsi_print_command(cmd); + qla4xxx_print_srb_info((struct srb *) cmd->SCp.ptr); +} + +void __dump_registers(struct scsi_qla_host *ha) +{ + uint8_t i; + for (i = 0; i < MBOX_REG_COUNT; i++) { + printk(KERN_INFO "0x%02X mailbox[%d] = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, mailbox[i]), i, + readw(&ha->reg->mailbox[i])); + } + printk(KERN_INFO "0x%02X flash_address = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, flash_address), + readw(&ha->reg->flash_address)); + printk(KERN_INFO "0x%02X flash_data = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, flash_data), + readw(&ha->reg->flash_data)); + printk(KERN_INFO "0x%02X ctrl_status = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, ctrl_status), + readw(&ha->reg->ctrl_status)); + if (is_qla4010(ha)) { + printk(KERN_INFO "0x%02X nvram = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, u1.isp4010.nvram), + readw(&ha->reg->u1.isp4010.nvram)); + } + + else if (is_qla4022(ha) | is_qla4032(ha)) { + printk(KERN_INFO "0x%02X intr_mask = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, + u1.isp4022.intr_mask), + readw(&ha->reg->u1.isp4022.intr_mask)); + printk(KERN_INFO "0x%02X nvram = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, u1.isp4022.nvram), + readw(&ha->reg->u1.isp4022.nvram)); + printk(KERN_INFO "0x%02X semaphore = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, + u1.isp4022.semaphore), + readw(&ha->reg->u1.isp4022.semaphore)); + } + printk(KERN_INFO "0x%02X req_q_in = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, req_q_in), + readw(&ha->reg->req_q_in)); + printk(KERN_INFO "0x%02X rsp_q_out = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, rsp_q_out), + readw(&ha->reg->rsp_q_out)); + if (is_qla4010(ha)) { + printk(KERN_INFO "0x%02X ext_hw_conf = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, + u2.isp4010.ext_hw_conf), + readw(&ha->reg->u2.isp4010.ext_hw_conf)); + printk(KERN_INFO "0x%02X port_ctrl = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, + u2.isp4010.port_ctrl), + readw(&ha->reg->u2.isp4010.port_ctrl)); + printk(KERN_INFO "0x%02X port_status = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, + u2.isp4010.port_status), + readw(&ha->reg->u2.isp4010.port_status)); + printk(KERN_INFO "0x%02X req_q_out = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, + u2.isp4010.req_q_out), + readw(&ha->reg->u2.isp4010.req_q_out)); + printk(KERN_INFO "0x%02X gp_out = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, u2.isp4010.gp_out), + readw(&ha->reg->u2.isp4010.gp_out)); + printk(KERN_INFO "0x%02X gp_in = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, u2.isp4010.gp_in), + readw(&ha->reg->u2.isp4010.gp_in)); + printk(KERN_INFO "0x%02X port_err_status = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, + u2.isp4010.port_err_status), + readw(&ha->reg->u2.isp4010.port_err_status)); + } + + else if (is_qla4022(ha) | is_qla4032(ha)) { + printk(KERN_INFO "Page 0 Registers:\n"); + printk(KERN_INFO "0x%02X ext_hw_conf = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, + u2.isp4022.p0.ext_hw_conf), + readw(&ha->reg->u2.isp4022.p0.ext_hw_conf)); + printk(KERN_INFO "0x%02X port_ctrl = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, + u2.isp4022.p0.port_ctrl), + readw(&ha->reg->u2.isp4022.p0.port_ctrl)); + printk(KERN_INFO "0x%02X port_status = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, + u2.isp4022.p0.port_status), + readw(&ha->reg->u2.isp4022.p0.port_status)); + printk(KERN_INFO "0x%02X gp_out = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, + u2.isp4022.p0.gp_out), + readw(&ha->reg->u2.isp4022.p0.gp_out)); + printk(KERN_INFO "0x%02X gp_in = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, u2.isp4022.p0.gp_in), + readw(&ha->reg->u2.isp4022.p0.gp_in)); + printk(KERN_INFO "0x%02X port_err_status = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, + u2.isp4022.p0.port_err_status), + readw(&ha->reg->u2.isp4022.p0.port_err_status)); + printk(KERN_INFO "Page 1 Registers:\n"); + writel(HOST_MEM_CFG_PAGE & set_rmask(CSR_SCSI_PAGE_SELECT), + &ha->reg->ctrl_status); + printk(KERN_INFO "0x%02X req_q_out = 0x%08X\n", + (uint8_t) offsetof(struct isp_reg, + u2.isp4022.p1.req_q_out), + readw(&ha->reg->u2.isp4022.p1.req_q_out)); + writel(PORT_CTRL_STAT_PAGE & set_rmask(CSR_SCSI_PAGE_SELECT), + &ha->reg->ctrl_status); + } +} + +void qla4xxx_dump_mbox_registers(struct scsi_qla_host *ha) +{ + unsigned long flags = 0; + int i = 0; + spin_lock_irqsave(&ha->hardware_lock, flags); + for (i = 1; i < MBOX_REG_COUNT; i++) + printk(KERN_INFO " Mailbox[%d] = %08x\n", i, + readw(&ha->reg->mailbox[i])); + spin_unlock_irqrestore(&ha->hardware_lock, flags); +} + +void qla4xxx_dump_registers(struct scsi_qla_host *ha) +{ + unsigned long flags = 0; + spin_lock_irqsave(&ha->hardware_lock, flags); + __dump_registers(ha); + spin_unlock_irqrestore(&ha->hardware_lock, flags); +} + void qla4xxx_dump_buffer(void *b, uint32_t size) { uint32_t cnt; @@ -30,4 +182,3 @@ void qla4xxx_dump_buffer(void *b, uint32_t size) if (cnt % 16) printk(KERN_DEBUG "\n"); } - diff --git a/drivers/scsi/qla4xxx/ql4_dbg.h b/drivers/scsi/qla4xxx/ql4_dbg.h index d861c3b..20dfe4a 100644 --- a/drivers/scsi/qla4xxx/ql4_dbg.h +++ b/drivers/scsi/qla4xxx/ql4_dbg.h @@ -12,6 +12,7 @@ /* #define QL_DEBUG_LEVEL_3 */ /* Output function tracing */ /* #define QL_DEBUG_LEVEL_4 */ /* #define QL_DEBUG_LEVEL_5 */ +/* #define QL_DEBUG_LEVEL_6 */ /* #define QL_DEBUG_LEVEL_9 */ #define QL_DEBUG_LEVEL_2 /* ALways enable error messagess */ @@ -22,14 +23,14 @@ #endif #if defined(QL_DEBUG_LEVEL_2) -#define DEBUG2(x) do {if(ql4xextended_error_logging == 2) x;} while (0); +#define DEBUG2(x) do {if(extended_error_logging == 2) x;} while (0); #define DEBUG2_3(x) do {x;} while (0); #else /* */ #define DEBUG2(x) do {} while (0); #endif /* */ #if defined(QL_DEBUG_LEVEL_3) -#define DEBUG3(x) do {if(ql4xextended_error_logging == 3) x;} while (0); +#define DEBUG3(x) do {if(extended_error_logging == 3) x;} while (0); #else /* */ #define DEBUG3(x) do {} while (0); #if !defined(QL_DEBUG_LEVEL_2) @@ -48,6 +49,12 @@ #define DEBUG5(x) do {} while (0); #endif /* */ +#if defined(QL_DEBUG_LEVEL_6) +#define DEBUG6(x) do {x;} while (0); +#else /* */ +#define DEBUG6(x) do {} while (0); +#endif /* */ + #if defined(QL_DEBUG_LEVEL_9) #define DEBUG9(x) do {x;} while (0); #else /* */ diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index d6be076..52d36b2 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -90,10 +90,10 @@ ***********************************/ #define MAX_HBAS 16 #define MAX_BUSES 1 -#define MAX_TARGETS (MAX_PRST_DEV_DB_ENTRIES + MAX_DEV_DB_ENTRIES) +#define MAX_TARGETS MAX_DEV_DB_ENTRIES #define MAX_LUNS 0xffff #define MAX_AEN_ENTRIES 256 /* should be > EXT_DEF_MAX_AEN_QUEUE */ -#define MAX_DDB_ENTRIES (MAX_PRST_DEV_DB_ENTRIES + MAX_DEV_DB_ENTRIES) +#define MAX_DDB_ENTRIES MAX_DEV_DB_ENTRIES #define MAX_PDU_ENTRIES 32 #define INVALID_ENTRY 0xFFFF #define MAX_CMDS_TO_RISC 1024 @@ -121,8 +121,9 @@ #define MAX_REQS_SERVICED_PER_INTR 16 #define ISCSI_IPADDR_SIZE 4 /* IP address size */ -#define ISCSI_ALIAS_SIZE 32 /* ISCSI Alias name size */ -#define ISCSI_NAME_SIZE 0xE0 /* ISCSI Name size */ +#define ISCSI_ALIAS_SIZE 32 /* ISCSI Alais name size */ +#define ISCSI_NAME_SIZE 0xE0 /* ISCSI Name size - + * usually a string */ #define LSDW(x) ((u32)((u64)(x))) #define MSDW(x) ((u32)((((u64)(x)) >> 16) >> 16)) @@ -158,6 +159,7 @@ struct srb { struct ddb_entry *ddb; uint16_t flags; /* (1) Status flags. */ +#define SRB_SCSI_PASSTHRU BIT_2 /* for scsi passthru cmds */ #define SRB_DMA_VALID BIT_3 /* DMA Buffer mapped. */ #define SRB_GOT_SENSE BIT_4 /* sense data recieved. */ uint8_t state; /* (1) Status flags. */ @@ -182,25 +184,12 @@ struct srb { uint16_t iocb_tov; uint16_t iocb_cnt; /* Number of used iocbs */ uint16_t cc_stat; - u_long r_start; /* Time we recieve a cmd from OS */ - u_long u_start; /* Time when we handed the cmd to F/W */ + uint32_t dma_len; }; -/* - * Asynchronous Event Queue structure - */ -struct aen { - uint32_t mbox_sts[MBOX_AEN_REG_COUNT]; -}; - -struct ql4_aen_log { - int count; - struct aen entry[MAX_AEN_ENTRIES]; -}; - -/* - * Device Database (DDB) structure - */ + /* + * Device Database (DDB) structure + */ struct ddb_entry { struct list_head list; /* ddb list */ struct scsi_qla_host *ha; @@ -262,9 +251,19 @@ struct ddb_entry { #define DF_RELOGIN 0 /* Relogin to device */ #define DF_NO_RELOGIN 1 /* Do not relogin if IOCTL * logged it out */ -#define DF_ISNS_DISCOVERED 2 /* Device was discovered via iSNS */ -#define DF_FO_MASKED 3 +#define DF_SCAN_ISSUED 2 + +/* + * Asynchronous Event Queue structure + */ +struct aen { + uint32_t mbox_sts[MBOX_AEN_REG_COUNT]; +}; +struct ql4_aen_log { + int count; + struct aen entry[MAX_AEN_ENTRIES]; +}; #include "ql4_fw.h" #include "ql4_nvram.h" @@ -273,16 +272,29 @@ struct ddb_entry { * Linux Host Adapter structure */ struct scsi_qla_host { + struct klist_node node; + uint16_t instance; + uint16_t rsvd0; + + /* exported functions */ + int (*ql4cmd)(struct scsi_qla_host *ha, struct srb * srb); + int (*ql4mbx)(struct scsi_qla_host *ha, uint8_t inCount, + uint8_t outCount, uint32_t *mbx_cmd, uint32_t *mbx_sts); + /* Linux adapter configuration data */ + struct Scsi_Host *host; /* pointer to host data */ + uint32_t tot_ddbs; unsigned long flags; +#define AF_ISNS_CMD_DONE 13 /* 0x00002000 */ #define AF_ONLINE 0 /* 0x00000001 */ #define AF_INIT_DONE 1 /* 0x00000002 */ #define AF_MBOX_COMMAND 2 /* 0x00000004 */ #define AF_MBOX_COMMAND_DONE 3 /* 0x00000008 */ -#define AF_INTERRUPTS_ON 6 /* 0x00000040 */ +#define AF_INTERRUPTS_ON 6 /* 0x00000040 Not Used */ #define AF_GET_CRASH_RECORD 7 /* 0x00000080 */ #define AF_LINK_UP 8 /* 0x00000100 */ +#define AF_TOPCAT_CHIP_PRESENT 9 /* 0x00000200 */ #define AF_IRQ_ATTACHED 10 /* 0x00000400 */ #define AF_DISABLE_ACB_COMPLETE 11 /* 0x00000800 */ @@ -297,9 +309,6 @@ struct scsi_qla_host { #define DPC_AEN 9 /* 0x00000200 */ #define DPC_GET_DHCP_IP_ADDR 15 /* 0x00008000 */ - struct Scsi_Host *host; /* pointer to host data */ - uint32_t tot_ddbs; - uint16_t iocb_cnt; uint16_t iocb_hiwat; @@ -324,6 +333,7 @@ struct scsi_qla_host { /* NVRAM registers */ struct eeprom_data *nvram; spinlock_t hardware_lock ____cacheline_aligned; + spinlock_t list_lock; uint32_t eeprom_cmd_data; /* Counters for general statistics */ @@ -348,7 +358,6 @@ struct scsi_qla_host { uint32_t firmware_version[2]; uint32_t patch_number; uint32_t build_number; - uint32_t board_id; /* --- From Init_FW --- */ /* init_cb_t *init_cb; */ @@ -368,6 +377,7 @@ struct scsi_qla_host { /* --- From GetFwState --- */ uint32_t firmware_state; + uint32_t board_id; uint32_t addl_fw_state; /* Linux kernel thread */ @@ -390,6 +400,10 @@ struct scsi_qla_host { uint16_t free_srb_q_count; uint16_t num_srbs_allocated; + /* Active array */ + struct srb *active_srb_array[MAX_SRBS]; + uint16_t current_active_index; + /* DMA Memory Block */ void *queues; dma_addr_t queues_dma; @@ -418,12 +432,20 @@ struct scsi_qla_host { uint16_t aen_out; struct aen aen_q[MAX_AEN_ENTRIES]; - struct ql4_aen_log aen_log;/* tracks all aens */ + /* pdu variables */ + uint16_t pdu_count; /* Number of available aen_q entries */ + uint16_t pdu_in; /* Current indexes */ + uint16_t pdu_out; + uint16_t pdu_active; + struct pdu_entry *free_pdu_top; + struct pdu_entry *free_pdu_bottom; + struct pdu_entry pdu_queue[MAX_PDU_ENTRIES]; /* This mutex protects several threads to do mailbox commands * concurrently. */ struct mutex mbox_sem; + wait_queue_head_t mailbox_wait_queue; /* temporary mailbox status registers */ volatile uint8_t mbox_status_count; @@ -434,7 +456,11 @@ struct scsi_qla_host { /* Map ddb_list entry by FW ddb index */ struct ddb_entry *fw_ddb_index_map[MAX_DDB_ENTRIES]; - + struct ql4_aen_log aen_log; + void (*ql4getaenlog)(struct scsi_qla_host *ha, struct ql4_aen_log *aenl); +#define QL_INDICES_PER_ENTRY 32 +#define QL_OSINDEX_ENTRIES (MAX_DDB_ENTRIES/QL_INDICES_PER_ENTRY) + volatile uint32_t os_map[QL_OSINDEX_ENTRIES]; }; static inline int is_qla4010(struct scsi_qla_host *ha) @@ -512,6 +538,20 @@ static inline void __iomem * isp_gp_out(struct scsi_qla_host *ha) &ha->reg->u2.isp4022.p0.gp_out); } +static inline void __iomem * isp_probe_mux_addr(struct scsi_qla_host *ha) +{ + return (is_qla4010(ha) ? + &ha->reg->u2.isp4010.probe_mux_addr : + &ha->reg->u2.isp4022.p0.probe_mux_addr); +} + +static inline void __iomem * isp_probe_mux_data(struct scsi_qla_host *ha) +{ + return (is_qla4010(ha) ? + &ha->reg->u2.isp4010.probe_mux_data : + &ha->reg->u2.isp4022.p0.probe_mux_data); +} + static inline int eeprom_ext_hw_conf_offset(struct scsi_qla_host *ha) { return (is_qla4010(ha) ? @@ -590,5 +630,6 @@ static inline void ql4xxx_unlock_drvr(struct scsi_qla_host *a) #define PROCESS_ALL_AENS 0 #define FLUSH_DDB_CHANGED_AENS 1 #define RELOGIN_DDB_CHANGED_AENS 2 +#define PROCESS_FOR_PROBE 3 #endif /*_QLA4XXX_H */ diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h index 1b667a7..3fb3658 100644 --- a/drivers/scsi/qla4xxx/ql4_fw.h +++ b/drivers/scsi/qla4xxx/ql4_fw.h @@ -27,7 +27,11 @@ struct port_ctrl_stat_regs { __le32 rsrvd1[32]; /* 0x60-0xdf */ __le32 gp_out; /* 0xe0 */ __le32 gp_in; /* 0xe4 */ - __le32 rsrvd2[5]; /* 0xe8-0xfb */ + __le32 probe_mux_addr; /* 0xe8 */ + __le32 probe_mux_data; /* 0xec */ + __le32 stats_index; /* 0xf0 */ + __le32 stats_read_data_inc; /* 0xf4 */ + __le32 stats_read_data_noinc; /* 0xf8 */ __le32 port_err_status; /* 0xfc */ }; @@ -61,7 +65,9 @@ struct isp_reg { __le32 req_q_in; /* SCSI Request Queue Producer Index */ __le32 rsp_q_out; /* SCSI Completion Queue Consumer Index */ - __le32 reserved2[4]; /* 0x40 */ + __le32 reserved2[2]; /* 0x40 */ + __le32 arc_madi_cmd; + __le32 arc_madi_data; union { struct { @@ -79,7 +85,10 @@ struct isp_reg { __le32 gp_out; /* 0xe0 */ __le32 gp_in; - __le32 reserved5[5]; + __le32 probe_mux_addr; + __le32 probe_mux_data; + + __le32 reserved5[3]; __le32 port_err_status; /* 0xfc */ } __attribute__ ((packed)) isp4010; @@ -216,7 +225,6 @@ union external_hw_config_reg { #define MBOX_CMD_ABOUT_FW 0x0009 #define MBOX_CMD_PING 0x000B #define MBOX_CMD_LUN_RESET 0x0016 -#define MBOX_CMD_TARGET_WARM_RESET 0x0017 #define MBOX_CMD_GET_MANAGEMENT_DATA 0x001E #define MBOX_CMD_GET_FW_STATUS 0x001F #define MBOX_CMD_SET_ISNS_SERVICE 0x0021 @@ -431,8 +439,9 @@ struct init_fw_ctrl_blk { struct dev_db_entry { uint16_t options; /* 00-01 */ -#define DDB_OPT_DISC_SESSION 0x10 -#define DDB_OPT_TARGET 0x02 /* device is a target */ +#define DDB_OPT_DISC_SESSION 0x10 +#define DDB_OPT_TARGET 0x02 /* device is a target */ +#define DDB_OPT_IPV6_DEVICE 0x100 uint16_t exec_throttle; /* 02-03 */ uint16_t exec_count; /* 04-05 */ @@ -672,14 +681,13 @@ struct continuation_t1_entry { #define ET_CONTINUE ET_CONT_T1 /* Marker entry structure*/ -struct qla4_marker_entry { +struct marker_entry { struct qla4_header hdr; /* 00-03 */ uint32_t system_defined; /* 04-07 */ uint16_t target; /* 08-09 */ uint16_t modifier; /* 0A-0B */ -#define MM_LUN_RESET 0 -#define MM_TGT_WARM_RESET 1 +#define MM_LUN_RESET 0 uint16_t flags; /* 0C-0D */ uint16_t reserved1; /* 0E-0F */ @@ -733,6 +741,15 @@ struct status_entry { }; +struct pdu_entry { + uint8_t *Buff; + uint32_t BuffLen; + uint32_t SendBuffLen; + uint32_t RecvBuffLen; + struct pdu_entry *Next; + dma_addr_t DmaBuff; +}; + struct passthru0 { struct qla4_header hdr; /* 00-03 */ uint32_t handle; /* 04-07 */ diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index 96ebfb0..f948b9a 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h @@ -12,6 +12,7 @@ struct iscsi_cls_conn; void qla4xxx_hw_reset(struct scsi_qla_host *ha); int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a); +int qla4xxx_conn_start(struct iscsi_cls_conn *conn); int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port); int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb); int qla4xxx_initialize_adapter(struct scsi_qla_host * ha, @@ -27,8 +28,6 @@ int qla4xxx_relogin_device(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry); int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry, int lun); -int qla4xxx_reset_target(struct scsi_qla_host * ha, - struct ddb_entry * ddb_entry); int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr, uint32_t offset, uint32_t len); int qla4xxx_get_firmware_status(struct scsi_qla_host * ha); @@ -56,25 +55,35 @@ void qla4xxx_mark_device_missing(struct scsi_qla_host *ha, u16 rd_nvram_word(struct scsi_qla_host * ha, int offset); void qla4xxx_get_crash_record(struct scsi_qla_host * ha); struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha); -int qla4xxx_add_sess(struct ddb_entry *); +int qla4xxx_add_sess(struct ddb_entry *, int); void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry); +int qla4xxx_conn_close_sess_logout(struct scsi_qla_host * ha, + uint16_t fw_ddb_index, + uint16_t connection_id, + uint16_t option); +int qla4xxx_clear_database_entry(struct scsi_qla_host * ha, + uint16_t fw_ddb_index); int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host * ha); int qla4xxx_get_fw_version(struct scsi_qla_host * ha); void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha, uint32_t intr_status); int qla4xxx_init_rings(struct scsi_qla_host * ha); -struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, - uint32_t index); +void qla4xxx_dump_buffer(void *b, uint32_t size); +struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index); void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb); int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host * ha); int qla4xxx_process_ddb_changed(struct scsi_qla_host * ha, - uint32_t fw_ddb_index, uint32_t state); -void qla4xxx_dump_buffer(void *b, uint32_t size); + uint32_t fw_ddb_index, uint32_t state, uint32_t probe); + +int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, + uint8_t outCount, uint32_t *mbx_cmd, uint32_t *mbx_sts); int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha, - struct ddb_entry *ddb_entry, int lun, uint16_t mrkr_mod); + struct ddb_entry *ddb_entry, int lun); + + -extern int ql4xextended_error_logging; +extern int extended_error_logging; extern int ql4xdiscoverywait; extern int ql4xdontresethba; extern int ql4_mod_unload; -#endif /* _QLA4x_GBL_H */ +#endif /* _QLA4x_GBL_H */ diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 109c5f5..6e83198 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -5,12 +5,20 @@ * See LICENSE.qla4xxx for copyright and licensing details. */ -#include #include "ql4_def.h" +#include "ql4_version.h" #include "ql4_glbl.h" #include "ql4_dbg.h" #include "ql4_inline.h" +/* link auto negotiation normally takes roughly 2s. */ +/* If we don't have link in 3 times that period quit. */ +#define QLA4XXX_LINK_UP_DELAY 6 + +/* + * QLogic ISP4xxx Hardware Support Function Prototypes. + */ + static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha, uint32_t fw_ddb_index); @@ -44,7 +52,7 @@ static void ql4xxx_set_mac_number(struct scsi_qla_host *ha) } /** - * qla4xxx_free_ddb - deallocate ddb + * qla4xxx_free_ddb - deallocate ddb * @ha: pointer to host adapter structure. * @ddb_entry: pointer to device database entry * @@ -58,8 +66,7 @@ static void qla4xxx_free_ddb(struct scsi_qla_host *ha, list_del_init(&ddb_entry->list); /* Remove device pointer from index mapping arrays */ - ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = - (struct ddb_entry *) INVALID_ENTRY; + ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = NULL; ha->tot_ddbs--; /* Free memory and scsi-ml struct for device entry */ @@ -95,6 +102,7 @@ void qla4xxx_free_ddb_list(struct scsi_qla_host *ha) **/ int qla4xxx_init_rings(struct scsi_qla_host *ha) { + uint16_t i; unsigned long flags = 0; /* Initialize request queue. */ @@ -123,6 +131,10 @@ int qla4xxx_init_rings(struct scsi_qla_host *ha) writel(0, &ha->reg->rsp_q_out); readl(&ha->reg->rsp_q_out); + /* Initialize active array */ + for (i = 0; i < MAX_SRBS; i++) + ha->active_srb_array[i] = NULL; + spin_unlock_irqrestore(&ha->hardware_lock, flags); return QLA_SUCCESS; @@ -183,6 +195,16 @@ static int qla4xxx_validate_mac_address(struct scsi_qla_host *ha) **/ static int qla4xxx_init_local_data(struct scsi_qla_host *ha) { + int i; + + /* Initialize passthru PDU list */ + for (i = 0; i < (MAX_PDU_ENTRIES - 1); i++) + ha->pdu_queue[i].Next = &ha->pdu_queue[i + 1]; + ha->free_pdu_top = &ha->pdu_queue[0]; + ha->free_pdu_bottom = &ha->pdu_queue[MAX_PDU_ENTRIES - 1]; + ha->free_pdu_bottom->Next = NULL; + ha->pdu_active = 0; + /* Initilize aen queue */ ha->aen_q_count = MAX_AEN_ENTRIES; @@ -263,12 +285,10 @@ static int qla4xxx_fw_ready(struct scsi_qla_host *ha) "seconds expired= %d\n", ha->host_no, __func__, ha->firmware_state, ha->addl_fw_state, timeout_count)); - if (is_qla4032(ha) && - !(ha->addl_fw_state & FW_ADDSTATE_LINK_UP) && + if (!(ha->addl_fw_state & FW_ADDSTATE_LINK_UP) && (timeout_count < ADAPTER_INIT_TOV - 5)) { break; } - msleep(1000); } /* end of for */ @@ -276,7 +296,8 @@ static int qla4xxx_fw_ready(struct scsi_qla_host *ha) DEBUG2(printk("scsi%ld: %s: FW Initialization timed out!\n", ha->host_no, __func__)); - if (ha->firmware_state & FW_STATE_DHCP_IN_PROGRESS) { + if ((ha->firmware_state & FW_STATE_DHCP_IN_PROGRESS)|| + !(ha->addl_fw_state & FW_ADDSTATE_LINK_UP)) { DEBUG2(printk("scsi%ld: %s: FW is reporting its waiting to" " grab an IP address from DHCP server\n", ha->host_no, __func__)); @@ -307,145 +328,27 @@ static int qla4xxx_init_firmware(struct scsi_qla_host *ha) return qla4xxx_get_firmware_status(ha); } -static struct ddb_entry* qla4xxx_get_ddb_entry(struct scsi_qla_host *ha, - uint32_t fw_ddb_index, - uint32_t *new_tgt) +static void qla4xxx_fill_ddb(struct ddb_entry *ddb_entry, + struct dev_db_entry *fw_ddb_entry) { - struct dev_db_entry *fw_ddb_entry = NULL; - dma_addr_t fw_ddb_entry_dma; - struct ddb_entry *ddb_entry = NULL; - int found = 0; - uint32_t device_state; - - *new_tgt = 0; - /* Make sure the dma buffer is valid */ - fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, - sizeof(*fw_ddb_entry), - &fw_ddb_entry_dma, GFP_KERNEL); - if (fw_ddb_entry == NULL) { - DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n", - ha->host_no, __func__)); - return NULL; - } - - if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry, - fw_ddb_entry_dma, NULL, NULL, - &device_state, NULL, NULL, NULL) == - QLA_ERROR) { - DEBUG2(printk("scsi%ld: %s: failed get_ddb_entry for " - "fw_ddb_index %d\n", ha->host_no, __func__, - fw_ddb_index)); - return NULL; - } - - /* Allocate DDB if not already allocated. */ - DEBUG2(printk("scsi%ld: %s: Looking for ddb[%d]\n", ha->host_no, - __func__, fw_ddb_index)); - list_for_each_entry(ddb_entry, &ha->ddb_list, list) { - if (memcmp(ddb_entry->iscsi_name, fw_ddb_entry->iscsi_name, - ISCSI_NAME_SIZE) == 0) { - found++; - break; - } - } - - if (!found) { - DEBUG2(printk("scsi%ld: %s: ddb[%d] not found - allocating " - "new ddb\n", ha->host_no, __func__, - fw_ddb_index)); - *new_tgt = 1; - ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index); - } - - /* if not found allocate new ddb */ - dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry, - fw_ddb_entry_dma); - - return ddb_entry; -} - -/** - * qla4xxx_update_ddb_entry - update driver's internal ddb - * @ha: pointer to host adapter structure. - * @ddb_entry: pointer to device database structure to be filled - * @fw_ddb_index: index of the ddb entry in fw ddb table - * - * This routine updates the driver's internal device database entry - * with information retrieved from the firmware's device database - * entry for the specified device. The ddb_entry->fw_ddb_index field - * must be initialized prior to calling this routine - * - **/ -static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha, - struct ddb_entry *ddb_entry, - uint32_t fw_ddb_index) -{ - struct dev_db_entry *fw_ddb_entry = NULL; - dma_addr_t fw_ddb_entry_dma; - int status = QLA_ERROR; - - if (ddb_entry == NULL) { - DEBUG2(printk("scsi%ld: %s: ddb_entry is NULL\n", ha->host_no, - __func__)); - goto exit_update_ddb; - } - - /* Make sure the dma buffer is valid */ - fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, - sizeof(*fw_ddb_entry), - &fw_ddb_entry_dma, GFP_KERNEL); - if (fw_ddb_entry == NULL) { - DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n", - ha->host_no, __func__)); - - goto exit_update_ddb; - } - - if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry, - fw_ddb_entry_dma, NULL, NULL, - &ddb_entry->fw_ddb_device_state, NULL, - &ddb_entry->tcp_source_port_num, - &ddb_entry->connection_id) == - QLA_ERROR) { - DEBUG2(printk("scsi%ld: %s: failed get_ddb_entry for " - "fw_ddb_index %d\n", ha->host_no, __func__, - fw_ddb_index)); - - goto exit_update_ddb; - } - - status = QLA_SUCCESS; ddb_entry->target_session_id = le16_to_cpu(fw_ddb_entry->tsid); ddb_entry->task_mgmt_timeout = le16_to_cpu(fw_ddb_entry->def_timeout); ddb_entry->CmdSn = 0; ddb_entry->exe_throttle = le16_to_cpu(fw_ddb_entry->exec_throttle); + ddb_entry->default_relogin_timeout = le16_to_cpu(fw_ddb_entry->def_timeout); - ddb_entry->default_time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait); - - /* Update index in case it changed */ - ddb_entry->fw_ddb_index = fw_ddb_index; - ha->fw_ddb_index_map[fw_ddb_index] = ddb_entry; + ddb_entry->default_time2wait = + le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait); ddb_entry->port = le16_to_cpu(fw_ddb_entry->port); ddb_entry->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp); memcpy(&ddb_entry->iscsi_name[0], &fw_ddb_entry->iscsi_name[0], - min(sizeof(ddb_entry->iscsi_name), - sizeof(fw_ddb_entry->iscsi_name))); + min(sizeof(ddb_entry->iscsi_name), + sizeof(fw_ddb_entry->iscsi_name))); memcpy(&ddb_entry->ip_addr[0], &fw_ddb_entry->ip_addr[0], - min(sizeof(ddb_entry->ip_addr), sizeof(fw_ddb_entry->ip_addr))); - - DEBUG2(printk("scsi%ld: %s: ddb[%d] - State= %x status= %d.\n", - ha->host_no, __func__, fw_ddb_index, - ddb_entry->fw_ddb_device_state, status)); - - exit_update_ddb: - if (fw_ddb_entry) - dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), - fw_ddb_entry, fw_ddb_entry_dma); - - return status; + min(sizeof(ddb_entry->ip_addr), sizeof(fw_ddb_entry->ip_addr))); } /** @@ -478,6 +381,12 @@ static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha, atomic_set(&ddb_entry->relogin_timer, 0); atomic_set(&ddb_entry->relogin_retry_count, 0); atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); + + dev_info(&ha->pdev->dev, + "scsi%ld: %s: ddb[%d] os[%d] marked ONLINE\n", + ha->host_no, __func__, ddb_entry->fw_ddb_index, + ddb_entry->os_target_id); + list_add_tail(&ddb_entry->list, &ha->ddb_list); ha->fw_ddb_index_map[fw_ddb_index] = ddb_entry; ha->tot_ddbs++; @@ -490,7 +399,7 @@ static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha, * @ha: Pointer to host adapter structure. * * This routine searches for all valid firmware ddb entries and builds - * an internal ddb list. Ddbs that are considered valid are those with + * an internal ddb list. Ddbs that are considered valid are those with * a device state of SESSION_ACTIVE. **/ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha) @@ -501,90 +410,116 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha) uint32_t ddb_state; uint32_t conn_err, err_code; struct ddb_entry *ddb_entry; - uint32_t new_tgt; + struct dev_db_entry *fw_ddb_entry = NULL; + dma_addr_t fw_ddb_entry_dma; + uint16_t src_port, conn_id; + uint32_t ipv6_device; dev_info(&ha->pdev->dev, "Initializing DDBs ...\n"); + + fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), + &fw_ddb_entry_dma, GFP_KERNEL); + + if (fw_ddb_entry == NULL) { + DEBUG2(dev_info(&ha->pdev->dev, "%s: DMA alloc failed\n", + __func__)); + return QLA_ERROR; + } + for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES; fw_ddb_index = next_fw_ddb_index) { /* First, let's see if a device exists here */ - if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, NULL, 0, NULL, - &next_fw_ddb_index, &ddb_state, - &conn_err, NULL, NULL) == - QLA_ERROR) { - DEBUG2(printk("scsi%ld: %s: get_ddb_entry, " - "fw_ddb_index %d failed", ha->host_no, - __func__, fw_ddb_index)); - return QLA_ERROR; + if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry, + fw_ddb_entry_dma, NULL, &next_fw_ddb_index, + &ddb_state, &conn_err, &src_port, + &conn_id) == QLA_ERROR) { + DEBUG2(dev_info(&ha->pdev->dev, "%s: get_ddb_entry," + " fw_ddb_index %d failed", __func__, + fw_ddb_index)); + goto exit_ddb_list; } - DEBUG2(printk("scsi%ld: %s: Getting DDB[%d] ddbstate=0x%x, " - "next_fw_ddb_index=%d.\n", ha->host_no, __func__, + DEBUG2(dev_info(&ha->pdev->dev, "%s: DDB[%d] ddbstate=0x%x, " + "next_fw_ddb_index=%d.\n", __func__, fw_ddb_index, ddb_state, next_fw_ddb_index)); /* Issue relogin, if necessary. */ if (ddb_state == DDB_DS_SESSION_FAILED || ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) { + ipv6_device = le16_to_cpu(fw_ddb_entry->options) & + DDB_OPT_IPV6_DEVICE; /* Try and login to device */ - DEBUG2(printk("scsi%ld: %s: Login to DDB[%d]\n", - ha->host_no, __func__, fw_ddb_index)); + DEBUG2(dev_info(&ha->pdev->dev, "%s: Login DDB[%d]\n", + __func__, fw_ddb_index)); err_code = ((conn_err & 0x00ff0000) >> 16); if (err_code == 0x1c || err_code == 0x06) { - DEBUG2(printk("scsi%ld: %s send target " - "completed " - "or access denied failure\n", - ha->host_no, __func__)); - } else { + DEBUG2(dev_info(&ha->pdev->dev, + ": %s send target completed or access" + " denied failure\n", __func__)); + } else if ((!ipv6_device && + *((uint32_t *)fw_ddb_entry->ip_addr)) || + ipv6_device) { qla4xxx_set_ddb_entry(ha, fw_ddb_index, 0); if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, - NULL, 0, NULL, &next_fw_ddb_index, - &ddb_state, &conn_err, NULL, NULL) - == QLA_ERROR) { - DEBUG2(printk("scsi%ld: %s:" - "get_ddb_entry %d failed\n", - ha->host_no, + fw_ddb_entry, fw_ddb_entry_dma, NULL, + &next_fw_ddb_index, &ddb_state, + &conn_err, &src_port, + &conn_id) == QLA_ERROR) { + DEBUG2(dev_info(&ha->pdev->dev, + "%s: get_fwddb %d failed\n", __func__, fw_ddb_index)); - return QLA_ERROR; + goto exit_ddb_list; } } } - if (ddb_state != DDB_DS_SESSION_ACTIVE) - goto next_one; - /* - * if fw_ddb with session active state found, - * add to ddb_list - */ - DEBUG2(printk("scsi%ld: %s: DDB[%d] added to list\n", - ha->host_no, __func__, fw_ddb_index)); - - /* Add DDB to internal our ddb list. */ - ddb_entry = qla4xxx_get_ddb_entry(ha, fw_ddb_index, &new_tgt); - if (ddb_entry == NULL) { - DEBUG2(printk("scsi%ld: %s: Unable to allocate memory " - "for device at fw_ddb_index %d\n", - ha->host_no, __func__, fw_ddb_index)); - return QLA_ERROR; - } - /* Fill in the device structure */ - if (qla4xxx_update_ddb_entry(ha, ddb_entry, fw_ddb_index) == - QLA_ERROR) { - ha->fw_ddb_index_map[fw_ddb_index] = - (struct ddb_entry *)INVALID_ENTRY; - - - DEBUG2(printk("scsi%ld: %s: update_ddb_entry failed " - "for fw_ddb_index %d.\n", - ha->host_no, __func__, fw_ddb_index)); - return QLA_ERROR; + if (!(le16_to_cpu(fw_ddb_entry->options) & DDB_OPT_DISC_SESSION) && + (ddb_state != DDB_DS_UNASSIGNED) && + (strlen(fw_ddb_entry->iscsi_name) != 0)){ + ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index); + if (ddb_entry == NULL) { + DEBUG2(dev_info(&ha->pdev->dev,"%s alloc_ddb %d " + "failed\n", __func__, fw_ddb_index)); + goto exit_ddb_list; + } + ddb_entry->fw_ddb_index = fw_ddb_index; + ha->fw_ddb_index_map[fw_ddb_index] = ddb_entry; + ddb_entry->tcp_source_port_num = src_port; + ddb_entry->connection_id = conn_id; + qla4xxx_fill_ddb(ddb_entry, fw_ddb_entry); + ddb_entry->fw_ddb_device_state = ddb_state; + + if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { + atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); + dev_info(&ha->pdev->dev, + "scsi%ld: %s: ddb[%d] os[%d] marked ONLINE\n", + ha->host_no, __func__, ddb_entry->fw_ddb_index, + ddb_entry->os_target_id); + } else { + atomic_set(&ddb_entry->state, DDB_STATE_MISSING); + dev_info(&ha->pdev->dev, + "scsi%ld: %s: ddb[%d] os[%d] marked MISSING\n", + ha->host_no, __func__, ddb_entry->fw_ddb_index, + ddb_entry->os_target_id); + } + DEBUG6(dev_info(&ha->pdev->dev, "%s: DDB[%d] osIdx = %d State %04x" + " ConnErr %08x %d.%d.%d.%d:%04d \"%s\"\n", __func__, + fw_ddb_index, ddb_entry->os_target_id, ddb_state, conn_err, + fw_ddb_entry->ip_addr[0], fw_ddb_entry->ip_addr[1], + fw_ddb_entry->ip_addr[2], fw_ddb_entry->ip_addr[3], + le16_to_cpu(fw_ddb_entry->port), + fw_ddb_entry->iscsi_name)); } -next_one: /* We know we've reached the last device when * next_fw_ddb_index is 0 */ if (next_fw_ddb_index == 0) break; } +exit_ddb_list: + dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry, + fw_ddb_entry_dma); dev_info(&ha->pdev->dev, "DDB list done..\n"); return status; @@ -682,15 +617,18 @@ static int qla4_scan_for_relogin(struct scsi_qla_host *ha, static int qla4xxx_devices_ready(struct scsi_qla_host *ha) { int error; - unsigned long discovery_wtime; + unsigned long discovery_wtime = 0; struct qla4_relog_scan rs; - discovery_wtime = jiffies + (ql4xdiscoverywait * HZ); - DEBUG(printk("Waiting (%d) for devices ...\n", ql4xdiscoverywait)); do { /* poll for AEN. */ qla4xxx_get_firmware_state(ha); + + if(!(ha->addl_fw_state & FW_ADDSTATE_LINK_UP) && + (discovery_wtime > QLA4XXX_LINK_UP_DELAY)) + break; + if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) { /* Set time-between-relogin timer */ qla4xxx_process_aen(ha, RELOGIN_DDB_CHANGED_AENS); @@ -708,7 +646,8 @@ static int qla4xxx_devices_ready(struct scsi_qla_host *ha) } msleep(2000); - } while (!time_after_eq(jiffies, discovery_wtime)); + discovery_wtime += 2; + } while (discovery_wtime < ql4xdiscoverywait); DEBUG3(qla4xxx_get_conn_event_log(ha)); @@ -750,13 +689,13 @@ static int qla4xxx_initialize_ddb_list(struct scsi_qla_host *ha) qla4xxx_free_ddb_list(ha); for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES; fw_ddb_index++) - ha->fw_ddb_index_map[fw_ddb_index] = - (struct ddb_entry *)INVALID_ENTRY; + ha->fw_ddb_index_map[fw_ddb_index] = NULL; ha->tot_ddbs = 0; qla4xxx_flush_AENS(ha); + /* * First perform device discovery for active * fw ddb indexes and build @@ -773,7 +712,7 @@ static int qla4xxx_initialize_ddb_list(struct scsi_qla_host *ha) * the aens here will catch them. */ if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) - qla4xxx_process_aen(ha, PROCESS_ALL_AENS); + qla4xxx_process_aen(ha, PROCESS_FOR_PROBE); return status; } @@ -789,19 +728,37 @@ int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host *ha) { int status = QLA_SUCCESS; struct ddb_entry *ddb_entry, *detemp; + struct dev_db_entry *fw_ddb_entry = NULL; + dma_addr_t fw_ddb_entry_dma; + + fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, + sizeof(*fw_ddb_entry), &fw_ddb_entry_dma, + GFP_KERNEL); + if (fw_ddb_entry == NULL) + return QLA_ERROR; /* Update the device information for all devices. */ list_for_each_entry_safe(ddb_entry, detemp, &ha->ddb_list, list) { - qla4xxx_update_ddb_entry(ha, ddb_entry, - ddb_entry->fw_ddb_index); - if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { - atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); - DEBUG2(printk ("scsi%ld: %s: ddb index [%d] marked " - "ONLINE\n", ha->host_no, __func__, - ddb_entry->fw_ddb_index)); - } else if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE) - qla4xxx_mark_device_missing(ha, ddb_entry); + if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, + fw_ddb_entry, fw_ddb_entry_dma, NULL, NULL, + &ddb_entry->fw_ddb_device_state, NULL, + &ddb_entry->tcp_source_port_num, + &ddb_entry->connection_id) == QLA_SUCCESS) { + + qla4xxx_fill_ddb(ddb_entry, fw_ddb_entry); + + if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { + atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); + dev_info(&ha->pdev->dev, + "scsi%ld: %s: ddb[%d] os[%d] marked ONLINE\n", + ha->host_no, __func__, ddb_entry->fw_ddb_index, + ddb_entry->os_target_id); + } else if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE) + qla4xxx_mark_device_missing(ha, ddb_entry); + } } + dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), + fw_ddb_entry, fw_ddb_entry_dma); return status; } @@ -884,12 +841,11 @@ static int qla4xxx_config_nvram(struct scsi_qla_host *ha) static void qla4x00_pci_config(struct scsi_qla_host *ha) { uint16_t w; - int status; dev_info(&ha->pdev->dev, "Configuring PCI space...\n"); pci_set_master(ha->pdev); - status = pci_set_mwi(ha->pdev); + pci_set_mwi(ha->pdev); /* * We want to respect framework's setting of PCI configuration space * command register and also want to make sure that all bits of @@ -1007,7 +963,7 @@ int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a) * qla4xxx_start_firmware - starts qla4xxx firmware * @ha: Pointer to host adapter structure. * - * This routine performs the necessary steps to start the firmware for + * This routine performs the neccessary steps to start the firmware for * the QLA4010 adapter. **/ static int qla4xxx_start_firmware(struct scsi_qla_host *ha) @@ -1127,7 +1083,7 @@ static int qla4xxx_start_firmware(struct scsi_qla_host *ha) * @renew_ddb_list: Indicates what to do with the adapter's ddb list * after adapter recovery has completed. * 0=preserve ddb list, 1=destroy and rebuild ddb list - * + * * This routine parforms all of the steps necessary to initialize the adapter. * **/ @@ -1211,51 +1167,81 @@ exit_init_hba: * This routine processes adds a device as a result of an 8014h AEN. **/ static void qla4xxx_add_device_dynamically(struct scsi_qla_host *ha, - uint32_t fw_ddb_index) + uint32_t fw_ddb_index, uint32_t probe) { - struct ddb_entry * ddb_entry; - uint32_t new_tgt; + struct dev_db_entry *fw_ddb_entry = NULL; + dma_addr_t fw_ddb_entry_dma; + uint16_t src_port, conn_id; + struct ddb_entry *ddb_entry = NULL; + uint32_t ddb_state, found = 0; - /* First allocate a device structure */ - ddb_entry = qla4xxx_get_ddb_entry(ha, fw_ddb_index, &new_tgt); - if (ddb_entry == NULL) { - DEBUG2(printk(KERN_WARNING - "scsi%ld: Unable to allocate memory to add " - "fw_ddb_index %d\n", ha->host_no, fw_ddb_index)); + fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), + &fw_ddb_entry_dma, GFP_KERNEL); + + if (fw_ddb_entry == NULL) { + DEBUG2(dev_info(&ha->pdev->dev, "%s dmaalloc failed\n", __func__)); return; } - if (!new_tgt && (ddb_entry->fw_ddb_index != fw_ddb_index)) { + if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry, + fw_ddb_entry_dma, NULL, NULL, &ddb_state, NULL, &src_port, + &conn_id) == QLA_ERROR) { + DEBUG2(dev_info(&ha->pdev->dev, "%s getddb %d failed\n", + __func__, fw_ddb_index)); + return; + } + + list_for_each_entry(ddb_entry, &ha->ddb_list, list) { + if (memcmp(ddb_entry->iscsi_name, fw_ddb_entry->iscsi_name, + ISCSI_NAME_SIZE) == 0) { + found = 1; + + DEBUG6(dev_info(&ha->pdev->dev, "%s found target ddb = 0x%p" + " sess 0x%p conn 0x%p state 0x%x nidx 0x%x oidx 0x%x\n", + __func__, ddb_entry, ddb_entry->sess, ddb_entry->conn, + ddb_entry->state, fw_ddb_index, ddb_entry->fw_ddb_index)); + break; + } + } + + if (!found) + ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index); + else if (ddb_entry->fw_ddb_index != fw_ddb_index) { /* Target has been bound to a new fw_ddb_index */ qla4xxx_free_ddb(ha, ddb_entry); ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index); - if (ddb_entry == NULL) { - DEBUG2(printk(KERN_WARNING - "scsi%ld: Unable to allocate memory" - " to add fw_ddb_index %d\n", - ha->host_no, fw_ddb_index)); - return; - } } - if (qla4xxx_update_ddb_entry(ha, ddb_entry, fw_ddb_index) == - QLA_ERROR) { - ha->fw_ddb_index_map[fw_ddb_index] = - (struct ddb_entry *)INVALID_ENTRY; - DEBUG2(printk(KERN_WARNING - "scsi%ld: failed to add new device at index " - "[%d]\n Unable to retrieve fw ddb entry\n", - ha->host_no, fw_ddb_index)); - qla4xxx_free_ddb(ha, ddb_entry); - return; + + if (ddb_entry == NULL) { + DEBUG2(dev_info(&ha->pdev->dev, "%s NULL DDB %d\n", + __func__, fw_ddb_index)); + goto exit_dyn_add; } - if (qla4xxx_add_sess(ddb_entry)) { - DEBUG2(printk(KERN_WARNING + ddb_entry->fw_ddb_index = fw_ddb_index; + ha->fw_ddb_index_map[fw_ddb_index] = ddb_entry; + ddb_entry->tcp_source_port_num = src_port; + ddb_entry->connection_id = conn_id; + qla4xxx_fill_ddb(ddb_entry, fw_ddb_entry); + ddb_entry->fw_ddb_device_state = ddb_state; + + if (!probe) { + if (qla4xxx_add_sess(ddb_entry, 1)) { + DEBUG2(printk(KERN_WARNING "scsi%ld: failed to add new device at index " "[%d]\n Unable to add connection and session\n", ha->host_no, fw_ddb_index)); - qla4xxx_free_ddb(ha, ddb_entry); + qla4xxx_free_ddb(ha, ddb_entry); + } } + + DEBUG6(dev_info(&ha->pdev->dev, "%s added ddb 0x%p sess 0x%p conn 0x%p" + " state 0x%x\n", __func__, ddb_entry, ddb_entry->sess, + ddb_entry->conn, ddb_entry->state)); +exit_dyn_add: + dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry, + fw_ddb_entry_dma); + return; } /** @@ -1267,11 +1253,13 @@ static void qla4xxx_add_device_dynamically(struct scsi_qla_host *ha, * This routine processes a Decive Database Changed AEN Event. **/ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, - uint32_t fw_ddb_index, uint32_t state) + uint32_t fw_ddb_index, uint32_t state, uint32_t probe) { struct ddb_entry * ddb_entry; uint32_t old_fw_ddb_device_state; + DEBUG6(dev_info(&ha->pdev->dev, "%s idx %d nstate 0x%x\n", + __func__, fw_ddb_index, state)); /* check for out of range index */ if (fw_ddb_index >= MAX_DDB_ENTRIES) return QLA_ERROR; @@ -1281,9 +1269,12 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, /* Device does not currently exist in our database. */ if (ddb_entry == NULL) { if (state == DDB_DS_SESSION_ACTIVE) - qla4xxx_add_device_dynamically(ha, fw_ddb_index); + qla4xxx_add_device_dynamically(ha, fw_ddb_index, probe); return QLA_SUCCESS; } + DEBUG6(dev_info(&ha->pdev->dev, "%s ddb_entry 0x%p ostate 0x%x" + " sess 0x%p conn 0x%p\n", __func__, ddb_entry, + ddb_entry->state, ddb_entry->sess, ddb_entry->conn)); /* Device already exists in our database. */ old_fw_ddb_device_state = ddb_entry->fw_ddb_device_state; @@ -1297,25 +1288,43 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, } ddb_entry->fw_ddb_device_state = state; + + if (probe) + return QLA_SUCCESS; + /* Device is back online. */ if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { - atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); atomic_set(&ddb_entry->port_down_timer, ha->port_down_retry_count); + atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); atomic_set(&ddb_entry->relogin_retry_count, 0); atomic_set(&ddb_entry->relogin_timer, 0); clear_bit(DF_RELOGIN, &ddb_entry->flags); clear_bit(DF_NO_RELOGIN, &ddb_entry->flags); - iscsi_unblock_session(ddb_entry->sess); - iscsi_session_event(ddb_entry->sess, - ISCSI_KEVENT_CREATE_SESSION); - /* - * Change the lun state to READY in case the lun TIMEOUT before - * the device came back. - */ + + DEBUG6(dev_info(&ha->pdev->dev, "%s conn startddb_entry 0x%p" + " sess 0x%p conn 0x%p\n", + __func__, ddb_entry, ddb_entry->sess, ddb_entry->conn)); + + qla4xxx_conn_start(ddb_entry->conn); + + DEBUG6(dev_info(&ha->pdev->dev, "%s conn start done " + "ddb_entry 0x%p sess 0x%p conn 0x%p\n", + __func__, ddb_entry, ddb_entry->sess, ddb_entry->conn)); + + if (!test_bit(DF_SCAN_ISSUED, &ddb_entry->flags)) { + scsi_scan_target(&ddb_entry->sess->dev, 0, + ddb_entry->sess->target_id, + SCAN_WILD_CARD, 0); + set_bit(DF_SCAN_ISSUED, &ddb_entry->flags); + } } else { /* Device went away, try to relogin. */ /* Mark device missing */ + DEBUG6(dev_info(&ha->pdev->dev, "%s mark missing ddb_entry 0x%p" + " sess 0x%p conn 0x%p\n", __func__, ddb_entry, + ddb_entry->sess, ddb_entry->conn)); + if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE) qla4xxx_mark_device_missing(ha, ddb_entry); /* @@ -1325,8 +1334,7 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, */ if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_FAILED && !test_bit(DF_RELOGIN, &ddb_entry->flags) && - !test_bit(DF_NO_RELOGIN, &ddb_entry->flags) && - !test_bit(DF_ISNS_DISCOVERED, &ddb_entry->flags)) { + !test_bit(DF_NO_RELOGIN, &ddb_entry->flags)) { /* * This triggers a relogin. After the relogin_timer * expires, the relogin gets scheduled. We must wait a diff --git a/drivers/scsi/qla4xxx/ql4_inline.h b/drivers/scsi/qla4xxx/ql4_inline.h index 6375eb0..3cf28aa 100644 --- a/drivers/scsi/qla4xxx/ql4_inline.h +++ b/drivers/scsi/qla4xxx/ql4_inline.h @@ -24,8 +24,7 @@ qla4xxx_lookup_ddb_by_fw_index(struct scsi_qla_host *ha, uint32_t fw_ddb_index) struct ddb_entry *ddb_entry = NULL; if ((fw_ddb_index < MAX_DDB_ENTRIES) && - (ha->fw_ddb_index_map[fw_ddb_index] != - (struct ddb_entry *) INVALID_ENTRY)) { + (ha->fw_ddb_index_map[fw_ddb_index] != NULL)) { ddb_entry = ha->fw_ddb_index_map[fw_ddb_index]; } diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c index 912a674..d387386 100644 --- a/drivers/scsi/qla4xxx/ql4_iocb.c +++ b/drivers/scsi/qla4xxx/ql4_iocb.c @@ -6,11 +6,12 @@ */ #include "ql4_def.h" +#include "ql4_version.h" #include "ql4_glbl.h" #include "ql4_dbg.h" #include "ql4_inline.h" - +#define VMWARE_CMD_TIMEOUT 30 #include /** @@ -67,9 +68,9 @@ static int qla4xxx_get_req_pkt(struct scsi_qla_host *ha, * This routine issues a marker IOCB. **/ int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha, - struct ddb_entry *ddb_entry, int lun, uint16_t mrkr_mod) + struct ddb_entry *ddb_entry, int lun) { - struct qla4_marker_entry *marker_entry; + struct marker_entry *marker_entry; unsigned long flags = 0; uint8_t status = QLA_SUCCESS; @@ -87,7 +88,7 @@ int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha, marker_entry->hdr.entryType = ET_MARKER; marker_entry->hdr.entryCount = 1; marker_entry->target = cpu_to_le16(ddb_entry->fw_ddb_index); - marker_entry->modifier = cpu_to_le16(mrkr_mod); + marker_entry->modifier = cpu_to_le16(MM_LUN_RESET); int_to_scsilun(lun, &marker_entry->lun); wmb(); @@ -160,6 +161,13 @@ static void qla4xxx_build_scsi_iocbs(struct srb *srb, avail_dsds = COMMAND_SEG; cur_dsd = (struct data_seg_a64 *) & (cmd_entry->dataseg[0]); + if (srb->flags & SRB_SCSI_PASSTHRU) { + cur_dsd->base.addrLow = cpu_to_le32(LSDW(srb->dma_handle)); + cur_dsd->base.addrHigh = cpu_to_le32(MSDW(srb->dma_handle)); + cur_dsd->count = cpu_to_le32(srb->dma_len); + return; + } + scsi_for_each_sg(cmd, sg, tot_dsds, i) { dma_addr_t sle_dma; @@ -204,6 +212,7 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb) unsigned long flags; uint16_t cnt; + uint16_t i; uint32_t index; char tag[2]; @@ -215,7 +224,22 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb) /* Acquire hardware specific lock */ spin_lock_irqsave(&ha->hardware_lock, flags); - index = (uint32_t)cmd->request->tag; + index = ha->current_active_index; + for (i = 0; i < MAX_SRBS; i++) { + index++; + if (index == MAX_SRBS) + index = 1; + if (ha->active_srb_array[index] == 0) { + ha->current_active_index = index; + break; + } + } + if (i >= MAX_SRBS) { + printk(KERN_INFO "scsi%ld: %s: NO more SRB entries used " + "iocbs=%d, \n reqs remaining=%d\n", ha->host_no, + __func__, ha->iocb_cnt, ha->req_q_count); + goto queuing_error; + } /* Calculate the number of request entries needed. */ nseg = scsi_dma_map(cmd); @@ -258,8 +282,8 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb) /* Set data transfer direction control flags * NOTE: Look at data_direction bits iff there is data to be - * transferred, as the data direction bit is sometimed filled - * in when there is no data to be transferred */ + * transferred, as the data direction bit is sometimed filled + * in when there is no data to be transferred */ cmd_entry->control_flags = CF_NO_DATA; if (scsi_bufflen(cmd)) { if (cmd->sc_data_direction == DMA_TO_DEVICE) @@ -286,7 +310,6 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb) break; } - /* Advance request queue pointer */ ha->request_in++; if (ha->request_in == REQUEST_QUEUE_DEPTH) { @@ -313,6 +336,7 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb) } srb->cmd->host_scribble = (unsigned char *)srb; + ha->active_srb_array[index] = srb; /* update counters */ srb->state = SRB_ACTIVE_STATE; @@ -331,6 +355,9 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb) return QLA_SUCCESS; queuing_error: + if (srb->flags & SRB_SCSI_PASSTHRU) + return QLA_ERROR; + if (tot_dsds) scsi_dma_unmap(cmd); @@ -338,4 +365,3 @@ queuing_error: return QLA_ERROR; } - diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c index 799120f..dfe985b 100644 --- a/drivers/scsi/qla4xxx/ql4_isr.c +++ b/drivers/scsi/qla4xxx/ql4_isr.c @@ -6,6 +6,7 @@ */ #include "ql4_def.h" +#include "ql4_version.h" #include "ql4_glbl.h" #include "ql4_dbg.h" #include "ql4_inline.h" @@ -27,11 +28,6 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, srb = qla4xxx_del_from_active_array(ha, le32_to_cpu(sts_entry->handle)); if (!srb) { - /* FIXMEdg: Don't we need to reset ISP in this case??? */ - DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Status Entry invalid " - "handle 0x%x, sp=%p. This cmd may have already " - "been completed.\n", ha->host_no, __func__, - le32_to_cpu(sts_entry->handle), srb)); dev_warn(&ha->pdev->dev, "%s invalid status entry:" " handle=0x%0x\n", __func__, sts_entry->handle); set_bit(DPC_RESET_HA, &ha->dpc_flags); @@ -40,12 +36,9 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, cmd = srb->cmd; if (cmd == NULL) { - DEBUG2(printk("scsi%ld: %s: Command already returned back to " - "OS pkt->handle=%d srb=%p srb->state:%d\n", - ha->host_no, __func__, sts_entry->handle, - srb, srb->state)); - dev_warn(&ha->pdev->dev, "Command is NULL:" - " already returned to OS (srb=%p)\n", srb); + dev_warn(&ha->pdev->dev, "%s Command is NULL: srb=%p" + " sts_handle=0x%0x srb_state=0x%0x\n", __func__, + srb, sts_entry->handle, srb->state); return; } @@ -61,27 +54,15 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, scsi_status = sts_entry->scsiStatus; switch (sts_entry->completionStatus) { case SCS_COMPLETE: - if (sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_OVER) { cmd->result = DID_ERROR << 16; break; } - - if (sts_entry->iscsiFlags &ISCSI_FLAG_RESIDUAL_UNDER) { + if (sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_UNDER) { scsi_set_resid(cmd, residual); if (!scsi_status && ((scsi_bufflen(cmd) - residual) < - cmd->underflow)) { - + cmd->underflow)) { cmd->result = DID_ERROR << 16; - - DEBUG2(printk("scsi%ld:%d:%d:%d: %s: " - "Mid-layer Data underrun0, " - "xferlen = 0x%x, " - "residual = 0x%x\n", ha->host_no, - cmd->device->channel, - cmd->device->id, - cmd->device->lun, __func__, - scsi_bufflen(cmd), residual)); break; } } @@ -218,13 +202,13 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, * will return DID_ERROR. */ DEBUG2(printk("scsi%ld:%d:%d:%d: %s: " - "Mid-layer Data underrun1, " - "xferlen = 0x%x, " - "residual = 0x%x\n", ha->host_no, - cmd->device->channel, - cmd->device->id, - cmd->device->lun, __func__, - scsi_bufflen(cmd), residual)); + "Mid-layer Data underrun len = 0x%x, " + "resid = 0x%x, compstat = 0x%x\n", + ha->host_no, cmd->device->channel, + cmd->device->id, cmd->device->lun, + __func__, scsi_bufflen(cmd), + residual, + sts_entry->completionStatus)); cmd->result = DID_ERROR << 16; } else { @@ -414,6 +398,15 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, } else if (mbox_status >> 12 == MBOX_ASYNC_EVENT_STATUS) { /* Immediately process the AENs that don't require much work. * Only queue the database_changed AENs */ + + dev_info(&ha->pdev->dev, "%s mbx0 0x%08x mbx1 0x%08x" + " mbx2 0x%08x mbx3 0x%08x mbx4 0x%08x mbx5 0x%08x " + "mbx6 0x%08x mbx7 0x%08x\n", __func__, + readl(&ha->reg->mailbox[0]), readl(&ha->reg->mailbox[1]), + readl(&ha->reg->mailbox[2]), readl(&ha->reg->mailbox[3]), + readl(&ha->reg->mailbox[4]), readl(&ha->reg->mailbox[5]), + readl(&ha->reg->mailbox[6]), readl(&ha->reg->mailbox[7])); + if (ha->aen_log.count < MAX_AEN_ENTRIES) { for (i = 0; i < MBOX_AEN_REG_COUNT; i++) ha->aen_log.entry[ha->aen_log.count].mbox_sts[i] = @@ -480,9 +473,9 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, mbox_stat2 = readl(&ha->reg->mailbox[2]); mbox_stat3 = readl(&ha->reg->mailbox[3]); - if ((mbox_stat3 == 5) && (mbox_stat2 == 3)) + if ((mbox_stat3 == 5) && (mbox_stat2 == 3)) set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags); - else if ((mbox_stat3 == 2) && (mbox_stat2 == 5)) + else if ((mbox_stat3 == 2) && (mbox_stat2 == 5)) set_bit(DPC_RESET_HA, &ha->dpc_flags); break; @@ -604,6 +597,7 @@ void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha, **/ irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id) { + struct scsi_qla_host *ha; uint32_t intr_status; unsigned long flags = 0; @@ -714,7 +708,17 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen) int i; unsigned long flags; + DEBUG6(dev_info(&ha->pdev->dev, "%s proc_aen 0x%x\n", + __func__, process_aen)); + spin_lock_irqsave(&ha->hardware_lock, flags); + if (process_aen == FLUSH_DDB_CHANGED_AENS) { + ha->aen_q_count = MAX_AEN_ENTRIES; + ha->aen_out = ha->aen_in = 0; + spin_unlock_irqrestore(&ha->hardware_lock, flags); + return; + } + while (ha->aen_out != ha->aen_in) { aen = &ha->aen_q[ha->aen_out]; /* copy aen information to local structure */ @@ -727,60 +731,46 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen) if (ha->aen_out == MAX_AEN_ENTRIES) ha->aen_out = 0; - spin_unlock_irqrestore(&ha->hardware_lock, flags); + DEBUG6(dev_info(&ha->pdev->dev, "%s mbx0 0x%x mbx1 0x%x mbx2 " + "0x%x mbx3 0x%x ddb 0x%p\n", __func__, mbox_sts[0], + mbox_sts[1], mbox_sts[2], mbox_sts[3], + qla4xxx_lookup_ddb_by_fw_index(ha, mbox_sts[2]))); - DEBUG2(printk("qla4xxx(%ld): AEN[%d]=0x%08x, mbx1=0x%08x mbx2=0x%08x" - " mbx3=0x%08x mbx4=0x%08x\n", ha->host_no, - (ha->aen_out ? (ha->aen_out-1): (MAX_AEN_ENTRIES-1)), - mbox_sts[0], mbox_sts[1], mbox_sts[2], - mbox_sts[3], mbox_sts[4])); + if (process_aen == RELOGIN_DDB_CHANGED_AENS) { + /* for use during init time, we only want to + * relogin non-active ddbs */ + struct ddb_entry *ddb_entry; - switch (mbox_sts[0]) { - case MBOX_ASTS_DATABASE_CHANGED: - if (process_aen == FLUSH_DDB_CHANGED_AENS) { - DEBUG2(printk("scsi%ld: AEN[%d] %04x, index " - "[%d] state=%04x FLUSHED!\n", - ha->host_no, ha->aen_out, - mbox_sts[0], mbox_sts[2], - mbox_sts[3])); - break; - } else if (process_aen == RELOGIN_DDB_CHANGED_AENS) { - /* for use during init time, we only want to - * relogin non-active ddbs */ - struct ddb_entry *ddb_entry; - - ddb_entry = - /* FIXME: name length? */ - qla4xxx_lookup_ddb_by_fw_index(ha, - mbox_sts[2]); - if (!ddb_entry) - break; - - ddb_entry->dev_scan_wait_to_complete_relogin = - 0; + ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, mbox_sts[2]); + + if (ddb_entry) { + + DEBUG6(dev_info(&ha->pdev->dev, "%s ddb 0x%p " + "sess 0x%p conn 0x%p state 0x%x\n", + __func__, ddb_entry, ddb_entry->sess, + ddb_entry->conn, ddb_entry->state)); + + ddb_entry->dev_scan_wait_to_complete_relogin = 0; ddb_entry->dev_scan_wait_to_start_relogin = jiffies + - ((ddb_entry->default_time2wait + - 4) * HZ); + ((ddb_entry->default_time2wait + 4) * HZ); DEBUG2(printk("scsi%ld: ddb index [%d] initate" - " RELOGIN after %d seconds\n", - ha->host_no, - ddb_entry->fw_ddb_index, - ddb_entry->default_time2wait + - 4)); - break; + " RELOGIN after %d seconds\n", ha->host_no, + ddb_entry->fw_ddb_index, + ddb_entry->default_time2wait + 4)); } - + } else if (mbox_sts[0] == MBOX_ASTS_DATABASE_CHANGED) { + spin_unlock_irqrestore(&ha->hardware_lock, flags); if (mbox_sts[1] == 0) { /* Global DB change. */ qla4xxx_reinitialize_ddb_list(ha); } else if (mbox_sts[1] == 1) { /* Specific device. */ qla4xxx_process_ddb_changed(ha, mbox_sts[2], - mbox_sts[3]); + mbox_sts[3], + ((process_aen == PROCESS_FOR_PROBE) ? 1 : 0 )); } - break; + spin_lock_irqsave(&ha->hardware_lock, flags); } - spin_lock_irqsave(&ha->hardware_lock, flags); } spin_unlock_irqrestore(&ha->hardware_lock, flags); } diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index c577d79..dbd7218 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -6,6 +6,7 @@ */ #include "ql4_def.h" +#include "ql4_version.h" #include "ql4_glbl.h" #include "ql4_dbg.h" #include "ql4_inline.h" @@ -23,9 +24,9 @@ * If outCount is 0, this routine completes successfully WITHOUT waiting * for the mailbox command to complete. **/ -static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, - uint8_t outCount, uint32_t *mbx_cmd, - uint32_t *mbx_sts) +int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, + uint8_t outCount, uint32_t *mbx_cmd, + uint32_t *mbx_sts) { int status = QLA_ERROR; uint8_t i; @@ -39,9 +40,9 @@ static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, "pointer\n", ha->host_no, __func__)); return status; } + /* Mailbox code active */ wait_count = MBOX_TOV * 100; - while (wait_count--) { mutex_lock(&ha->mbox_sem); if (!test_bit(AF_MBOX_COMMAND, &ha->flags)) { @@ -87,8 +88,6 @@ static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, readl(&ha->reg->ctrl_status); spin_unlock_irqrestore(&ha->hardware_lock, flags); - /* Wait for completion */ - /* * If we don't want status, don't wait for the mailbox command to * complete. For example, MBOX_CMD_RESET_FW doesn't return status, @@ -98,6 +97,8 @@ static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, status = QLA_SUCCESS; goto mbox_exit; } + /* Wait for completion */ + set_current_state(TASK_UNINTERRUPTIBLE); /* Wait for command to complete */ wait_count = jiffies + MBOX_TOV * HZ; while (test_bit(AF_MBOX_COMMAND_DONE, &ha->flags) == 0) { @@ -119,6 +120,7 @@ static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, spin_unlock_irqrestore(&ha->hardware_lock, flags); msleep(10); } + set_current_state(TASK_RUNNING); /* Check for mailbox timeout. */ if (!test_bit(AF_MBOX_COMMAND_DONE, &ha->flags)) { @@ -172,6 +174,86 @@ mbox_exit: return status; } + +/** + * qla4xxx_issue_iocb - issue mailbox iocb command + * @ha: adapter state pointer. + * @buffer: buffer pointer. + * @phys_addr: physical address of buffer. + * @size: size of buffer. + * + * Issues iocbs via mailbox commands. + * TARGET_QUEUE_LOCK must be released. + * ADAPTER_STATE_LOCK must be released. + **/ +int +qla4xxx_issue_iocb(struct scsi_qla_host * ha, void *buffer, + dma_addr_t phys_addr, size_t size) +{ + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + int status; + + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); + + mbox_cmd[0] = MBOX_CMD_EXECUTE_IOCB_A64; + mbox_cmd[1] = 0; + mbox_cmd[2] = LSDW(phys_addr); + mbox_cmd[3] = MSDW(phys_addr); + + status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]); + return status; +} + +int qla4xxx_conn_close_sess_logout(struct scsi_qla_host * ha, + uint16_t fw_ddb_index, + uint16_t connection_id, + uint16_t option) +{ + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); + + mbox_cmd[0] = MBOX_CMD_CONN_CLOSE_SESS_LOGOUT; + mbox_cmd[1] = fw_ddb_index; + mbox_cmd[2] = connection_id; + mbox_cmd[3] = LOGOUT_OPTION_RELOGIN; + + if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 2, &mbox_cmd[0], &mbox_sts[0]) != + QLA_SUCCESS) { + DEBUG2(printk("scsi%ld: %s: MBOX_CMD_CONN_CLOSE_SESS_LOGOUT " + "option %04x failed sts %04X %04X", + ha->host_no, __func__, + option, mbox_sts[0], mbox_sts[1])); + if (mbox_sts[0] == 0x4005) + DEBUG2(printk("%s reason %04X\n", __func__, + mbox_sts[1])); + } + return QLA_SUCCESS; +} + +int qla4xxx_clear_database_entry(struct scsi_qla_host * ha, + uint16_t fw_ddb_index) +{ + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); + + mbox_cmd[0] = MBOX_CMD_CLEAR_DATABASE_ENTRY; + mbox_cmd[1] = fw_ddb_index; + + if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) != + QLA_SUCCESS) + return QLA_ERROR; + + return QLA_SUCCESS; +} + /** * qla4xxx_initialize_fw_cb - initializes firmware control block. * @ha: Pointer to host adapter structure. @@ -450,15 +532,16 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha, mbox_sts[1])); goto exit_get_fwddb; } + if (fw_ddb_entry) { - dev_info(&ha->pdev->dev, "DDB[%d] MB0 %04x Tot %d Next %d " - "State %04x ConnErr %08x %d.%d.%d.%d:%04d \"%s\"\n", + DEBUG6(dev_info(&ha->pdev->dev, "%s: DDB[%d] MB0 %04x Tot %d Next %d " + "State %04x ConnErr %08x %d.%d.%d.%d:%04d \"%s\"\n", __func__, fw_ddb_index, mbox_sts[0], mbox_sts[2], mbox_sts[3], mbox_sts[4], mbox_sts[5], fw_ddb_entry->ip_addr[0], fw_ddb_entry->ip_addr[1], fw_ddb_entry->ip_addr[2], fw_ddb_entry->ip_addr[3], le16_to_cpu(fw_ddb_entry->port), - fw_ddb_entry->iscsi_name); + fw_ddb_entry->iscsi_name)); } if (num_valid_ddb_entries) *num_valid_ddb_entries = mbox_sts[2]; @@ -518,6 +601,31 @@ int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index, return qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]); } +int qla4xxx_conn_open_session_login(struct scsi_qla_host * ha, + uint16_t fw_ddb_index) +{ + int status = QLA_ERROR; + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + + /* Do not wait for completion. The firmware will send us an + * ASTS_DATABASE_CHANGED (0x8014) to notify us of the login status. + */ + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); + + mbox_cmd[0] = MBOX_CMD_CONN_OPEN_SESS_LOGIN; + mbox_cmd[1] = (uint32_t) fw_ddb_index; + mbox_cmd[6] = 1; + + status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 0, &mbox_cmd[0], &mbox_sts[0]); + DEBUG2(printk("%s fw_ddb_index=%d status=%d mbx0_1=0x%x :0x%x\n", + __func__, fw_ddb_index, status, mbox_sts[0], + mbox_sts[1]);) + + return status; +} + /** * qla4xxx_get_crash_record - retrieves crash record. * @ha: Pointer to host adapter structure. @@ -642,7 +750,7 @@ void qla4xxx_get_conn_event_log(struct scsi_qla_host * ha) DEBUG3(printk("scsi%ld: Connection Event Log Dump (%d entries):\n", ha->host_no, num_valid_entries)); - if (ql4xextended_error_logging == 3) { + if (extended_error_logging == 3) { if (oldest_entry == 0) { /* Circular Buffer has not wrapped around */ for (i=0; i < num_valid_entries; i++) { @@ -713,45 +821,6 @@ int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry, return status; } -/** - * qla4xxx_reset_target - issues target Reset - * @ha: Pointer to host adapter structure. - * @db_entry: Pointer to device database entry - * @un_entry: Pointer to lun entry structure - * - * This routine performs a TARGET RESET on the specified target. - * The caller must ensure that the ddb_entry pointers - * are valid before calling this routine. - **/ -int qla4xxx_reset_target(struct scsi_qla_host *ha, - struct ddb_entry *ddb_entry) -{ - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - int status = QLA_SUCCESS; - - DEBUG2(printk("scsi%ld:%d: target reset issued\n", ha->host_no, - ddb_entry->os_target_id)); - - /* - * Send target reset command to ISP, so that the ISP will return all - * outstanding requests with RESET status - */ - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - mbox_cmd[0] = MBOX_CMD_TARGET_WARM_RESET; - mbox_cmd[1] = ddb_entry->fw_ddb_index; - mbox_cmd[5] = 0x01; /* Immediate Command Enable */ - - qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], - &mbox_sts[0]); - if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE && - mbox_sts[0] != MBOX_STS_COMMAND_ERROR) - status = QLA_ERROR; - - return status; -} int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr, uint32_t offset, uint32_t len) @@ -782,8 +851,8 @@ int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr, * qla4xxx_get_fw_version - gets firmware version * @ha: Pointer to host adapter structure. * - * Retrieves the firmware version on HBA. In QLA4010, mailboxes 2 & 3 may - * hold an address for data. Make sure that we write 0 to those mailboxes, + * Retrieves the firmware version on HBA. In QLA4010, mailboxes 2 & 3 may + * hold an address for data. Make sure that we write 0 to those mailboxes, * if unused. **/ int qla4xxx_get_fw_version(struct scsi_qla_host * ha) @@ -835,7 +904,7 @@ static int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, return QLA_SUCCESS; } -static int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t *ddb_index) +int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t *ddb_index) { uint32_t mbox_cmd[MBOX_REG_COUNT]; uint32_t mbox_sts[MBOX_REG_COUNT]; @@ -889,14 +958,14 @@ int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port) if (ret_val != QLA_SUCCESS) goto qla4xxx_send_tgts_exit; - memset(fw_ddb_entry->iscsi_alias, 0, + memset((void *)fw_ddb_entry->iscsi_alias, 0, sizeof(fw_ddb_entry->iscsi_alias)); - memset(fw_ddb_entry->iscsi_name, 0, + memset((void *)fw_ddb_entry->iscsi_name, 0, sizeof(fw_ddb_entry->iscsi_name)); - memset(fw_ddb_entry->ip_addr, 0, sizeof(fw_ddb_entry->ip_addr)); - memset(fw_ddb_entry->tgt_addr, 0, + memset((void *)fw_ddb_entry->ip_addr, 0, sizeof(fw_ddb_entry->ip_addr)); + memset((void *)fw_ddb_entry->tgt_addr, 0, sizeof(fw_ddb_entry->tgt_addr)); fw_ddb_entry->options = (DDB_OPT_DISC_SESSION | DDB_OPT_TARGET); diff --git a/drivers/scsi/qla4xxx/ql4_nvram.c b/drivers/scsi/qla4xxx/ql4_nvram.c index 7fe0482..67cfd0a 100644 --- a/drivers/scsi/qla4xxx/ql4_nvram.c +++ b/drivers/scsi/qla4xxx/ql4_nvram.c @@ -6,6 +6,7 @@ */ #include "ql4_def.h" +#include "ql4_version.h" #include "ql4_glbl.h" #include "ql4_dbg.h" #include "ql4_inline.h" diff --git a/drivers/scsi/qla4xxx/ql4_nvram.h b/drivers/scsi/qla4xxx/ql4_nvram.h index b47b4fc..08e2aed 100644 --- a/drivers/scsi/qla4xxx/ql4_nvram.h +++ b/drivers/scsi/qla4xxx/ql4_nvram.h @@ -134,7 +134,9 @@ struct eeprom_data { u16 phyConfig; /* x36 */ #define PHY_CONFIG_PHY_ADDR_MASK 0x1f #define PHY_CONFIG_ENABLE_FW_MANAGEMENT_MASK 0x20 - u16 reserved_56; /* x38 */ + u16 topcat; /* x38 */ +#define TOPCAT_PRESENT 0x0100 +#define TOPCAT_MASK 0xFF00 #define EEPROM_UNUSED_1_SIZE 2 u8 unused_1[EEPROM_UNUSED_1_SIZE]; /* x3A */ diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 4255b36..a62188b 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -1,6 +1,6 @@ /* * QLogic iSCSI HBA Driver - * Copyright (c) 2003-2006 QLogic Corporation + * Copyright (c) 2003-2006 QLogic Corporation * * See LICENSE.qla4xxx for copyright and licensing details. */ @@ -9,6 +9,7 @@ #include #include +#include #include "ql4_def.h" #include "ql4_version.h" #include "ql4_glbl.h" @@ -18,7 +19,18 @@ /* * Driver version */ -static char qla4xxx_version_str[40]; +char qla4xxx_version_str[40]; +EXPORT_SYMBOL_GPL(qla4xxx_version_str); + +/* + * List of host adapters + */ +struct klist qla4xxx_hostlist; + +struct klist *qla4xxx_hostlist_ptr = &qla4xxx_hostlist; +EXPORT_SYMBOL_GPL(qla4xxx_hostlist_ptr); + +static atomic_t qla4xxx_hba_count; /* * SRB allocation cache @@ -38,16 +50,13 @@ MODULE_PARM_DESC(ql4xdontresethba, " default it will reset hba :0" " set to 1 to avoid resetting HBA"); -int ql4xextended_error_logging = 0; /* 0 = off, 1 = log errors */ -module_param(ql4xextended_error_logging, int, S_IRUGO | S_IRUSR); -MODULE_PARM_DESC(ql4xextended_error_logging, +int extended_error_logging = 0; /* 0 = off, 1 = log errors */ +module_param(extended_error_logging, int, S_IRUGO | S_IRUSR); +MODULE_PARM_DESC(extended_error_logging, "Option to enable extended error logging, " "Default is 0 - no logging, 1 - debug logging"); int ql4_mod_unload = 0; - -#define QL4_DEF_QDEPTH 32 - /* * SCSI host template entry points */ @@ -73,12 +82,9 @@ static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session); static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, void (*done) (struct scsi_cmnd *)); static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd); -static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd); static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd); static int qla4xxx_slave_alloc(struct scsi_device *device); static int qla4xxx_slave_configure(struct scsi_device *device); -static void qla4xxx_slave_destroy(struct scsi_device *sdev); -static void qla4xxx_scan_start(struct Scsi_Host *shost); static struct scsi_host_template qla4xxx_driver_template = { .module = THIS_MODULE, @@ -87,15 +93,10 @@ static struct scsi_host_template qla4xxx_driver_template = { .queuecommand = qla4xxx_queuecommand, .eh_device_reset_handler = qla4xxx_eh_device_reset, - .eh_target_reset_handler = qla4xxx_eh_target_reset, .eh_host_reset_handler = qla4xxx_eh_host_reset, .slave_configure = qla4xxx_slave_configure, .slave_alloc = qla4xxx_slave_alloc, - .slave_destroy = qla4xxx_slave_destroy, - - .scan_finished = iscsi_scan_finished, - .scan_start = qla4xxx_scan_start, .this_id = -1, .cmd_per_lun = 3, @@ -108,13 +109,10 @@ static struct scsi_host_template qla4xxx_driver_template = { static struct iscsi_transport qla4xxx_iscsi_transport = { .owner = THIS_MODULE, .name = DRIVER_NAME, - .caps = CAP_FW_DB | CAP_SENDTARGETS_OFFLOAD | - CAP_DATA_PATH_OFFLOAD, - .param_mask = ISCSI_CONN_PORT | ISCSI_CONN_ADDRESS | - ISCSI_TARGET_NAME | ISCSI_TPGT, - .host_param_mask = ISCSI_HOST_HWADDRESS | - ISCSI_HOST_IPADDRESS | - ISCSI_HOST_INITIATOR_NAME, + .param_mask = ISCSI_CONN_PORT | + ISCSI_CONN_ADDRESS | + ISCSI_TARGET_NAME | + ISCSI_TPGT, .tgt_dscvr = qla4xxx_tgt_dscvr, .get_conn_param = qla4xxx_conn_get_param, .get_session_param = qla4xxx_sess_get_param, @@ -129,19 +127,16 @@ static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session) struct ddb_entry *ddb_entry = session->dd_data; struct scsi_qla_host *ha = ddb_entry->ha; - if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) { - atomic_set(&ddb_entry->state, DDB_STATE_DEAD); + atomic_set(&ddb_entry->state, DDB_STATE_DEAD); - DEBUG2(printk("scsi%ld: %s: index [%d] port down retry count " - "of (%d) secs exhausted, marking device DEAD.\n", - ha->host_no, __func__, ddb_entry->fw_ddb_index, - ha->port_down_retry_count)); + dev_info(&ha->pdev->dev, "%s: ddb[%d] os[%d] marked DEAD" + " - retry count of (%d)\n", __func__, + ddb_entry->fw_ddb_index, ddb_entry->os_target_id, + ha->port_down_retry_count); - DEBUG2(printk("scsi%ld: %s: scheduling dpc routine - dpc " - "flags = 0x%lx\n", - ha->host_no, __func__, ha->dpc_flags)); - queue_work(ha->dpc_thread, &ha->dpc_work); - } + DEBUG2(printk("scsi%ld: %s: scheduling dpc routine - dpc flags = " + "0x%lx\n", ha->host_no, __func__, ha->dpc_flags)); + queue_work(ha->dpc_thread, &ha->dpc_work); } static int qla4xxx_host_get_param(struct Scsi_Host *shost, @@ -151,16 +146,13 @@ static int qla4xxx_host_get_param(struct Scsi_Host *shost, int len; switch (param) { - case ISCSI_HOST_PARAM_HWADDRESS: - len = sysfs_format_mac(buf, ha->my_mac, MAC_ADDR_LEN); - break; case ISCSI_HOST_PARAM_IPADDRESS: - len = sprintf(buf, "%d.%d.%d.%d\n", ha->ip_address[0], - ha->ip_address[1], ha->ip_address[2], - ha->ip_address[3]); + len = sprintf(buf, "%d.%d.%d.%d", ha->ip_address[0], + ha->ip_address[1], ha->ip_address[2], + ha->ip_address[3]); break; case ISCSI_HOST_PARAM_INITIATOR_NAME: - len = sprintf(buf, "%s\n", ha->name_string); + len = sprintf(buf, "%s", ha->name_string); break; default: return -ENOSYS; @@ -169,6 +161,38 @@ static int qla4xxx_host_get_param(struct Scsi_Host *shost, return len; } +int qla4xxx_conn_start(struct iscsi_cls_conn *conn) +{ + struct iscsi_cls_session *session; + struct ddb_entry *ddb_entry; + + session = iscsi_dev_to_session(conn->dev.parent); + ddb_entry = session->dd_data; + + DEBUG2(printk("scsi%ld: %s: index [%d] starting conn\n", + ddb_entry->ha->host_no, __func__, + ddb_entry->fw_ddb_index)); + iscsi_unblock_session(session); + return 0; +} + +static void qla4xxx_conn_stop(struct iscsi_cls_conn *conn, int flag) +{ + struct iscsi_cls_session *session; + struct ddb_entry *ddb_entry; + + session = iscsi_dev_to_session(conn->dev.parent); + ddb_entry = session->dd_data; + + DEBUG2(printk("scsi%ld: %s: index [%d] stopping conn\n", + ddb_entry->ha->host_no, __func__, + ddb_entry->fw_ddb_index)); + if (flag == STOP_CONN_RECOVER) + iscsi_block_session(session); + else + printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag); +} + static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess, enum iscsi_param param, char *buf) { @@ -177,11 +201,11 @@ static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess, switch (param) { case ISCSI_PARAM_TARGET_NAME: - len = snprintf(buf, PAGE_SIZE - 1, "%s\n", - ddb_entry->iscsi_name); + len = snprintf(buf, PAGE_SIZE - 1, "%s", + ddb_entry->iscsi_name); break; case ISCSI_PARAM_TPGT: - len = sprintf(buf, "%u\n", ddb_entry->tpgt); + len = sprintf(buf, "%u", ddb_entry->tpgt); break; default: return -ENOSYS; @@ -202,12 +226,12 @@ static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn, switch (param) { case ISCSI_PARAM_CONN_PORT: - len = sprintf(buf, "%hu\n", ddb_entry->port); + len = sprintf(buf, "%u", (uint32_t)ddb_entry->port); break; case ISCSI_PARAM_CONN_ADDRESS: /* TODO: what are the ipv6 bits */ - len = sprintf(buf, "%u.%u.%u.%u\n", - NIPQUAD(ddb_entry->ip_addr)); + len = sprintf(buf, "%u.%u.%u.%u", + NIPQUAD(ddb_entry->ip_addr)); break; default: return -ENOSYS; @@ -257,17 +281,15 @@ void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry) return; if (ddb_entry->conn) { - atomic_set(&ddb_entry->state, DDB_STATE_DEAD); iscsi_remove_session(ddb_entry->sess); } iscsi_free_session(ddb_entry->sess); } -int qla4xxx_add_sess(struct ddb_entry *ddb_entry) +int qla4xxx_add_sess(struct ddb_entry *ddb_entry, int scan) { int err; - ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count; err = iscsi_add_session(ddb_entry->sess, ddb_entry->fw_ddb_index); if (err) { DEBUG2(printk(KERN_ERR "Could not add session.\n")); @@ -281,7 +303,11 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry) return -ENOMEM; } - /* finally ready to go */ + ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count; + if (scan) + scsi_scan_target(&ddb_entry->sess->dev, 0, + ddb_entry->sess->target_id, + SCAN_WILD_CARD, 0); iscsi_unblock_session(ddb_entry->sess); return 0; } @@ -292,7 +318,7 @@ struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha) struct iscsi_cls_session *sess; sess = iscsi_alloc_session(ha->host, &qla4xxx_iscsi_transport, - sizeof(struct ddb_entry)); + sizeof(struct ddb_entry)); if (!sess) return NULL; @@ -303,18 +329,6 @@ struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha) return ddb_entry; } -static void qla4xxx_scan_start(struct Scsi_Host *shost) -{ - struct scsi_qla_host *ha = shost_priv(shost); - struct ddb_entry *ddb_entry, *ddbtemp; - - /* finish setup of sessions that were already setup in firmware */ - list_for_each_entry_safe(ddb_entry, ddbtemp, &ha->ddb_list, list) { - if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) - qla4xxx_add_sess(ddb_entry); - } -} - /* * Timer routines */ @@ -323,7 +337,7 @@ static void qla4xxx_start_timer(struct scsi_qla_host *ha, void *func, unsigned long interval) { DEBUG(printk("scsi: %s: Starting timer thread for adapter %d\n", - __func__, ha->host->host_no)); + __func__, ha->host->host_no)); init_timer(&ha->timer); ha->timer.expires = jiffies + interval * HZ; ha->timer.data = (unsigned long)ha; @@ -349,11 +363,11 @@ void qla4xxx_mark_device_missing(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry) { atomic_set(&ddb_entry->state, DDB_STATE_MISSING); - DEBUG3(printk("scsi%d:%d:%d: index [%d] marked MISSING\n", - ha->host_no, ddb_entry->bus, ddb_entry->target, - ddb_entry->fw_ddb_index)); - iscsi_block_session(ddb_entry->sess); - iscsi_conn_error(ddb_entry->conn, ISCSI_ERR_CONN_FAILED); + + dev_info(&ha->pdev->dev, "%s: ddb[%d] os[%d] marked MISSING\n", + __func__, ddb_entry->fw_ddb_index, ddb_entry->os_target_id); + + qla4xxx_conn_stop(ddb_entry->conn, STOP_CONN_RECOVER); } static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha, @@ -393,10 +407,10 @@ void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb) { struct scsi_cmnd *cmd = srb->cmd; - qla4xxx_srb_free_dma(ha, srb); - - mempool_free(srb, ha->srb_mempool); - + if (!(srb->flags & SRB_SCSI_PASSTHRU)) { + qla4xxx_srb_free_dma(ha, srb); + mempool_free(srb, ha->srb_mempool); + } cmd->scsi_done(cmd); } @@ -404,7 +418,7 @@ void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb) * qla4xxx_queuecommand - scsi layer issues scsi command to driver. * @cmd: Pointer to Linux's SCSI command structure * @done_fn: Function that the driver calls to notify the SCSI mid-layer - * that the command has been processed. + * that the command has been processed. * * Remarks: * This routine is invoked by Linux to send a SCSI command to the driver. @@ -419,30 +433,20 @@ static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, { struct scsi_qla_host *ha = to_qla_host(cmd->device->host); struct ddb_entry *ddb_entry = cmd->device->hostdata; - struct iscsi_cls_session *sess = ddb_entry->sess; struct srb *srb; int rval; - if (!sess) { - cmd->result = DID_IMM_RETRY << 16; - goto qc_fail_command; - } - - rval = iscsi_session_chkready(sess); - if (rval) { - cmd->result = rval; - goto qc_fail_command; - } - if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) { if (atomic_read(&ddb_entry->state) == DDB_STATE_DEAD) { cmd->result = DID_NO_CONNECT << 16; goto qc_fail_command; } - return SCSI_MLQUEUE_TARGET_BUSY; + goto qc_host_busy; } - if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) + if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || + test_bit(DPC_RESET_HA, &ha->dpc_flags) || + test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags)) goto qc_host_busy; spin_unlock_irq(ha->host->host_lock); @@ -596,7 +600,7 @@ static void qla4xxx_timer(struct scsi_qla_host *ha) if (atomic_read(&ddb_entry->retry_relogin_timer) != INVALID_ENTRY) { if (atomic_read(&ddb_entry->retry_relogin_timer) - == 0) { + == 0) { atomic_set(&ddb_entry-> retry_relogin_timer, INVALID_ENTRY); @@ -669,7 +673,7 @@ static void qla4xxx_timer(struct scsi_qla_host *ha) test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) || test_bit(DPC_AEN, &ha->dpc_flags)) && - ha->dpc_thread) { + ha->dpc_thread) { DEBUG2(printk("scsi%ld: %s: scheduling dpc routine" " - dpc flags = 0x%lx\n", ha->host_no, __func__, ha->dpc_flags)); @@ -694,7 +698,6 @@ static int qla4xxx_cmd_wait(struct scsi_qla_host *ha) uint32_t index = 0; int stat = QLA_SUCCESS; unsigned long flags; - struct scsi_cmnd *cmd; int wait_cnt = WAIT_CMD_TOV; /* * Initialized for 30 seconds as we * expect all commands to retuned @@ -704,15 +707,14 @@ static int qla4xxx_cmd_wait(struct scsi_qla_host *ha) while (wait_cnt) { spin_lock_irqsave(&ha->hardware_lock, flags); /* Find a command that hasn't completed. */ - for (index = 0; index < ha->host->can_queue; index++) { - cmd = scsi_host_find_tag(ha->host, index); - if (cmd != NULL) + for (index = 1; index < MAX_SRBS; index++) { + if (ha->active_srb_array[index] != NULL) break; } spin_unlock_irqrestore(&ha->hardware_lock, flags); /* If No Commands are pending, wait is complete */ - if (index == ha->host->can_queue) { + if (index == MAX_SRBS) { break; } @@ -738,7 +740,6 @@ void qla4xxx_hw_reset(struct scsi_qla_host *ha) DEBUG2(printk(KERN_ERR "scsi%ld: %s\n", ha->host_no, __func__)); spin_lock_irqsave(&ha->hardware_lock, flags); - /* * If the SCSI Reset Interrupt bit is set, clear it. * Otherwise, the Soft Reset won't work. @@ -865,9 +866,9 @@ static void qla4xxx_flush_active_srbs(struct scsi_qla_host *ha) unsigned long flags; spin_lock_irqsave(&ha->hardware_lock, flags); - for (i = 0; i < ha->host->can_queue; i++) { - srb = qla4xxx_del_from_active_array(ha, i); - if (srb != NULL) { + for (i = 1; i < MAX_SRBS; i++) { + if ((srb = ha->active_srb_array[i]) != NULL) { + qla4xxx_del_from_active_array(ha, i); srb->cmd->result = DID_RESET << 16; qla4xxx_srb_compl(ha, srb); } @@ -879,19 +880,13 @@ static void qla4xxx_flush_active_srbs(struct scsi_qla_host *ha) /** * qla4xxx_recover_adapter - recovers adapter after a fatal error * @ha: Pointer to host adapter structure. - * @renew_ddb_list: Indicates what to do with the adapter's ddb list - * - * renew_ddb_list value can be 0=preserve ddb list, 1=destroy and rebuild - * ddb list. **/ -static int qla4xxx_recover_adapter(struct scsi_qla_host *ha, - uint8_t renew_ddb_list) +static int qla4xxx_recover_adapter(struct scsi_qla_host *ha) { int status; /* Stall incoming I/O until we are done */ clear_bit(AF_ONLINE, &ha->flags); - DEBUG2(printk("scsi%ld: %s calling qla4xxx_cmd_wait\n", ha->host_no, __func__)); @@ -909,7 +904,7 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha, * returns with ISP interrupts enabled. */ if (status == QLA_SUCCESS) { - DEBUG2(printk("scsi%ld: %s - Performing soft reset..\n", + DEBUG2(printk(KERN_ERR "scsi%ld: %s - Performing soft reset..\n", ha->host_no, __func__)); qla4xxx_flush_active_srbs(ha); if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) @@ -929,7 +924,7 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha, /* If successful, AF_ONLINE flag set in * qla4xxx_initialize_adapter */ - status = qla4xxx_initialize_adapter(ha, renew_ddb_list); + status = qla4xxx_initialize_adapter(ha, PRESERVE_DDB_LIST); } /* Failed adapter initialization? @@ -990,7 +985,7 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha, * @data: in our case pointer to adapter structure * * This routine is a task that is schedule by the interrupt handler - * to perform the background processing for interrupts. We put it + * to perform the background processing for interrupts. We put it * on a task queue that is consumed whenever the scheduler runs; that's * so you can do anything (i.e. put the process to sleep etc). In fact, * the mid-level tries to sleep when it reaches the driver threshold @@ -1004,7 +999,8 @@ static void qla4xxx_do_dpc(struct work_struct *work) int status = QLA_ERROR; DEBUG2(printk("scsi%ld: %s: DPC handler waking up." - "flags = 0x%08lx, dpc_flags = 0x%08lx ctrl_stat = 0x%08x\n", + "ha->flags=0x%08lx ha->dpc_flags=0x%08lx" + " ctrl_status=0x%08x\n", ha->host_no, __func__, ha->flags, ha->dpc_flags, readw(&ha->reg->ctrl_status))); @@ -1017,8 +1013,8 @@ static void qla4xxx_do_dpc(struct work_struct *work) test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags)) { if (test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) || - test_bit(DPC_RESET_HA, &ha->dpc_flags)) - qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST); + test_bit(DPC_RESET_HA, &ha->dpc_flags)) + qla4xxx_recover_adapter(ha); if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { uint8_t wait_time = RESET_INTR_TOV; @@ -1036,7 +1032,7 @@ static void qla4xxx_do_dpc(struct work_struct *work) qla4xxx_flush_active_srbs(ha); if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) { qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); - status = qla4xxx_initialize_adapter(ha, + status = qla4xxx_initialize_adapter(ha, PRESERVE_DDB_LIST); } clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags); @@ -1070,8 +1066,8 @@ static void qla4xxx_do_dpc(struct work_struct *work) */ if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) { printk(KERN_WARNING "scsi%ld: %s: " - "need to reset hba\n", - ha->host_no, __func__); + "need to reset hba\n", + ha->host_no, __func__); break; } } @@ -1110,7 +1106,6 @@ static void qla4xxx_free_adapter(struct scsi_qla_host *ha) qla4xxx_mem_free(ha); pci_disable_device(ha->pdev); - } /*** @@ -1147,7 +1142,6 @@ static int qla4xxx_iospace_config(struct scsi_qla_host *ha) if (!(mmio_flags & IORESOURCE_MEM)) { dev_err(&ha->pdev->dev, "region #0 not an MMIO resource, aborting\n"); - goto iospace_error_exit; } if (mmio_len < MIN_IOBASE_LEN) { @@ -1179,6 +1173,14 @@ iospace_error_exit: return -ENOMEM; } +static void ql4_get_aen_log(struct scsi_qla_host *ha, struct ql4_aen_log *aenl) +{ + if (aenl) { + memcpy(aenl, &ha->aen_log, sizeof (ha->aen_log)); + ha->aen_log.count = 0; + } +} + /** * qla4xxx_probe_adapter - callback function to probe HBA * @pdev: pointer to pci_dev structure @@ -1194,6 +1196,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, int ret = -ENODEV, status; struct Scsi_Host *host; struct scsi_qla_host *ha; + struct ddb_entry *ddb_entry, *ddbtemp; uint8_t init_retry_count = 0; char buf[34]; @@ -1211,18 +1214,22 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, ha = (struct scsi_qla_host *) host->hostdata; memset(ha, 0, sizeof(*ha)); - /* Save the information from PCI BIOS. */ + /* Save the information from PCI BIOS. */ ha->pdev = pdev; ha->host = host; ha->host_no = host->host_no; + ha->ql4mbx = qla4xxx_mailbox_command; + ha->ql4cmd = qla4xxx_send_command_to_isp; + ha->ql4getaenlog = ql4_get_aen_log; + /* Configure PCI I/O space. */ ret = qla4xxx_iospace_config(ha); if (ret) goto probe_failed; dev_info(&ha->pdev->dev, "Found an ISP%04x, irq %d, iobase 0x%p\n", - pdev->device, pdev->irq, ha->reg); + pdev->device, pdev->irq, ha->reg); qla4xxx_config_dma_addressing(ha); @@ -1233,11 +1240,12 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, mutex_init(&ha->mbox_sem); spin_lock_init(&ha->hardware_lock); + spin_lock_init(&ha->list_lock); /* Allocate dma buffers */ if (qla4xxx_mem_alloc(ha)) { dev_warn(&ha->pdev->dev, - "[ERROR] Failed to allocate memory for adapter\n"); + "[ERROR] Failed to allocate memory for adapter\n"); ret = -ENOMEM; goto probe_failed; @@ -1250,8 +1258,8 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, */ status = qla4xxx_initialize_adapter(ha, REBUILD_DDB_LIST); while (status == QLA_ERROR && init_retry_count++ < MAX_INIT_RETRIES) { - DEBUG2(printk("scsi: %s: retrying adapter initialization " - "(%d)\n", __func__, init_retry_count)); + DEBUG2(printk(KERN_ERR "scsi%ld: %s: retrying adapter initialization " + "(%d)\n", ha->host_no, __func__, init_retry_count)); qla4xxx_soft_reset(ha); status = qla4xxx_initialize_adapter(ha, REBUILD_DDB_LIST); } @@ -1267,15 +1275,9 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, host->max_lun = MAX_LUNS - 1; host->max_id = MAX_TARGETS; host->max_cmd_len = IOCB_MAX_CDB_LEN; - host->can_queue = MAX_SRBS ; + host->can_queue = REQUEST_QUEUE_DEPTH + 128; host->transportt = qla4xxx_scsi_transport; - ret = scsi_init_shared_tag_map(host, MAX_SRBS); - if (ret) { - dev_warn(&ha->pdev->dev, "scsi_init_shared_tag_map failed\n"); - goto probe_failed; - } - /* Startup the kernel thread for this host adapter. */ DEBUG2(printk("scsi: %s: Starting kernel thread for " "qla4xxx_dpc\n", __func__)); @@ -1287,9 +1289,8 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, goto probe_failed; } INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc); - ret = request_irq(pdev->irq, qla4xxx_intr_handler, - IRQF_DISABLED | IRQF_SHARED, "qla4xxx", ha); + IRQF_DISABLED | IRQF_SHARED, "qla4xxx", ha); if (ret) { dev_warn(&ha->pdev->dev, "Failed to reserve interrupt %d" " already in use.\n", pdev->irq); @@ -1312,15 +1313,39 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, if (ret) goto probe_failed; + /* Update transport device information for all devices. */ + list_for_each_entry_safe(ddb_entry, ddbtemp, &ha->ddb_list, list) { + + if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) + set_bit(DF_SCAN_ISSUED, &ddb_entry->flags); + + if (qla4xxx_add_sess(ddb_entry, + test_bit(DF_SCAN_ISSUED, &ddb_entry->flags))) + goto remove_host; + if (!test_bit(DF_SCAN_ISSUED, &ddb_entry->flags)) + qla4xxx_mark_device_missing(ha, ddb_entry); + } + printk(KERN_INFO " QLogic iSCSI HBA Driver version: %s\n" - " QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\n", - qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev), + " QLogic ISP%04x @ %s, pdev = %p host#=%ld, fw=%02d.%02d.%02d.%02d\n", + qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev), pdev, ha->host_no, ha->firmware_version[0], ha->firmware_version[1], ha->patch_number, ha->build_number); - scsi_scan_host(host); + + /* Insert new entry into the list of adapters. */ + klist_add_tail(&ha->node, &qla4xxx_hostlist); + ha->instance = atomic_inc_return(&qla4xxx_hba_count) - 1; + + DEBUG2(printk("qla4xxx: listhead=%p, done adding ha=%p i=%d\n", + &qla4xxx_hostlist, &ha->node, ha->instance)); + return 0; +remove_host: + qla4xxx_free_ddb_list(ha); + scsi_remove_host(host); + probe_failed: qla4xxx_free_adapter(ha); scsi_host_put(ha->host); @@ -1346,6 +1371,9 @@ static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev) while (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) ssleep(1); + klist_remove(&ha->node); + atomic_dec(&qla4xxx_hba_count); + /* remove devs from iscsi_sessions to scsi_devices */ qla4xxx_free_ddb_list(ha); @@ -1374,7 +1402,7 @@ static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha) if (pci_set_consistent_dma_mask(ha->pdev, DMA_64BIT_MASK)) { dev_dbg(&ha->pdev->dev, "Failed to set 64 bit PCI consistent mask; " - "using 32 bit.\n"); + "using 32 bit.\n"); retval = pci_set_consistent_dma_mask(ha->pdev, DMA_32BIT_MASK); } @@ -1385,23 +1413,22 @@ static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha) static int qla4xxx_slave_alloc(struct scsi_device *sdev) { struct iscsi_cls_session *sess = starget_to_session(sdev->sdev_target); - struct ddb_entry *ddb = sess->dd_data; - sdev->hostdata = ddb; - sdev->tagged_supported = 1; - scsi_activate_tcq(sdev, QL4_DEF_QDEPTH); - return 0; + if (sess) { + sdev->hostdata = sess->dd_data; + return 0; + } + return FAILED; } static int qla4xxx_slave_configure(struct scsi_device *sdev) { - sdev->tagged_supported = 1; - return 0; -} + if (sdev->tagged_supported) + scsi_activate_tcq(sdev, 32); + else + scsi_deactivate_tcq(sdev, 32); -static void qla4xxx_slave_destroy(struct scsi_device *sdev) -{ - scsi_deactivate_tcq(sdev, 1); + return 0; } /** @@ -1414,12 +1441,14 @@ static void qla4xxx_slave_destroy(struct scsi_device *sdev) struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index) { struct srb *srb = NULL; - struct scsi_cmnd *cmd; - if (!(cmd = scsi_host_find_tag(ha->host, index))) + /* validate handle and remove from active array */ + if (index >= MAX_SRBS) return srb; - if (!(srb = (struct srb *)cmd->host_scribble)) + srb = ha->active_srb_array[index]; + ha->active_srb_array[index] = NULL; + if (!srb) return srb; /* update counters */ @@ -1467,24 +1496,18 @@ static int qla4xxx_eh_wait_on_command(struct scsi_qla_host *ha, **/ static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha) { - unsigned long wait_online; - - wait_online = jiffies + (30 * HZ); - while (time_before(jiffies, wait_online)) { + unsigned long wait_online = 60; + while (wait_online--) { if (adapter_up(ha)) return QLA_SUCCESS; - else if (ha->retry_reset_ha_cnt == 0) - return QLA_ERROR; - - msleep(2000); + ssleep(2); } - return QLA_ERROR; } /** - * qla4xxx_eh_wait_for_commands - wait for active cmds to finish. + * qla4xxx_eh_wait_for_active_target_commands - wait for active cmds to finish. * @ha: pointer to to HBA * @t: target id * @l: lun id @@ -1492,26 +1515,33 @@ static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha) * This function waits for all outstanding commands to a lun to complete. It * returns 0 if all pending commands are returned and 1 otherwise. **/ -static int qla4xxx_eh_wait_for_commands(struct scsi_qla_host *ha, - struct scsi_target *stgt, - struct scsi_device *sdev) +static int qla4xxx_eh_wait_for_active_target_commands(struct scsi_qla_host *ha, + int t, int l) { int cnt; - int status = 0; + int status; + struct srb *sp; struct scsi_cmnd *cmd; /* - * Waiting for all commands for the designated target or dev - * in the active array + * Waiting for all commands for the designated target in the active + * array */ - for (cnt = 0; cnt < ha->host->can_queue; cnt++) { - cmd = scsi_host_find_tag(ha->host, cnt); - if (cmd && stgt == scsi_target(cmd->device) && - (!sdev || sdev == cmd->device)) { - if (!qla4xxx_eh_wait_on_command(ha, cmd)) { - status++; - break; + status = 0; + for (cnt = 1; cnt < MAX_SRBS; cnt++) { + spin_lock(&ha->hardware_lock); + sp = ha->active_srb_array[cnt]; + if (sp) { + cmd = sp->cmd; + spin_unlock(&ha->hardware_lock); + if (cmd->device->id == t && cmd->device->lun == l) { + if (!qla4xxx_eh_wait_on_command(ha, cmd)) { + status++; + break; + } } + } else { + spin_unlock(&ha->hardware_lock); } } return status; @@ -1528,47 +1558,49 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd) { struct scsi_qla_host *ha = to_qla_host(cmd->device->host); struct ddb_entry *ddb_entry = cmd->device->hostdata; - struct srb *sp; int ret = FAILED, stat; - sp = (struct srb *) cmd->SCp.ptr; - if (!sp || !ddb_entry) + if (!ddb_entry) return ret; dev_info(&ha->pdev->dev, - "scsi%ld:%d:%d:%d: DEVICE RESET ISSUED.\n", ha->host_no, - cmd->device->channel, cmd->device->id, cmd->device->lun); + "scsi%ld:%d:%d:%d: DEVICE RESET ISSUED.\n", ha->host_no, + cmd->device->channel, cmd->device->id, cmd->device->lun); - DEBUG2(printk(KERN_INFO - "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x," - "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no, - cmd, jiffies, cmd->request->timeout / HZ, - ha->dpc_flags, cmd->result, cmd->allowed)); + if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) { + dev_info(&ha->pdev->dev, "%s: HBA OFFLINE: FAILED\n", __func__); + return FAILED; + } - /* FIXME: wait for hba to go online */ stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun); if (stat != QLA_SUCCESS) { dev_info(&ha->pdev->dev, "DEVICE RESET FAILED. %d\n", stat); goto eh_dev_reset_done; } - if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device), - cmd->device)) { - dev_info(&ha->pdev->dev, - "DEVICE RESET FAILED - waiting for " - "commands.\n"); - goto eh_dev_reset_done; + /* + * If we are coming down the EH path, wait for all commands to complete + * for the device. + */ + if (cmd->device->host->shost_state == SHOST_RECOVERY) { + if (qla4xxx_eh_wait_for_active_target_commands(ha, + cmd->device->id, + cmd->device-> + lun)) { + dev_info(&ha->pdev->dev, + "DEVICE RESET FAILED - waiting for " + "commands.\n"); + goto eh_dev_reset_done; + } } - - /* Send marker. */ - if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun, - MM_LUN_RESET) != QLA_SUCCESS) + if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun) + != QLA_SUCCESS) goto eh_dev_reset_done; dev_info(&ha->pdev->dev, - "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n", - ha->host_no, cmd->device->channel, cmd->device->id, - cmd->device->lun); + "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n", + ha->host_no, cmd->device->channel, cmd->device->id, + cmd->device->lun); ret = SUCCESS; @@ -1578,59 +1610,6 @@ eh_dev_reset_done: } /** - * qla4xxx_eh_target_reset - callback for target reset. - * @cmd: Pointer to Linux's SCSI command structure - * - * This routine is called by the Linux OS to reset the target. - **/ -static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd) -{ - struct scsi_qla_host *ha = to_qla_host(cmd->device->host); - struct ddb_entry *ddb_entry = cmd->device->hostdata; - int stat; - - if (!ddb_entry) - return FAILED; - - starget_printk(KERN_INFO, scsi_target(cmd->device), - "WARM TARGET RESET ISSUED.\n"); - - DEBUG2(printk(KERN_INFO - "scsi%ld: TARGET_DEVICE_RESET cmd=%p jiffies = 0x%lx, " - "to=%x,dpc_flags=%lx, status=%x allowed=%d\n", - ha->host_no, cmd, jiffies, cmd->request->timeout / HZ, - ha->dpc_flags, cmd->result, cmd->allowed)); - - stat = qla4xxx_reset_target(ha, ddb_entry); - if (stat != QLA_SUCCESS) { - starget_printk(KERN_INFO, scsi_target(cmd->device), - "WARM TARGET RESET FAILED.\n"); - return FAILED; - } - - if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device), - NULL)) { - starget_printk(KERN_INFO, scsi_target(cmd->device), - "WARM TARGET DEVICE RESET FAILED - " - "waiting for commands.\n"); - return FAILED; - } - - /* Send marker. */ - if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun, - MM_TGT_WARM_RESET) != QLA_SUCCESS) { - starget_printk(KERN_INFO, scsi_target(cmd->device), - "WARM TARGET DEVICE RESET FAILED - " - "marker iocb failed.\n"); - return FAILED; - } - - starget_printk(KERN_INFO, scsi_target(cmd->device), - "WARM TARGET RESET SUCCEEDED.\n"); - return SUCCESS; -} - -/** * qla4xxx_eh_host_reset - kernel callback * @cmd: Pointer to Linux's SCSI command structure * @@ -1644,27 +1623,19 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd) ha = (struct scsi_qla_host *) cmd->device->host->hostdata; - dev_info(&ha->pdev->dev, - "scsi(%ld:%d:%d:%d): ADAPTER RESET ISSUED.\n", ha->host_no, - cmd->device->channel, cmd->device->id, cmd->device->lun); + dev_info(&ha->pdev->dev, "%s: ADAPTER RESET ISSUED.\n", __func__); if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) { - DEBUG2(printk("scsi%ld:%d: %s: Unable to reset host. Adapter " - "DEAD.\n", ha->host_no, cmd->device->channel, - __func__)); - + dev_info(&ha->pdev->dev, "%s: HBA OFFLINE: FAILED\n", __func__); return FAILED; } - /* make sure the dpc thread is stopped while we reset the hba */ - clear_bit(AF_ONLINE, &ha->flags); - flush_workqueue(ha->dpc_thread); - - if (qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST) == QLA_SUCCESS) + if (qla4xxx_recover_adapter(ha) == QLA_SUCCESS) { return_status = SUCCESS; + } dev_info(&ha->pdev->dev, "HOST RESET %s.\n", - return_status == FAILED ? "FAILED" : "SUCCEDED"); + return_status == FAILED ? "FAILED" : "SUCCEDED"); return return_status; } @@ -1704,9 +1675,11 @@ static int __init qla4xxx_module_init(void) { int ret; + atomic_set(&qla4xxx_hba_count, 0); + klist_init(&qla4xxx_hostlist, NULL, NULL); /* Allocate cache for SRBs. */ srb_cachep = kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0, - SLAB_HWCACHE_ALIGN, NULL); + SLAB_HWCACHE_ALIGN, NULL); if (srb_cachep == NULL) { printk(KERN_ERR "%s: Unable to allocate SRB cache..." @@ -1717,7 +1690,7 @@ static int __init qla4xxx_module_init(void) /* Derive version string. */ strcpy(qla4xxx_version_str, QLA4XXX_DRIVER_VERSION); - if (ql4xextended_error_logging) + if (extended_error_logging) strcat(qla4xxx_version_str, "-debug"); qla4xxx_scsi_transport = @@ -1727,13 +1700,13 @@ static int __init qla4xxx_module_init(void) goto release_srb_cache; } + printk(KERN_INFO "QLogic iSCSI HBA Driver\n"); ret = pci_register_driver(&qla4xxx_pci_driver); if (ret) goto unregister_transport; printk(KERN_INFO "QLogic iSCSI HBA Driver\n"); return 0; - unregister_transport: iscsi_unregister_transport(&qla4xxx_iscsi_transport); release_srb_cache: diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h index ab984cb..1cbfcbb 100644 --- a/drivers/scsi/qla4xxx/ql4_version.h +++ b/drivers/scsi/qla4xxx/ql4_version.h @@ -5,5 +5,6 @@ * See LICENSE.qla4xxx for copyright and licensing details. */ -#define QLA4XXX_DRIVER_VERSION "5.01.00-k8" +#define QLA4XXX_DRIVER_VERSION "5.01.00-k8_sles11-01" +