From c18b78ede52d2ac8c664449bccaf36753a3c419b Mon Sep 17 00:00:00 2001 From: Manish Dusane Date: Thu, 7 Mar 2013 05:43:07 -0500 Subject: [SCSI] qla4xxx: Take E-port out of reset before disabling pause frames Problem Description: Disabling pause frames might cause hardware wedging needing a power cycle. This might happen if the Eport is not initialized and is in reset. Solution: Before disabling pause frames ensure that eport is out of reset. Signed-off-by: Manish Dusane Signed-off-by: Vikas Chaudhary Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_83xx.c | 28 ++++++++++++++++++++++++++++ drivers/scsi/qla4xxx/ql4_83xx.h | 10 ++++++++++ 2 files changed, 38 insertions(+) (limited to 'drivers/scsi/qla4xxx') diff --git a/drivers/scsi/qla4xxx/ql4_83xx.c b/drivers/scsi/qla4xxx/ql4_83xx.c index 5d8fe4f75650..d607eb8e24cb 100644 --- a/drivers/scsi/qla4xxx/ql4_83xx.c +++ b/drivers/scsi/qla4xxx/ql4_83xx.c @@ -1629,9 +1629,37 @@ static void __qla4_83xx_disable_pause(struct scsi_qla_host *ha) ql4_printk(KERN_INFO, ha, "Disabled pause frames successfully.\n"); } +/** + * qla4_83xx_eport_init - Initialize EPort. + * @ha: Pointer to host adapter structure. + * + * If EPort hardware is in reset state before disabling pause, there would be + * serious hardware wedging issues. To prevent this perform eport init everytime + * before disabling pause frames. + **/ +static void qla4_83xx_eport_init(struct scsi_qla_host *ha) +{ + /* Clear the 8 registers */ + qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_REG, 0x0); + qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_PORT0, 0x0); + qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_PORT1, 0x0); + qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_PORT2, 0x0); + qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_PORT3, 0x0); + qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_SRE_SHIM, 0x0); + qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_EPG_SHIM, 0x0); + qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_ETHER_PCS, 0x0); + + /* Write any value to Reset Control register */ + qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_CONTROL, 0xFF); + + ql4_printk(KERN_INFO, ha, "EPORT is out of reset.\n"); +} + void qla4_83xx_disable_pause(struct scsi_qla_host *ha) { ha->isp_ops->idc_lock(ha); + /* Before disabling pause frames, ensure that eport is not in reset */ + qla4_83xx_eport_init(ha); qla4_83xx_dump_pause_control_regs(ha); __qla4_83xx_disable_pause(ha); ha->isp_ops->idc_unlock(ha); diff --git a/drivers/scsi/qla4xxx/ql4_83xx.h b/drivers/scsi/qla4xxx/ql4_83xx.h index 6a00f903f2a6..fab237fa32cc 100644 --- a/drivers/scsi/qla4xxx/ql4_83xx.h +++ b/drivers/scsi/qla4xxx/ql4_83xx.h @@ -55,6 +55,16 @@ #define QLA83XX_SET_PAUSE_VAL 0x0 #define QLA83XX_SET_TC_MAX_CELL_VAL 0x03FF03FF +#define QLA83XX_RESET_CONTROL 0x28084E50 +#define QLA83XX_RESET_REG 0x28084E60 +#define QLA83XX_RESET_PORT0 0x28084E70 +#define QLA83XX_RESET_PORT1 0x28084E80 +#define QLA83XX_RESET_PORT2 0x28084E90 +#define QLA83XX_RESET_PORT3 0x28084EA0 +#define QLA83XX_RESET_SRE_SHIM 0x28084EB0 +#define QLA83XX_RESET_EPG_SHIM 0x28084EC0 +#define QLA83XX_RESET_ETHER_PCS 0x28084ED0 + /* qla_83xx_reg_tbl registers */ #define QLA83XX_PEG_HALT_STATUS1 0x34A8 #define QLA83XX_PEG_HALT_STATUS2 0x34AC -- cgit v1.2.3 From 3e788fb16d7f9a909ed45f9f0f331d5cd0283f18 Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Thu, 7 Mar 2013 05:43:08 -0500 Subject: [SCSI] qla4xxx: Boot from SAN fix for ISP83XX Issue: ISP83XX check is missing in function get_fw_boot_info() because of this qla4xxx will not export boot target to sysfs and iscsistart cannot issue login to boot target. Fix: Added check for ISP83XX in function get_fw_boot_info() Signed-off-by: Vikas Chaudhary Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_os.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi/qla4xxx') diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 6142729167f4..1c387e7b2227 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -4005,7 +4005,7 @@ static int get_fw_boot_info(struct scsi_qla_host *ha, uint16_t ddb_index[]) if (val & BIT_7) ddb_index[1] = (val & 0x7f); - } else if (is_qla8022(ha)) { + } else if (is_qla80XX(ha)) { buf = dma_alloc_coherent(&ha->pdev->dev, size, &buf_dma, GFP_KERNEL); if (!buf) { -- cgit v1.2.3 From ebd777dec72991a26af247ab83c8f7f288b28621 Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Thu, 7 Mar 2013 05:43:09 -0500 Subject: [SCSI] qla4xxx: Set graceful reset bit for ISP83XX For ISP83XX set graceful reset bit in IDC_DRV_CTRL if reset is issued by application Signed-off-by: Vikas Chaudhary Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_os.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/scsi/qla4xxx') diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 1c387e7b2227..b3ccb1ad8c02 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -6081,6 +6081,7 @@ static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type) { struct scsi_qla_host *ha = to_qla_host(shost); int rval = QLA_SUCCESS; + uint32_t idc_ctrl; if (ql4xdontresethba) { DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Don't Reset HBA\n", @@ -6111,6 +6112,14 @@ static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type) } recover_adapter: + /* For ISP83XX set graceful reset bit in IDC_DRV_CTRL if + * reset is issued by application */ + if (is_qla8032(ha) && test_bit(DPC_RESET_HA, &ha->dpc_flags)) { + idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL); + qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL, + (idc_ctrl | GRACEFUL_RESET_BIT1)); + } + rval = qla4xxx_recover_adapter(ha); if (rval != QLA_SUCCESS) { DEBUG2(ql4_printk(KERN_INFO, ha, "%s: recover adapter fail\n", -- cgit v1.2.3 From 6cf9412124a4a2166b4d5a6919050f7fdfb82b64 Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Thu, 7 Mar 2013 05:43:10 -0500 Subject: [SCSI] qla4xxx: Fix double reset in case of firmware hung for ISP83XX In case of firmware hung we need to call "mailbox_premature_completion" to complete any pending mbox command as firmware is not alive. Signed-off-by: Vikas Chaudhary Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_os.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers/scsi/qla4xxx') diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index b3ccb1ad8c02..ade1ba6b3451 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -2543,6 +2543,7 @@ static void qla4_8xxx_process_fw_error(struct scsi_qla_host *ha) void qla4_8xxx_watchdog(struct scsi_qla_host *ha) { uint32_t dev_state; + uint32_t idc_ctrl; /* don't poll if reset is going on */ if (!(test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) || @@ -2561,10 +2562,23 @@ void qla4_8xxx_watchdog(struct scsi_qla_host *ha) qla4xxx_wake_dpc(ha); } else if (dev_state == QLA8XXX_DEV_NEED_RESET && !test_bit(DPC_RESET_HA, &ha->dpc_flags)) { + + ql4_printk(KERN_INFO, ha, "%s: HW State: NEED RESET!\n", + __func__); + + if (is_qla8032(ha)) { + idc_ctrl = qla4_83xx_rd_reg(ha, + QLA83XX_IDC_DRV_CTRL); + if (!(idc_ctrl & GRACEFUL_RESET_BIT1)) { + ql4_printk(KERN_INFO, ha, "%s: Graceful reset bit is not set\n", + __func__); + qla4xxx_mailbox_premature_completion( + ha); + } + } + if (is_qla8032(ha) || (is_qla8022(ha) && !ql4xdontresethba)) { - ql4_printk(KERN_INFO, ha, "%s: HW State: " - "NEED RESET!\n", __func__); set_bit(DPC_RESET_HA, &ha->dpc_flags); qla4xxx_wake_dpc(ha); } -- cgit v1.2.3 From ae3ae252356377e523ae1163834e088d346410b0 Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Thu, 7 Mar 2013 05:43:11 -0500 Subject: [SCSI] qla4xxx: Pass correct LUN address to firmware in case of lun_reset Use function int_to_scsilun() in qla4xxx_reset_lun() to convert integer value comming from scsi_transport to scsi LUN address format. Signed-off-by: Vikas Chaudhary Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_mbx.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/scsi/qla4xxx') diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index 160d33697216..446511d58124 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -1129,6 +1129,7 @@ int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry, { uint32_t mbox_cmd[MBOX_REG_COUNT]; uint32_t mbox_sts[MBOX_REG_COUNT]; + uint32_t scsi_lun[2]; int status = QLA_SUCCESS; DEBUG2(printk("scsi%ld:%d:%d: lun reset issued\n", ha->host_no, @@ -1140,10 +1141,16 @@ int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry, */ memset(&mbox_cmd, 0, sizeof(mbox_cmd)); memset(&mbox_sts, 0, sizeof(mbox_sts)); + int_to_scsilun(lun, (struct scsi_lun *) scsi_lun); mbox_cmd[0] = MBOX_CMD_LUN_RESET; mbox_cmd[1] = ddb_entry->fw_ddb_index; - mbox_cmd[2] = lun << 8; + /* FW expects LUN bytes 0-3 in Incoming Mailbox 2 + * (LUN byte 0 is LSByte, byte 3 is MSByte) */ + mbox_cmd[2] = cpu_to_le32(scsi_lun[0]); + /* FW expects LUN bytes 4-7 in Incoming Mailbox 3 + * (LUN byte 4 is LSByte, byte 7 is MSByte) */ + mbox_cmd[3] = cpu_to_le32(scsi_lun[1]); mbox_cmd[5] = 0x01; /* Immediate Command Enable */ qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]); -- cgit v1.2.3 From 33338e31839fe45fa794bcc227d292dd7fab786c Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Thu, 7 Mar 2013 05:43:12 -0500 Subject: [SCSI] qla4xxx: Fix debug level to avoid floods of same message Move "Incorrect function ID" print message in case INTX interrupt from DEBUG2 to DEBUG7. This will avoid floods of this message if DEBUG2 is enabled. Signed-off-by: Vikas Chaudhary Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_dbg.h | 7 +++++++ drivers/scsi/qla4xxx/ql4_isr.c | 8 ++++---- 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers/scsi/qla4xxx') diff --git a/drivers/scsi/qla4xxx/ql4_dbg.h b/drivers/scsi/qla4xxx/ql4_dbg.h index 5b0afc18ef18..51c365bcf912 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_7 */ /* #define QL_DEBUG_LEVEL_9 */ #define QL_DEBUG_LEVEL_2 /* ALways enable error messagess */ @@ -48,6 +49,12 @@ #define DEBUG5(x) do {} while (0); #endif /* */ +#if defined(QL_DEBUG_LEVEL_7) +#define DEBUG7(x) do {x; } while (0) +#else /* */ +#define DEBUG7(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_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c index 1b83dc283d2e..e02a884b950b 100644 --- a/drivers/scsi/qla4xxx/ql4_isr.c +++ b/drivers/scsi/qla4xxx/ql4_isr.c @@ -1099,8 +1099,8 @@ irqreturn_t qla4_82xx_intr_handler(int irq, void *dev_id) status = qla4_82xx_rd_32(ha, ISR_INT_STATE_REG); if (!ISR_IS_LEGACY_INTR_TRIGGERED(status)) { - DEBUG2(ql4_printk(KERN_INFO, ha, - "%s legacy Int not triggered\n", __func__)); + DEBUG7(ql4_printk(KERN_INFO, ha, + "%s legacy Int not triggered\n", __func__)); return IRQ_NONE; } @@ -1158,7 +1158,7 @@ irqreturn_t qla4_83xx_intr_handler(int irq, void *dev_id) /* Legacy interrupt is valid if bit31 of leg_int_ptr is set */ if (!(leg_int_ptr & LEG_INT_PTR_B31)) { - DEBUG2(ql4_printk(KERN_ERR, ha, + DEBUG7(ql4_printk(KERN_ERR, ha, "%s: Legacy Interrupt Bit 31 not set, spurious interrupt!\n", __func__)); return IRQ_NONE; @@ -1166,7 +1166,7 @@ irqreturn_t qla4_83xx_intr_handler(int irq, void *dev_id) /* Validate the PCIE function ID set in leg_int_ptr bits [19..16] */ if ((leg_int_ptr & PF_BITS_MASK) != ha->pf_bit) { - DEBUG2(ql4_printk(KERN_ERR, ha, + DEBUG7(ql4_printk(KERN_ERR, ha, "%s: Incorrect function ID 0x%x in legacy interrupt register, ha->pf_bit = 0x%x\n", __func__, (leg_int_ptr & PF_BITS_MASK), ha->pf_bit)); -- cgit v1.2.3 From a24058f9c2368568aed14593b8a63706408547da Mon Sep 17 00:00:00 2001 From: Tej Parkash Date: Thu, 7 Mar 2013 05:43:13 -0500 Subject: [SCSI] qla4xxx: Fixed request queue count manipulation on response path Issue: Request queue count holds the information about free space in request queue which has to be manipulated based on request in and out pointer. But in driver response path, this count was incremented unconditionally, which could move req_in pointer beyond req_out pointer. This scenario leads fw hang during IO. Solution: Request queue count manipulation has to be done in IO path only, keeping req_in and req_out pointer two IOCB count away Signed-off-by: Tej Parkash Signed-off-by: Shyam Sundar Signed-off-by: Vikas Chaudhary Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_glbl.h | 2 -- drivers/scsi/qla4xxx/ql4_isr.c | 2 -- drivers/scsi/qla4xxx/ql4_os.c | 15 ++------------- 3 files changed, 2 insertions(+), 17 deletions(-) (limited to 'drivers/scsi/qla4xxx') diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index 982293edf02c..22706f66266f 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h @@ -224,8 +224,6 @@ void qla4_83xx_interrupt_service_routine(struct scsi_qla_host *ha, int qla4_83xx_isp_reset(struct scsi_qla_host *ha); void qla4_83xx_queue_iocb(struct scsi_qla_host *ha); void qla4_83xx_complete_iocb(struct scsi_qla_host *ha); -uint16_t qla4_83xx_rd_shdw_req_q_out(struct scsi_qla_host *ha); -uint16_t qla4_83xx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha); uint32_t qla4_83xx_rd_reg(struct scsi_qla_host *ha, ulong addr); void qla4_83xx_wr_reg(struct scsi_qla_host *ha, ulong addr, uint32_t val); int qla4_83xx_rd_reg_indirect(struct scsi_qla_host *ha, uint32_t addr, diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c index e02a884b950b..7bef448e2946 100644 --- a/drivers/scsi/qla4xxx/ql4_isr.c +++ b/drivers/scsi/qla4xxx/ql4_isr.c @@ -396,7 +396,6 @@ static void qla4xxx_passthru_status_entry(struct scsi_qla_host *ha, task_data = task->dd_data; memcpy(&task_data->sts, sts_entry, sizeof(struct passthru_status)); - ha->req_q_count += task_data->iocb_req_cnt; ha->iocb_cnt -= task_data->iocb_req_cnt; queue_work(ha->task_wq, &task_data->task_work); } @@ -416,7 +415,6 @@ static struct mrb *qla4xxx_del_mrb_from_active_array(struct scsi_qla_host *ha, return mrb; /* update counters */ - ha->req_q_count += mrb->iocb_cnt; ha->iocb_cnt -= mrb->iocb_cnt; return mrb; diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index ade1ba6b3451..a6ce04d1adae 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -3751,8 +3751,8 @@ static struct isp_operations qla4_83xx_isp_ops = { .reset_firmware = qla4_8xxx_stop_firmware, .queue_iocb = qla4_83xx_queue_iocb, .complete_iocb = qla4_83xx_complete_iocb, - .rd_shdw_req_q_out = qla4_83xx_rd_shdw_req_q_out, - .rd_shdw_rsp_q_in = qla4_83xx_rd_shdw_rsp_q_in, + .rd_shdw_req_q_out = qla4xxx_rd_shdw_req_q_out, + .rd_shdw_rsp_q_in = qla4xxx_rd_shdw_rsp_q_in, .get_sys_info = qla4_8xxx_get_sys_info, .rd_reg_direct = qla4_83xx_rd_reg, .wr_reg_direct = qla4_83xx_wr_reg, @@ -3775,11 +3775,6 @@ uint16_t qla4_82xx_rd_shdw_req_q_out(struct scsi_qla_host *ha) return (uint16_t)le32_to_cpu(readl(&ha->qla4_82xx_reg->req_q_out)); } -uint16_t qla4_83xx_rd_shdw_req_q_out(struct scsi_qla_host *ha) -{ - return (uint16_t)le32_to_cpu(readl(&ha->qla4_83xx_reg->req_q_out)); -} - uint16_t qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha) { return (uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in); @@ -3790,11 +3785,6 @@ uint16_t qla4_82xx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha) return (uint16_t)le32_to_cpu(readl(&ha->qla4_82xx_reg->rsp_q_in)); } -uint16_t qla4_83xx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha) -{ - return (uint16_t)le32_to_cpu(readl(&ha->qla4_83xx_reg->rsp_q_in)); -} - static ssize_t qla4xxx_show_boot_eth_info(void *data, int type, char *buf) { struct scsi_qla_host *ha = data; @@ -5683,7 +5673,6 @@ struct srb *qla4xxx_del_from_active_array(struct scsi_qla_host *ha, /* update counters */ if (srb->flags & SRB_DMA_VALID) { - ha->req_q_count += srb->iocb_cnt; ha->iocb_cnt -= srb->iocb_cnt; if (srb->cmd) srb->cmd->host_scribble = -- cgit v1.2.3 From 38a4089a9ef17f3185cb6ec4506f0734b53eabea Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Thu, 7 Mar 2013 05:43:14 -0500 Subject: [SCSI] qla4xxx: Update driver version to 5.03.00-k5 Signed-off-by: Vikas Chaudhary Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi/qla4xxx') diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h index 6775a45af315..4540028da75a 100644 --- a/drivers/scsi/qla4xxx/ql4_version.h +++ b/drivers/scsi/qla4xxx/ql4_version.h @@ -5,4 +5,4 @@ * See LICENSE.qla4xxx for copyright and licensing details. */ -#define QLA4XXX_DRIVER_VERSION "5.03.00-k4" +#define QLA4XXX_DRIVER_VERSION "5.03.00-k5" -- cgit v1.2.3 From d11b0ca38d1994c5a14dad0a3c0f47401e8ebcdb Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Fri, 22 Mar 2013 07:08:31 -0400 Subject: [SCSI] qla4xxx: Added missing check for ISP83XX in CHAP related functions Signed-off-by: Vikas Chaudhary Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_mbx.c | 2 +- drivers/scsi/qla4xxx/ql4_os.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/scsi/qla4xxx') diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index 446511d58124..ce4654501fab 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -1531,7 +1531,7 @@ int qla4xxx_get_chap_index(struct scsi_qla_host *ha, char *username, int max_chap_entries = 0; struct ql4_chap_table *chap_table; - if (is_qla8022(ha)) + if (is_qla80XX(ha)) max_chap_entries = (ha->hw.flt_chap_size / 2) / sizeof(struct ql4_chap_table); else diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index a6ce04d1adae..18f857a3b896 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -391,7 +391,7 @@ static int qla4xxx_get_chap_list(struct Scsi_Host *shost, uint16_t chap_tbl_idx, int valid_chap_entries = 0; int ret = 0, i; - if (is_qla8022(ha)) + if (is_qla80XX(ha)) max_chap_entries = (ha->hw.flt_chap_size / 2) / sizeof(struct ql4_chap_table); else @@ -495,7 +495,7 @@ static int qla4xxx_delete_chap(struct Scsi_Host *shost, uint16_t chap_tbl_idx) memset(chap_table, 0, sizeof(struct ql4_chap_table)); - if (is_qla8022(ha)) + if (is_qla80XX(ha)) max_chap_entries = (ha->hw.flt_chap_size / 2) / sizeof(struct ql4_chap_table); else @@ -4087,7 +4087,7 @@ static int qla4xxx_get_bidi_chap(struct scsi_qla_host *ha, char *username, int max_chap_entries = 0; struct ql4_chap_table *chap_table; - if (is_qla8022(ha)) + if (is_qla80XX(ha)) max_chap_entries = (ha->hw.flt_chap_size / 2) / sizeof(struct ql4_chap_table); else -- cgit v1.2.3 From 9a16f65bed06e562abb9882ffb277c6808a0fe34 Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Fri, 22 Mar 2013 07:08:32 -0400 Subject: [SCSI] qla4xxx: Assign correct CHAP table address to FLT Issue: If flash read for FLT fails, we are assigning wrong default address for CHAP table in FLT, which will cause CHAP table read/write to wrong address. Fix: Assign correct default CHAP table address to FLT. Signed-off-by: Vikas Chaudhary Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_nx.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/scsi/qla4xxx') diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c index 71d3d234f526..31fac90e54e2 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.c +++ b/drivers/scsi/qla4xxx/ql4_nx.c @@ -3166,14 +3166,15 @@ no_flash_data: hw->flt_region_boot = FA_BOOT_CODE_ADDR_82; hw->flt_region_bootload = FA_BOOT_LOAD_ADDR_82; hw->flt_region_fw = FA_RISC_CODE_ADDR_82; - hw->flt_region_chap = FA_FLASH_ISCSI_CHAP; + hw->flt_region_chap = FA_FLASH_ISCSI_CHAP >> 2; hw->flt_chap_size = FA_FLASH_CHAP_SIZE; done: - DEBUG2(ql4_printk(KERN_INFO, ha, "FLT[%s]: flt=0x%x fdt=0x%x " - "boot=0x%x bootload=0x%x fw=0x%x\n", loc, hw->flt_region_flt, - hw->flt_region_fdt, hw->flt_region_boot, hw->flt_region_bootload, - hw->flt_region_fw)); + DEBUG2(ql4_printk(KERN_INFO, ha, + "FLT[%s]: flt=0x%x fdt=0x%x boot=0x%x bootload=0x%x fw=0x%x chap=0x%x\n", + loc, hw->flt_region_flt, hw->flt_region_fdt, + hw->flt_region_boot, hw->flt_region_bootload, + hw->flt_region_fw, hw->flt_region_chap)); } static void -- cgit v1.2.3 From 17801c96b6fdf6048908e0680a140a87a267a397 Mon Sep 17 00:00:00 2001 From: Nilesh Javali Date: Fri, 22 Mar 2013 07:22:42 -0400 Subject: [SCSI] qla4xxx: Skip retry of initialize_adapter for ISP80XX While probe Skip retry of initialize_adapter only for ISP82XX and ISP83XX. We need to retry initialize_adapter for ISP40XX. Signed-off-by: Nilesh Javali Signed-off-by: Vikas Chaudhary Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_os.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/scsi/qla4xxx') diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 18f857a3b896..f3cf04ebf516 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -5345,8 +5345,11 @@ static int qla4xxx_probe_adapter(struct pci_dev *pdev, status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER); /* Dont retry adapter initialization if IRQ allocation failed */ - if (!test_bit(AF_IRQ_ATTACHED, &ha->flags)) + if (is_qla80XX(ha) && !test_bit(AF_IRQ_ATTACHED, &ha->flags)) { + ql4_printk(KERN_WARNING, ha, "%s: Skipping retry of adapter initialization\n", + __func__); goto skip_retry_init; + } while ((!test_bit(AF_ONLINE, &ha->flags)) && init_retry_count++ < MAX_INIT_RETRIES) { -- cgit v1.2.3 From 9060f6bfc389edb195548d7357e588430c32ab77 Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Fri, 22 Mar 2013 07:08:34 -0400 Subject: [SCSI] qla4xxx: Update driver version to 5.03.00-k6 Signed-off-by: Vikas Chaudhary Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi/qla4xxx') diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h index 4540028da75a..0cd824fe1513 100644 --- a/drivers/scsi/qla4xxx/ql4_version.h +++ b/drivers/scsi/qla4xxx/ql4_version.h @@ -5,4 +5,4 @@ * See LICENSE.qla4xxx for copyright and licensing details. */ -#define QLA4XXX_DRIVER_VERSION "5.03.00-k5" +#define QLA4XXX_DRIVER_VERSION "5.03.00-k6" -- cgit v1.2.3 From 1e9e2be3ee03b8b5c6066d3943c9c5ab1632ed0a Mon Sep 17 00:00:00 2001 From: Adheer Chandravanshi Date: Fri, 22 Mar 2013 07:41:31 -0400 Subject: [SCSI] qla4xxx: Add flash node mgmt support This patch allows iscsiadm to manage iSCSI target information stored on qla4xxx adapter flash on per host basis. Signed-off-by: Adheer Chandravanshi Signed-off-by: Manish Rangankar Signed-off-by: Vikas Chaudhary Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_def.h | 22 + drivers/scsi/qla4xxx/ql4_fw.h | 34 + drivers/scsi/qla4xxx/ql4_glbl.h | 7 + drivers/scsi/qla4xxx/ql4_mbx.c | 106 ++- drivers/scsi/qla4xxx/ql4_nx.c | 12 +- drivers/scsi/qla4xxx/ql4_os.c | 1861 ++++++++++++++++++++++++++++++++++++--- 6 files changed, 1931 insertions(+), 111 deletions(-) (limited to 'drivers/scsi/qla4xxx') diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index 129f5dd02822..b487b0aa4dee 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -159,6 +159,25 @@ #define LSDW(x) ((u32)((u64)(x))) #define MSDW(x) ((u32)((((u64)(x)) >> 16) >> 16)) +#define DEV_TYPE_IPV4 "ipv4" +#define DEV_TYPE_IPV6 "ipv6" + +#define DEV_DB_NON_PERSISTENT 0 +#define DEV_DB_PERSISTENT 1 + +#define COPY_ISID(dst_isid, src_isid) { \ + int i, j; \ + for (i = 0, j = ISID_SIZE - 1; i < ISID_SIZE;) \ + dst_isid[i++] = src_isid[j--]; \ +} + +#define SET_BITVAL(o, n, v) { \ + if (o) \ + n |= v; \ + else \ + n &= ~v; \ +} + /* * Retry & Timeout Values */ @@ -363,6 +382,8 @@ struct ql82xx_hw_data { uint32_t flt_iscsi_param; uint32_t flt_region_chap; uint32_t flt_chap_size; + uint32_t flt_region_ddb; + uint32_t flt_ddb_size; }; struct qla4_8xxx_legacy_intr_set { @@ -501,6 +522,7 @@ struct scsi_qla_host { #define AF_INIT_DONE 1 /* 0x00000002 */ #define AF_MBOX_COMMAND 2 /* 0x00000004 */ #define AF_MBOX_COMMAND_DONE 3 /* 0x00000008 */ +#define AF_ST_DISCOVERY_IN_PROGRESS 4 /* 0x00000010 */ #define AF_INTERRUPTS_ON 6 /* 0x00000040 */ #define AF_GET_CRASH_RECORD 7 /* 0x00000080 */ #define AF_LINK_UP 8 /* 0x00000100 */ diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h index ad9d2e2d370f..5945829d662f 100644 --- a/drivers/scsi/qla4xxx/ql4_fw.h +++ b/drivers/scsi/qla4xxx/ql4_fw.h @@ -288,6 +288,8 @@ union external_hw_config_reg { #define FA_GOLD_RISC_CODE_ADDR_82 0x80000 #define FA_FLASH_ISCSI_CHAP 0x540000 #define FA_FLASH_CHAP_SIZE 0xC0000 +#define FA_FLASH_ISCSI_DDB 0x420000 +#define FA_FLASH_DDB_SIZE 0x080000 /* Flash Description Table */ struct qla_fdt_layout { @@ -348,6 +350,7 @@ struct qla_flt_header { #define FLT_REG_BOOT_CODE_82 0x78 #define FLT_REG_ISCSI_PARAM 0x65 #define FLT_REG_ISCSI_CHAP 0x63 +#define FLT_REG_ISCSI_DDB 0x6A struct qla_flt_region { uint32_t code; @@ -779,12 +782,41 @@ struct dev_db_entry { #define DDB_OPT_IPV6_NULL_LINK_LOCAL 0x800 /* post connection */ #define DDB_OPT_IPV6_FW_DEFINED_LINK_LOCAL 0x800 /* pre connection */ +#define OPT_IS_FW_ASSIGNED_IPV6 11 +#define OPT_IPV6_DEVICE 8 +#define OPT_AUTO_SENDTGTS_DISABLE 6 +#define OPT_DISC_SESSION 4 +#define OPT_ENTRY_STATE 3 uint16_t exec_throttle; /* 02-03 */ uint16_t exec_count; /* 04-05 */ uint16_t res0; /* 06-07 */ uint16_t iscsi_options; /* 08-09 */ +#define ISCSIOPT_HEADER_DIGEST_EN 13 +#define ISCSIOPT_DATA_DIGEST_EN 12 +#define ISCSIOPT_IMMEDIATE_DATA_EN 11 +#define ISCSIOPT_INITIAL_R2T_EN 10 +#define ISCSIOPT_DATA_SEQ_IN_ORDER 9 +#define ISCSIOPT_DATA_PDU_IN_ORDER 8 +#define ISCSIOPT_CHAP_AUTH_EN 7 +#define ISCSIOPT_SNACK_REQ_EN 6 +#define ISCSIOPT_DISCOVERY_LOGOUT_EN 5 +#define ISCSIOPT_BIDI_CHAP_EN 4 +#define ISCSIOPT_DISCOVERY_AUTH_OPTIONAL 3 +#define ISCSIOPT_ERL1 1 +#define ISCSIOPT_ERL0 0 + uint16_t tcp_options; /* 0A-0B */ +#define TCPOPT_TIMESTAMP_STAT 6 +#define TCPOPT_NAGLE_DISABLE 5 +#define TCPOPT_WSF_DISABLE 4 +#define TCPOPT_TIMER_SCALE3 3 +#define TCPOPT_TIMER_SCALE2 2 +#define TCPOPT_TIMER_SCALE1 1 +#define TCPOPT_TIMESTAMP_EN 0 + uint16_t ip_options; /* 0C-0D */ +#define IPOPT_FRAGMENT_DISABLE 4 + uint16_t iscsi_max_rcv_data_seg_len; /* 0E-0F */ #define BYTE_UNITS 512 uint32_t res1; /* 10-13 */ @@ -816,6 +848,8 @@ struct dev_db_entry { * much RAM */ uint8_t link_local_ipv6_addr[0x10]; /* 1A0-1AF */ uint8_t res5[0x10]; /* 1B0-1BF */ +#define DDB_NO_LINK 0xFFFF +#define DDB_ISNS 0xFFFD uint16_t ddb_link; /* 1C0-1C1 */ uint16_t chap_tbl_idx; /* 1C2-1C3 */ uint16_t tgt_portal_grp; /* 1C4-1C5 */ diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index 22706f66266f..4a428009f699 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h @@ -191,6 +191,9 @@ int qla4xxx_ping_iocb(struct scsi_qla_host *ha, uint32_t options, int qla4xxx_post_ping_evt_work(struct scsi_qla_host *ha, uint32_t status, uint32_t pid, uint32_t data_size, uint8_t *data); +int qla4xxx_flashdb_by_index(struct scsi_qla_host *ha, + struct dev_db_entry *fw_ddb_entry, + dma_addr_t fw_ddb_entry_dma, uint16_t ddb_index); /* BSG Functions */ int qla4xxx_bsg_request(struct bsg_job *bsg_job); @@ -259,6 +262,10 @@ int qla4_83xx_post_idc_ack(struct scsi_qla_host *ha); void qla4_83xx_disable_pause(struct scsi_qla_host *ha); void qla4_83xx_enable_mbox_intrs(struct scsi_qla_host *ha); int qla4_83xx_can_perform_reset(struct scsi_qla_host *ha); +int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, uint32_t options, + dma_addr_t dma_addr); +int qla4xxx_get_uni_chap_at_index(struct scsi_qla_host *ha, char *username, + char *password, uint16_t chap_index); extern int ql4xextended_error_logging; extern int ql4xdontresethba; diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index ce4654501fab..8985997de576 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -1288,8 +1288,8 @@ exit_about_fw: return status; } -static int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, uint32_t options, - dma_addr_t dma_addr) +int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, uint32_t options, + dma_addr_t dma_addr) { uint32_t mbox_cmd[MBOX_REG_COUNT]; uint32_t mbox_sts[MBOX_REG_COUNT]; @@ -1417,6 +1417,52 @@ exit_bootdb_failed: return status; } +int qla4xxx_flashdb_by_index(struct scsi_qla_host *ha, + struct dev_db_entry *fw_ddb_entry, + dma_addr_t fw_ddb_entry_dma, uint16_t ddb_index) +{ + uint32_t dev_db_start_offset = FLASH_OFFSET_DB_INFO; + uint32_t dev_db_end_offset; + int status = QLA_ERROR; + + memset(fw_ddb_entry, 0, sizeof(*fw_ddb_entry)); + + if (is_qla40XX(ha)) { + dev_db_start_offset = FLASH_OFFSET_DB_INFO; + } else { + dev_db_start_offset = FLASH_RAW_ACCESS_ADDR + + (ha->hw.flt_region_ddb << 2); + /* flt_ddb_size is DDB table size for both ports + * so divide it by 2 to calculate the offset for second port + */ + if (ha->port_num == 1) + dev_db_start_offset += (ha->hw.flt_ddb_size / 2); + } + + dev_db_end_offset = dev_db_start_offset + (ha->hw.flt_ddb_size / 2); + dev_db_start_offset += (ddb_index * sizeof(*fw_ddb_entry)); + + if (dev_db_start_offset > dev_db_end_offset) { + DEBUG2(ql4_printk(KERN_ERR, ha, + "%s:Invalid DDB index %d", __func__, + ddb_index)); + goto exit_fdb_failed; + } + + if (qla4xxx_get_flash(ha, fw_ddb_entry_dma, dev_db_start_offset, + sizeof(*fw_ddb_entry)) != QLA_SUCCESS) { + ql4_printk(KERN_ERR, ha, "scsi%ld: %s: Get Flash failed\n", + ha->host_no, __func__); + goto exit_fdb_failed; + } + + if (fw_ddb_entry->cookie == DDB_VALID_COOKIE) + status = QLA_SUCCESS; + +exit_fdb_failed: + return status; +} + int qla4xxx_get_chap(struct scsi_qla_host *ha, char *username, char *password, uint16_t idx) { @@ -1510,6 +1556,62 @@ exit_set_chap: return ret; } + +int qla4xxx_get_uni_chap_at_index(struct scsi_qla_host *ha, char *username, + char *password, uint16_t chap_index) +{ + int rval = QLA_ERROR; + struct ql4_chap_table *chap_table = NULL; + int max_chap_entries; + + if (!ha->chap_list) { + ql4_printk(KERN_ERR, ha, "Do not have CHAP table cache\n"); + rval = QLA_ERROR; + goto exit_uni_chap; + } + + if (!username || !password) { + ql4_printk(KERN_ERR, ha, "No memory for username & secret\n"); + rval = QLA_ERROR; + goto exit_uni_chap; + } + + if (is_qla80XX(ha)) + max_chap_entries = (ha->hw.flt_chap_size / 2) / + sizeof(struct ql4_chap_table); + else + max_chap_entries = MAX_CHAP_ENTRIES_40XX; + + if (chap_index > max_chap_entries) { + ql4_printk(KERN_ERR, ha, "Invalid Chap index\n"); + rval = QLA_ERROR; + goto exit_uni_chap; + } + + mutex_lock(&ha->chap_sem); + chap_table = (struct ql4_chap_table *)ha->chap_list + chap_index; + if (chap_table->cookie != __constant_cpu_to_le16(CHAP_VALID_COOKIE)) { + rval = QLA_ERROR; + goto exit_unlock_uni_chap; + } + + if (!(chap_table->flags & BIT_6)) { + ql4_printk(KERN_ERR, ha, "Unidirectional entry not set\n"); + rval = QLA_ERROR; + goto exit_unlock_uni_chap; + } + + strncpy(password, chap_table->secret, MAX_CHAP_SECRET_LEN); + strncpy(username, chap_table->name, MAX_CHAP_NAME_LEN); + + rval = QLA_SUCCESS; + +exit_unlock_uni_chap: + mutex_unlock(&ha->chap_sem); +exit_uni_chap: + return rval; +} + /** * qla4xxx_get_chap_index - Get chap index given username and secret * @ha: pointer to adapter structure diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c index 31fac90e54e2..5f1dbb7c7bef 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.c +++ b/drivers/scsi/qla4xxx/ql4_nx.c @@ -3154,6 +3154,10 @@ qla4_8xxx_get_flt_info(struct scsi_qla_host *ha, uint32_t flt_addr) hw->flt_region_chap = start; hw->flt_chap_size = le32_to_cpu(region->size); break; + case FLT_REG_ISCSI_DDB: + hw->flt_region_ddb = start; + hw->flt_ddb_size = le32_to_cpu(region->size); + break; } } goto done; @@ -3168,13 +3172,17 @@ no_flash_data: hw->flt_region_fw = FA_RISC_CODE_ADDR_82; hw->flt_region_chap = FA_FLASH_ISCSI_CHAP >> 2; hw->flt_chap_size = FA_FLASH_CHAP_SIZE; + hw->flt_region_ddb = FA_FLASH_ISCSI_DDB >> 2; + hw->flt_ddb_size = FA_FLASH_DDB_SIZE; done: DEBUG2(ql4_printk(KERN_INFO, ha, - "FLT[%s]: flt=0x%x fdt=0x%x boot=0x%x bootload=0x%x fw=0x%x chap=0x%x\n", + "FLT[%s]: flt=0x%x fdt=0x%x boot=0x%x bootload=0x%x fw=0x%x chap=0x%x chap_size=0x%x ddb=0x%x ddb_size=0x%x\n", loc, hw->flt_region_flt, hw->flt_region_fdt, hw->flt_region_boot, hw->flt_region_bootload, - hw->flt_region_fw, hw->flt_region_chap)); + hw->flt_region_fw, hw->flt_region_chap, + hw->flt_chap_size, hw->flt_region_ddb, + hw->flt_ddb_size)); } static void diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index f3cf04ebf516..497ac681d733 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -166,6 +166,26 @@ static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type); static int qla4xxx_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason); +/* + * iSCSI Flash DDB sysfs entry points + */ +static int +qla4xxx_sysfs_ddb_set_param(struct iscsi_bus_flash_session *fnode_sess, + struct iscsi_bus_flash_conn *fnode_conn, + void *data, int len); +static int +qla4xxx_sysfs_ddb_get_param(struct iscsi_bus_flash_session *fnode_sess, + int param, char *buf); +static int qla4xxx_sysfs_ddb_add(struct Scsi_Host *shost, const char *buf, + int len); +static int +qla4xxx_sysfs_ddb_delete(struct iscsi_bus_flash_session *fnode_sess); +static int qla4xxx_sysfs_ddb_login(struct iscsi_bus_flash_session *fnode_sess, + struct iscsi_bus_flash_conn *fnode_conn); +static int qla4xxx_sysfs_ddb_logout(struct iscsi_bus_flash_session *fnode_sess, + struct iscsi_bus_flash_conn *fnode_conn); +static int qla4xxx_sysfs_ddb_logout_sid(struct iscsi_cls_session *cls_sess); + static struct qla4_8xxx_legacy_intr_set legacy_intr[] = QLA82XX_LEGACY_INTR_CONFIG; @@ -232,6 +252,13 @@ static struct iscsi_transport qla4xxx_iscsi_transport = { .send_ping = qla4xxx_send_ping, .get_chap = qla4xxx_get_chap_list, .delete_chap = qla4xxx_delete_chap, + .get_flashnode_param = qla4xxx_sysfs_ddb_get_param, + .set_flashnode_param = qla4xxx_sysfs_ddb_set_param, + .new_flashnode = qla4xxx_sysfs_ddb_add, + .del_flashnode = qla4xxx_sysfs_ddb_delete, + .login_flashnode = qla4xxx_sysfs_ddb_login, + .logout_flashnode = qla4xxx_sysfs_ddb_logout, + .logout_flashnode_sid = qla4xxx_sysfs_ddb_logout_sid, }; static struct scsi_transport_template *qla4xxx_scsi_transport; @@ -376,6 +403,68 @@ static umode_t qla4_attr_is_visible(int param_type, int param) default: return 0; } + case ISCSI_FLASHNODE_PARAM: + switch (param) { + case ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6: + case ISCSI_FLASHNODE_PORTAL_TYPE: + case ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE: + case ISCSI_FLASHNODE_DISCOVERY_SESS: + case ISCSI_FLASHNODE_ENTRY_EN: + case ISCSI_FLASHNODE_HDR_DGST_EN: + case ISCSI_FLASHNODE_DATA_DGST_EN: + case ISCSI_FLASHNODE_IMM_DATA_EN: + case ISCSI_FLASHNODE_INITIAL_R2T_EN: + case ISCSI_FLASHNODE_DATASEQ_INORDER: + case ISCSI_FLASHNODE_PDU_INORDER: + case ISCSI_FLASHNODE_CHAP_AUTH_EN: + case ISCSI_FLASHNODE_SNACK_REQ_EN: + case ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN: + case ISCSI_FLASHNODE_BIDI_CHAP_EN: + case ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL: + case ISCSI_FLASHNODE_ERL: + case ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT: + case ISCSI_FLASHNODE_TCP_NAGLE_DISABLE: + case ISCSI_FLASHNODE_TCP_WSF_DISABLE: + case ISCSI_FLASHNODE_TCP_TIMER_SCALE: + case ISCSI_FLASHNODE_TCP_TIMESTAMP_EN: + case ISCSI_FLASHNODE_IP_FRAG_DISABLE: + case ISCSI_FLASHNODE_MAX_RECV_DLENGTH: + case ISCSI_FLASHNODE_MAX_XMIT_DLENGTH: + case ISCSI_FLASHNODE_FIRST_BURST: + case ISCSI_FLASHNODE_DEF_TIME2WAIT: + case ISCSI_FLASHNODE_DEF_TIME2RETAIN: + case ISCSI_FLASHNODE_MAX_R2T: + case ISCSI_FLASHNODE_KEEPALIVE_TMO: + case ISCSI_FLASHNODE_ISID: + case ISCSI_FLASHNODE_TSID: + case ISCSI_FLASHNODE_PORT: + case ISCSI_FLASHNODE_MAX_BURST: + case ISCSI_FLASHNODE_DEF_TASKMGMT_TMO: + case ISCSI_FLASHNODE_IPADDR: + case ISCSI_FLASHNODE_ALIAS: + case ISCSI_FLASHNODE_REDIRECT_IPADDR: + case ISCSI_FLASHNODE_MAX_SEGMENT_SIZE: + case ISCSI_FLASHNODE_LOCAL_PORT: + case ISCSI_FLASHNODE_IPV4_TOS: + case ISCSI_FLASHNODE_IPV6_TC: + case ISCSI_FLASHNODE_IPV6_FLOW_LABEL: + case ISCSI_FLASHNODE_NAME: + case ISCSI_FLASHNODE_TPGT: + case ISCSI_FLASHNODE_LINK_LOCAL_IPV6: + case ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX: + case ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE: + case ISCSI_FLASHNODE_TCP_XMIT_WSF: + case ISCSI_FLASHNODE_TCP_RECV_WSF: + case ISCSI_FLASHNODE_CHAP_OUT_IDX: + case ISCSI_FLASHNODE_USERNAME: + case ISCSI_FLASHNODE_PASSWORD: + case ISCSI_FLASHNODE_STATSN: + case ISCSI_FLASHNODE_EXP_STATSN: + case ISCSI_FLASHNODE_IS_BOOT_TGT: + return S_IRUGO; + default: + return 0; + } } return 0; @@ -1922,6 +2011,250 @@ static int qla4xxx_task_xmit(struct iscsi_task *task) return -ENOSYS; } +static int qla4xxx_copy_from_fwddb_param(struct iscsi_bus_flash_session *sess, + struct iscsi_bus_flash_conn *conn, + struct dev_db_entry *fw_ddb_entry) +{ + unsigned long options = 0; + int rc = 0; + + options = le16_to_cpu(fw_ddb_entry->options); + conn->is_fw_assigned_ipv6 = test_bit(OPT_IS_FW_ASSIGNED_IPV6, &options); + if (test_bit(OPT_IPV6_DEVICE, &options)) { + rc = iscsi_switch_str_param(&sess->portal_type, DEV_TYPE_IPV6); + if (rc) + goto exit_copy; + } else { + rc = iscsi_switch_str_param(&sess->portal_type, DEV_TYPE_IPV4); + if (rc) + goto exit_copy; + } + + sess->auto_snd_tgt_disable = test_bit(OPT_AUTO_SENDTGTS_DISABLE, + &options); + sess->discovery_sess = test_bit(OPT_DISC_SESSION, &options); + sess->entry_state = test_bit(OPT_ENTRY_STATE, &options); + + options = le16_to_cpu(fw_ddb_entry->iscsi_options); + conn->hdrdgst_en = test_bit(ISCSIOPT_HEADER_DIGEST_EN, &options); + conn->datadgst_en = test_bit(ISCSIOPT_DATA_DIGEST_EN, &options); + sess->imm_data_en = test_bit(ISCSIOPT_IMMEDIATE_DATA_EN, &options); + sess->initial_r2t_en = test_bit(ISCSIOPT_INITIAL_R2T_EN, &options); + sess->dataseq_inorder_en = test_bit(ISCSIOPT_DATA_SEQ_IN_ORDER, + &options); + sess->pdu_inorder_en = test_bit(ISCSIOPT_DATA_PDU_IN_ORDER, &options); + sess->chap_auth_en = test_bit(ISCSIOPT_CHAP_AUTH_EN, &options); + conn->snack_req_en = test_bit(ISCSIOPT_SNACK_REQ_EN, &options); + sess->discovery_logout_en = test_bit(ISCSIOPT_DISCOVERY_LOGOUT_EN, + &options); + sess->bidi_chap_en = test_bit(ISCSIOPT_BIDI_CHAP_EN, &options); + sess->discovery_auth_optional = + test_bit(ISCSIOPT_DISCOVERY_AUTH_OPTIONAL, &options); + if (test_bit(ISCSIOPT_ERL1, &options)) + sess->erl |= BIT_1; + if (test_bit(ISCSIOPT_ERL0, &options)) + sess->erl |= BIT_0; + + options = le16_to_cpu(fw_ddb_entry->tcp_options); + conn->tcp_timestamp_stat = test_bit(TCPOPT_TIMESTAMP_STAT, &options); + conn->tcp_nagle_disable = test_bit(TCPOPT_NAGLE_DISABLE, &options); + conn->tcp_wsf_disable = test_bit(TCPOPT_WSF_DISABLE, &options); + if (test_bit(TCPOPT_TIMER_SCALE3, &options)) + conn->tcp_timer_scale |= BIT_3; + if (test_bit(TCPOPT_TIMER_SCALE2, &options)) + conn->tcp_timer_scale |= BIT_2; + if (test_bit(TCPOPT_TIMER_SCALE1, &options)) + conn->tcp_timer_scale |= BIT_1; + + conn->tcp_timer_scale >>= 1; + conn->tcp_timestamp_en = test_bit(TCPOPT_TIMESTAMP_EN, &options); + + options = le16_to_cpu(fw_ddb_entry->ip_options); + conn->fragment_disable = test_bit(IPOPT_FRAGMENT_DISABLE, &options); + + conn->max_recv_dlength = BYTE_UNITS * + le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len); + conn->max_xmit_dlength = BYTE_UNITS * + le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len); + sess->first_burst = BYTE_UNITS * + le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len); + sess->max_burst = BYTE_UNITS * + le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len); + sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t); + sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait); + sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain); + sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp); + conn->max_segment_size = le16_to_cpu(fw_ddb_entry->mss); + conn->tcp_xmit_wsf = fw_ddb_entry->tcp_xmt_wsf; + conn->tcp_recv_wsf = fw_ddb_entry->tcp_rcv_wsf; + conn->ipv6_flow_label = le16_to_cpu(fw_ddb_entry->ipv6_flow_lbl); + conn->keepalive_timeout = le16_to_cpu(fw_ddb_entry->ka_timeout); + conn->local_port = le16_to_cpu(fw_ddb_entry->lcl_port); + conn->statsn = le32_to_cpu(fw_ddb_entry->stat_sn); + conn->exp_statsn = le32_to_cpu(fw_ddb_entry->exp_stat_sn); + sess->discovery_parent_idx = le16_to_cpu(fw_ddb_entry->ddb_link); + sess->discovery_parent_type = le16_to_cpu(fw_ddb_entry->ddb_link); + sess->chap_out_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx); + sess->tsid = le16_to_cpu(fw_ddb_entry->tsid); + + sess->default_taskmgmt_timeout = + le16_to_cpu(fw_ddb_entry->def_timeout); + conn->port = le16_to_cpu(fw_ddb_entry->port); + + options = le16_to_cpu(fw_ddb_entry->options); + conn->ipaddress = kzalloc(IPv6_ADDR_LEN, GFP_KERNEL); + if (!conn->ipaddress) { + rc = -ENOMEM; + goto exit_copy; + } + + conn->redirect_ipaddr = kzalloc(IPv6_ADDR_LEN, GFP_KERNEL); + if (!conn->redirect_ipaddr) { + rc = -ENOMEM; + goto exit_copy; + } + + memcpy(conn->ipaddress, fw_ddb_entry->ip_addr, IPv6_ADDR_LEN); + memcpy(conn->redirect_ipaddr, fw_ddb_entry->tgt_addr, IPv6_ADDR_LEN); + + if (test_bit(OPT_IPV6_DEVICE, &options)) { + conn->ipv6_traffic_class = fw_ddb_entry->ipv4_tos; + + conn->link_local_ipv6_addr = kzalloc(IPv6_ADDR_LEN, GFP_KERNEL); + if (!conn->link_local_ipv6_addr) { + rc = -ENOMEM; + goto exit_copy; + } + + memcpy(conn->link_local_ipv6_addr, + fw_ddb_entry->link_local_ipv6_addr, IPv6_ADDR_LEN); + } else { + conn->ipv4_tos = fw_ddb_entry->ipv4_tos; + } + + if (fw_ddb_entry->iscsi_name[0]) { + rc = iscsi_switch_str_param(&sess->targetname, + (char *)fw_ddb_entry->iscsi_name); + if (rc) + goto exit_copy; + } + + if (fw_ddb_entry->iscsi_alias[0]) { + rc = iscsi_switch_str_param(&sess->targetalias, + (char *)fw_ddb_entry->iscsi_alias); + if (rc) + goto exit_copy; + } + + COPY_ISID(sess->isid, fw_ddb_entry->isid); + +exit_copy: + return rc; +} + +static int qla4xxx_copy_to_fwddb_param(struct iscsi_bus_flash_session *sess, + struct iscsi_bus_flash_conn *conn, + struct dev_db_entry *fw_ddb_entry) +{ + uint16_t options; + int rc = 0; + + options = le16_to_cpu(fw_ddb_entry->options); + SET_BITVAL(conn->is_fw_assigned_ipv6, options, BIT_11); + if (!strncmp(sess->portal_type, DEV_TYPE_IPV6, 4)) + options |= BIT_8; + else + options &= ~BIT_8; + + SET_BITVAL(sess->auto_snd_tgt_disable, options, BIT_6); + SET_BITVAL(sess->discovery_sess, options, BIT_4); + SET_BITVAL(sess->entry_state, options, BIT_3); + fw_ddb_entry->options = cpu_to_le16(options); + + options = le16_to_cpu(fw_ddb_entry->iscsi_options); + SET_BITVAL(conn->hdrdgst_en, options, BIT_13); + SET_BITVAL(conn->datadgst_en, options, BIT_12); + SET_BITVAL(sess->imm_data_en, options, BIT_11); + SET_BITVAL(sess->initial_r2t_en, options, BIT_10); + SET_BITVAL(sess->dataseq_inorder_en, options, BIT_9); + SET_BITVAL(sess->pdu_inorder_en, options, BIT_8); + SET_BITVAL(sess->chap_auth_en, options, BIT_7); + SET_BITVAL(conn->snack_req_en, options, BIT_6); + SET_BITVAL(sess->discovery_logout_en, options, BIT_5); + SET_BITVAL(sess->bidi_chap_en, options, BIT_4); + SET_BITVAL(sess->discovery_auth_optional, options, BIT_3); + SET_BITVAL(sess->erl & BIT_1, options, BIT_1); + SET_BITVAL(sess->erl & BIT_0, options, BIT_0); + fw_ddb_entry->iscsi_options = cpu_to_le16(options); + + options = le16_to_cpu(fw_ddb_entry->tcp_options); + SET_BITVAL(conn->tcp_timestamp_stat, options, BIT_6); + SET_BITVAL(conn->tcp_nagle_disable, options, BIT_5); + SET_BITVAL(conn->tcp_wsf_disable, options, BIT_4); + SET_BITVAL(conn->tcp_timer_scale & BIT_2, options, BIT_3); + SET_BITVAL(conn->tcp_timer_scale & BIT_1, options, BIT_2); + SET_BITVAL(conn->tcp_timer_scale & BIT_0, options, BIT_1); + SET_BITVAL(conn->tcp_timestamp_en, options, BIT_0); + fw_ddb_entry->tcp_options = cpu_to_le16(options); + + options = le16_to_cpu(fw_ddb_entry->ip_options); + SET_BITVAL(conn->fragment_disable, options, BIT_4); + fw_ddb_entry->ip_options = cpu_to_le16(options); + + fw_ddb_entry->iscsi_max_outsnd_r2t = cpu_to_le16(sess->max_r2t); + fw_ddb_entry->iscsi_max_rcv_data_seg_len = + cpu_to_le16(conn->max_recv_dlength / BYTE_UNITS); + fw_ddb_entry->iscsi_max_snd_data_seg_len = + cpu_to_le16(conn->max_xmit_dlength / BYTE_UNITS); + fw_ddb_entry->iscsi_first_burst_len = + cpu_to_le16(sess->first_burst / BYTE_UNITS); + fw_ddb_entry->iscsi_max_burst_len = cpu_to_le16(sess->max_burst / + BYTE_UNITS); + fw_ddb_entry->iscsi_def_time2wait = cpu_to_le16(sess->time2wait); + fw_ddb_entry->iscsi_def_time2retain = cpu_to_le16(sess->time2retain); + fw_ddb_entry->tgt_portal_grp = cpu_to_le16(sess->tpgt); + fw_ddb_entry->mss = cpu_to_le16(conn->max_segment_size); + fw_ddb_entry->tcp_xmt_wsf = cpu_to_le16(conn->tcp_xmit_wsf); + fw_ddb_entry->tcp_rcv_wsf = cpu_to_le16(conn->tcp_recv_wsf); + fw_ddb_entry->ipv4_tos = conn->ipv4_tos; + fw_ddb_entry->ipv6_flow_lbl = cpu_to_le16(conn->ipv6_flow_label); + fw_ddb_entry->ka_timeout = cpu_to_le16(conn->keepalive_timeout); + fw_ddb_entry->lcl_port = cpu_to_le16(conn->local_port); + fw_ddb_entry->stat_sn = cpu_to_le16(conn->statsn); + fw_ddb_entry->exp_stat_sn = cpu_to_le16(conn->exp_statsn); + fw_ddb_entry->ddb_link = cpu_to_le16(sess->discovery_parent_type); + fw_ddb_entry->chap_tbl_idx = cpu_to_le16(sess->chap_out_idx); + fw_ddb_entry->tsid = cpu_to_le16(sess->tsid); + fw_ddb_entry->port = cpu_to_le16(conn->port); + fw_ddb_entry->def_timeout = + cpu_to_le16(sess->default_taskmgmt_timeout); + + if (conn->ipaddress) + memcpy(fw_ddb_entry->ip_addr, conn->ipaddress, + sizeof(fw_ddb_entry->ip_addr)); + + if (conn->redirect_ipaddr) + memcpy(fw_ddb_entry->tgt_addr, conn->redirect_ipaddr, + sizeof(fw_ddb_entry->tgt_addr)); + + if (conn->link_local_ipv6_addr) + memcpy(fw_ddb_entry->link_local_ipv6_addr, + conn->link_local_ipv6_addr, + sizeof(fw_ddb_entry->link_local_ipv6_addr)); + + if (sess->targetname) + memcpy(fw_ddb_entry->iscsi_name, sess->targetname, + sizeof(fw_ddb_entry->iscsi_name)); + + if (sess->targetalias) + memcpy(fw_ddb_entry->iscsi_alias, sess->targetalias, + sizeof(fw_ddb_entry->iscsi_alias)); + + COPY_ISID(fw_ddb_entry->isid, sess->isid); + + return rc; +} + static void qla4xxx_copy_fwddb_param(struct scsi_qla_host *ha, struct dev_db_entry *fw_ddb_entry, struct iscsi_cls_session *cls_sess, @@ -5062,88 +5395,195 @@ exit_nt_list: dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma); } +static void qla4xxx_build_new_nt_list(struct scsi_qla_host *ha, + struct list_head *list_nt) +{ + struct dev_db_entry *fw_ddb_entry; + dma_addr_t fw_ddb_dma; + int max_ddbs; + int fw_idx_size; + int ret; + uint32_t idx = 0, next_idx = 0; + uint32_t state = 0, conn_err = 0; + uint16_t conn_id = 0; + struct qla_ddb_index *nt_ddb_idx; + + fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL, + &fw_ddb_dma); + if (fw_ddb_entry == NULL) { + DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n")); + goto exit_new_nt_list; + } + max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : + MAX_DEV_DB_ENTRIES; + fw_idx_size = sizeof(struct qla_ddb_index); + + for (idx = 0; idx < max_ddbs; idx = next_idx) { + ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma, + NULL, &next_idx, &state, + &conn_err, NULL, &conn_id); + if (ret == QLA_ERROR) + break; + + /* Check if NT, then add it to list */ + if (strlen((char *)fw_ddb_entry->iscsi_name) == 0) + goto continue_next_new_nt; + + if (!(state == DDB_DS_NO_CONNECTION_ACTIVE)) + goto continue_next_new_nt; + + DEBUG2(ql4_printk(KERN_INFO, ha, + "Adding DDB to session = 0x%x\n", idx)); + + nt_ddb_idx = vmalloc(fw_idx_size); + if (!nt_ddb_idx) + break; + + nt_ddb_idx->fw_ddb_idx = idx; + + ret = qla4xxx_is_session_exists(ha, fw_ddb_entry); + if (ret == QLA_SUCCESS) { + /* free nt_ddb_idx and do not add to list_nt */ + vfree(nt_ddb_idx); + goto continue_next_new_nt; + } + + list_add_tail(&nt_ddb_idx->list, list_nt); + + ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, RESET_ADAPTER, + idx); + if (ret == QLA_ERROR) + goto exit_new_nt_list; + +continue_next_new_nt: + if (next_idx == 0) + break; + } + +exit_new_nt_list: + if (fw_ddb_entry) + dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma); +} + /** - * qla4xxx_build_ddb_list - Build ddb list and setup sessions - * @ha: pointer to adapter structure - * @is_reset: Is this init path or reset path + * qla4xxx_sysfs_ddb_is_non_persistent - check for non-persistence of ddb entry + * @dev: dev associated with the sysfs entry + * @data: pointer to flashnode session object * - * Create a list of sendtargets (st) from firmware DDBs, issue send targets - * using connection open, then create the list of normal targets (nt) - * from firmware DDBs. Based on the list of nt setup session and connection - * objects. + * Returns: + * 1: if flashnode entry is non-persistent + * 0: if flashnode entry is persistent **/ -void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset) +static int qla4xxx_sysfs_ddb_is_non_persistent(struct device *dev, void *data) { - uint16_t tmo = 0; - struct list_head list_st, list_nt; - struct qla_ddb_index *st_ddb_idx, *st_ddb_idx_tmp; - unsigned long wtime; + struct iscsi_bus_flash_session *fnode_sess; - if (!test_bit(AF_LINK_UP, &ha->flags)) { - set_bit(AF_BUILD_DDB_LIST, &ha->flags); - ha->is_reset = is_reset; - return; - } + if (!iscsi_flashnode_bus_match(dev, NULL)) + return 0; - INIT_LIST_HEAD(&list_st); - INIT_LIST_HEAD(&list_nt); + fnode_sess = iscsi_dev_to_flash_session(dev); - qla4xxx_build_st_list(ha, &list_st); + return (fnode_sess->flash_state == DEV_DB_NON_PERSISTENT); +} - /* Before issuing conn open mbox, ensure all IPs states are configured - * Note, conn open fails if IPs are not configured - */ - qla4xxx_wait_for_ip_configuration(ha); +/** + * qla4xxx_sysfs_ddb_tgt_create - Create sysfs entry for target + * @ha: pointer to host + * @fw_ddb_entry: flash ddb data + * @idx: target index + * @user: if set then this call is made from userland else from kernel + * + * Returns: + * On sucess: QLA_SUCCESS + * On failure: QLA_ERROR + * + * This create separate sysfs entries for session and connection attributes of + * the given fw ddb entry. + * If this is invoked as a result of a userspace call then the entry is marked + * as nonpersistent using flash_state field. + **/ +int qla4xxx_sysfs_ddb_tgt_create(struct scsi_qla_host *ha, + struct dev_db_entry *fw_ddb_entry, + uint16_t *idx, int user) +{ + struct iscsi_bus_flash_session *fnode_sess = NULL; + struct iscsi_bus_flash_conn *fnode_conn = NULL; + int rc = QLA_ERROR; - /* Go thru the STs and fire the sendtargets by issuing conn open mbx */ - list_for_each_entry_safe(st_ddb_idx, st_ddb_idx_tmp, &list_st, list) { - qla4xxx_conn_open(ha, st_ddb_idx->fw_ddb_idx); + fnode_sess = iscsi_create_flashnode_sess(ha->host, *idx, + &qla4xxx_iscsi_transport, 0); + if (!fnode_sess) { + ql4_printk(KERN_ERR, ha, + "%s: Unable to create session sysfs entry for flashnode %d of host%lu\n", + __func__, *idx, ha->host_no); + goto exit_tgt_create; } - /* Wait to ensure all sendtargets are done for min 12 sec wait */ - tmo = ((ha->def_timeout > LOGIN_TOV) && - (ha->def_timeout < LOGIN_TOV * 10) ? - ha->def_timeout : LOGIN_TOV); + fnode_conn = iscsi_create_flashnode_conn(ha->host, fnode_sess, + &qla4xxx_iscsi_transport, 0); + if (!fnode_conn) { + ql4_printk(KERN_ERR, ha, + "%s: Unable to create conn sysfs entry for flashnode %d of host%lu\n", + __func__, *idx, ha->host_no); + goto free_sess; + } - DEBUG2(ql4_printk(KERN_INFO, ha, - "Default time to wait for build ddb %d\n", tmo)); + if (user) { + fnode_sess->flash_state = DEV_DB_NON_PERSISTENT; + } else { + fnode_sess->flash_state = DEV_DB_PERSISTENT; - wtime = jiffies + (HZ * tmo); - do { - if (list_empty(&list_st)) - break; + if (*idx == ha->pri_ddb_idx || *idx == ha->sec_ddb_idx) + fnode_sess->is_boot_target = 1; + else + fnode_sess->is_boot_target = 0; + } - qla4xxx_remove_failed_ddb(ha, &list_st); - schedule_timeout_uninterruptible(HZ / 10); - } while (time_after(wtime, jiffies)); + rc = qla4xxx_copy_from_fwddb_param(fnode_sess, fnode_conn, + fw_ddb_entry); - /* Free up the sendtargets list */ - qla4xxx_free_ddb_list(&list_st); + ql4_printk(KERN_INFO, ha, "%s: sysfs entry %s created\n", + __func__, fnode_sess->dev.kobj.name); - qla4xxx_build_nt_list(ha, &list_nt, is_reset); + ql4_printk(KERN_INFO, ha, "%s: sysfs entry %s created\n", + __func__, fnode_conn->dev.kobj.name); - qla4xxx_free_ddb_list(&list_nt); + return QLA_SUCCESS; - qla4xxx_free_ddb_index(ha); +free_sess: + iscsi_destroy_flashnode_sess(fnode_sess); + +exit_tgt_create: + return QLA_ERROR; } /** - * qla4xxx_wait_login_resp_boot_tgt - Wait for iSCSI boot target login - * response. - * @ha: pointer to adapter structure + * qla4xxx_sysfs_ddb_add - Add new ddb entry in flash + * @shost: pointer to host + * @buf: type of ddb entry (ipv4/ipv6) + * @len: length of buf * - * When the boot entry is normal iSCSI target then DF_BOOT_TGT flag will be - * set in DDB and we will wait for login response of boot targets during - * probe. + * This creates new ddb entry in the flash by finding first free index and + * storing default ddb there. And then create sysfs entry for the new ddb entry. **/ -static void qla4xxx_wait_login_resp_boot_tgt(struct scsi_qla_host *ha) +static int qla4xxx_sysfs_ddb_add(struct Scsi_Host *shost, const char *buf, + int len) { - struct ddb_entry *ddb_entry; + struct scsi_qla_host *ha = to_qla_host(shost); struct dev_db_entry *fw_ddb_entry = NULL; dma_addr_t fw_ddb_entry_dma; - unsigned long wtime; - uint32_t ddb_state; - int max_ddbs, idx, ret; + struct device *dev; + uint16_t idx = 0; + uint16_t max_ddbs = 0; + uint32_t options = 0; + uint32_t rval = QLA_ERROR; + + if (strncasecmp(DEV_TYPE_IPV4, buf, 4) && + strncasecmp(DEV_TYPE_IPV6, buf, 4)) { + DEBUG2(ql4_printk(KERN_ERR, ha, "%s: Invalid portal type\n", + __func__)); + goto exit_ddb_add; + } max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : MAX_DEV_DB_ENTRIES; @@ -5151,76 +5591,1278 @@ static void qla4xxx_wait_login_resp_boot_tgt(struct scsi_qla_host *ha) fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), &fw_ddb_entry_dma, GFP_KERNEL); if (!fw_ddb_entry) { - ql4_printk(KERN_ERR, ha, - "%s: Unable to allocate dma buffer\n", __func__); - goto exit_login_resp; + DEBUG2(ql4_printk(KERN_ERR, ha, + "%s: Unable to allocate dma buffer\n", + __func__)); + goto exit_ddb_add; } - wtime = jiffies + (HZ * BOOT_LOGIN_RESP_TOV); + dev = iscsi_find_flashnode_sess(ha->host, NULL, + qla4xxx_sysfs_ddb_is_non_persistent); + if (dev) { + ql4_printk(KERN_ERR, ha, + "%s: A non-persistent entry %s found\n", + __func__, dev->kobj.name); + goto exit_ddb_add; + } for (idx = 0; idx < max_ddbs; idx++) { - ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx); - if (ddb_entry == NULL) - continue; - - if (test_bit(DF_BOOT_TGT, &ddb_entry->flags)) { - DEBUG2(ql4_printk(KERN_INFO, ha, - "%s: DDB index [%d]\n", __func__, - ddb_entry->fw_ddb_index)); - do { - ret = qla4xxx_get_fwddb_entry(ha, - ddb_entry->fw_ddb_index, - fw_ddb_entry, fw_ddb_entry_dma, - NULL, NULL, &ddb_state, NULL, - NULL, NULL); - if (ret == QLA_ERROR) - goto exit_login_resp; + if (qla4xxx_flashdb_by_index(ha, fw_ddb_entry, + fw_ddb_entry_dma, idx)) + break; + } - if ((ddb_state == DDB_DS_SESSION_ACTIVE) || - (ddb_state == DDB_DS_SESSION_FAILED)) - break; + if (idx == max_ddbs) + goto exit_ddb_add; - schedule_timeout_uninterruptible(HZ); + if (!strncasecmp("ipv6", buf, 4)) + options |= IPV6_DEFAULT_DDB_ENTRY; - } while ((time_after(wtime, jiffies))); + rval = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma); + if (rval == QLA_ERROR) + goto exit_ddb_add; - if (!time_after(wtime, jiffies)) { - DEBUG2(ql4_printk(KERN_INFO, ha, - "%s: Login response wait timer expired\n", - __func__)); - goto exit_login_resp; - } - } - } + rval = qla4xxx_sysfs_ddb_tgt_create(ha, fw_ddb_entry, &idx, 1); -exit_login_resp: +exit_ddb_add: if (fw_ddb_entry) dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry, fw_ddb_entry_dma); + if (rval == QLA_SUCCESS) + return idx; + else + return -EIO; } /** - * qla4xxx_probe_adapter - callback function to probe HBA - * @pdev: pointer to pci_dev structure - * @pci_device_id: pointer to pci_device entry + * qla4xxx_sysfs_ddb_apply - write the target ddb contents to Flash + * @fnode_sess: pointer to session attrs of flash ddb entry + * @fnode_conn: pointer to connection attrs of flash ddb entry * - * This routine will probe for Qlogic 4xxx iSCSI host adapters. - * It returns zero if successful. It also initializes all data necessary for - * the driver. + * This writes the contents of target ddb buffer to Flash with a valid cookie + * value in order to make the ddb entry persistent. **/ -static int qla4xxx_probe_adapter(struct pci_dev *pdev, - const struct pci_device_id *ent) +static int qla4xxx_sysfs_ddb_apply(struct iscsi_bus_flash_session *fnode_sess, + struct iscsi_bus_flash_conn *fnode_conn) { - int ret = -ENODEV, status; - struct Scsi_Host *host; - struct scsi_qla_host *ha; - uint8_t init_retry_count = 0; - char buf[34]; - struct qla4_8xxx_legacy_intr_set *nx_legacy_intr; - uint32_t dev_state; + struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess); + struct scsi_qla_host *ha = to_qla_host(shost); + uint32_t dev_db_start_offset = FLASH_OFFSET_DB_INFO; + struct dev_db_entry *fw_ddb_entry = NULL; + dma_addr_t fw_ddb_entry_dma; + uint32_t options = 0; + int rval = 0; - if (pci_enable_device(pdev)) - return -1; + fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), + &fw_ddb_entry_dma, GFP_KERNEL); + if (!fw_ddb_entry) { + DEBUG2(ql4_printk(KERN_ERR, ha, + "%s: Unable to allocate dma buffer\n", + __func__)); + rval = -ENOMEM; + goto exit_ddb_apply; + } + + if (!strncasecmp(fnode_sess->portal_type, DEV_TYPE_IPV6, 4)) + options |= IPV6_DEFAULT_DDB_ENTRY; + + rval = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma); + if (rval == QLA_ERROR) + goto exit_ddb_apply; + + dev_db_start_offset += (fnode_sess->target_id * + sizeof(*fw_ddb_entry)); + + qla4xxx_copy_to_fwddb_param(fnode_sess, fnode_conn, fw_ddb_entry); + fw_ddb_entry->cookie = DDB_VALID_COOKIE; + + rval = qla4xxx_set_flash(ha, fw_ddb_entry_dma, dev_db_start_offset, + sizeof(*fw_ddb_entry), FLASH_OPT_RMW_COMMIT); + + if (rval == QLA_SUCCESS) { + fnode_sess->flash_state = DEV_DB_PERSISTENT; + ql4_printk(KERN_INFO, ha, + "%s: flash node %u of host %lu written to flash\n", + __func__, fnode_sess->target_id, ha->host_no); + } else { + rval = -EIO; + ql4_printk(KERN_ERR, ha, + "%s: Error while writing flash node %u of host %lu to flash\n", + __func__, fnode_sess->target_id, ha->host_no); + } + +exit_ddb_apply: + if (fw_ddb_entry) + dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), + fw_ddb_entry, fw_ddb_entry_dma); + return rval; +} + +static ssize_t qla4xxx_sysfs_ddb_conn_open(struct scsi_qla_host *ha, + struct dev_db_entry *fw_ddb_entry, + uint16_t idx) +{ + struct dev_db_entry *ddb_entry = NULL; + dma_addr_t ddb_entry_dma; + unsigned long wtime; + uint32_t mbx_sts = 0; + uint32_t state = 0, conn_err = 0; + uint16_t tmo = 0; + int ret = 0; + + ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*ddb_entry), + &ddb_entry_dma, GFP_KERNEL); + if (!ddb_entry) { + DEBUG2(ql4_printk(KERN_ERR, ha, + "%s: Unable to allocate dma buffer\n", + __func__)); + return QLA_ERROR; + } + + memcpy(ddb_entry, fw_ddb_entry, sizeof(*ddb_entry)); + + ret = qla4xxx_set_ddb_entry(ha, idx, ddb_entry_dma, &mbx_sts); + if (ret != QLA_SUCCESS) { + DEBUG2(ql4_printk(KERN_ERR, ha, + "%s: Unable to set ddb entry for index %d\n", + __func__, idx)); + goto exit_ddb_conn_open; + } + + qla4xxx_conn_open(ha, idx); + + /* To ensure that sendtargets is done, wait for at least 12 secs */ + tmo = ((ha->def_timeout > LOGIN_TOV) && + (ha->def_timeout < LOGIN_TOV * 10) ? + ha->def_timeout : LOGIN_TOV); + + DEBUG2(ql4_printk(KERN_INFO, ha, + "Default time to wait for login to ddb %d\n", tmo)); + + wtime = jiffies + (HZ * tmo); + do { + ret = qla4xxx_get_fwddb_entry(ha, idx, NULL, 0, NULL, + NULL, &state, &conn_err, NULL, + NULL); + if (ret == QLA_ERROR) + continue; + + if (state == DDB_DS_NO_CONNECTION_ACTIVE || + state == DDB_DS_SESSION_FAILED) + break; + + schedule_timeout_uninterruptible(HZ / 10); + } while (time_after(wtime, jiffies)); + +exit_ddb_conn_open: + if (ddb_entry) + dma_free_coherent(&ha->pdev->dev, sizeof(*ddb_entry), + ddb_entry, ddb_entry_dma); + return ret; +} + +static int qla4xxx_ddb_login_st(struct scsi_qla_host *ha, + struct dev_db_entry *fw_ddb_entry) +{ + struct qla_ddb_index *ddb_idx, *ddb_idx_tmp; + struct list_head list_nt; + uint16_t ddb_index; + int ret = 0; + + if (test_bit(AF_ST_DISCOVERY_IN_PROGRESS, &ha->flags)) { + ql4_printk(KERN_WARNING, ha, + "%s: A discovery already in progress!\n", __func__); + return QLA_ERROR; + } + + INIT_LIST_HEAD(&list_nt); + + set_bit(AF_ST_DISCOVERY_IN_PROGRESS, &ha->flags); + + ret = qla4xxx_get_ddb_index(ha, &ddb_index); + if (ret == QLA_ERROR) + goto exit_login_st_clr_bit; + + ret = qla4xxx_sysfs_ddb_conn_open(ha, fw_ddb_entry, ddb_index); + if (ret == QLA_ERROR) + goto exit_login_st; + + qla4xxx_build_new_nt_list(ha, &list_nt); + + list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, &list_nt, list) { + list_del_init(&ddb_idx->list); + qla4xxx_clear_ddb_entry(ha, ddb_idx->fw_ddb_idx); + vfree(ddb_idx); + } + +exit_login_st: + if (qla4xxx_clear_ddb_entry(ha, ddb_index) == QLA_ERROR) { + ql4_printk(KERN_ERR, ha, + "Unable to clear DDB index = 0x%x\n", ddb_index); + } + + clear_bit(ddb_index, ha->ddb_idx_map); + +exit_login_st_clr_bit: + clear_bit(AF_ST_DISCOVERY_IN_PROGRESS, &ha->flags); + return ret; +} + +static int qla4xxx_ddb_login_nt(struct scsi_qla_host *ha, + struct dev_db_entry *fw_ddb_entry, + uint16_t idx) +{ + int ret = QLA_ERROR; + + ret = qla4xxx_is_session_exists(ha, fw_ddb_entry); + if (ret != QLA_SUCCESS) + ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, RESET_ADAPTER, + idx); + else + ret = -EPERM; + + return ret; +} + +/** + * qla4xxx_sysfs_ddb_login - Login to the specified target + * @fnode_sess: pointer to session attrs of flash ddb entry + * @fnode_conn: pointer to connection attrs of flash ddb entry + * + * This logs in to the specified target + **/ +static int qla4xxx_sysfs_ddb_login(struct iscsi_bus_flash_session *fnode_sess, + struct iscsi_bus_flash_conn *fnode_conn) +{ + struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess); + struct scsi_qla_host *ha = to_qla_host(shost); + struct dev_db_entry *fw_ddb_entry = NULL; + dma_addr_t fw_ddb_entry_dma; + uint32_t options = 0; + int ret = 0; + + if (fnode_sess->flash_state == DEV_DB_NON_PERSISTENT) { + ql4_printk(KERN_ERR, ha, + "%s: Target info is not persistent\n", __func__); + ret = -EIO; + goto exit_ddb_login; + } + + fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), + &fw_ddb_entry_dma, GFP_KERNEL); + if (!fw_ddb_entry) { + DEBUG2(ql4_printk(KERN_ERR, ha, + "%s: Unable to allocate dma buffer\n", + __func__)); + ret = -ENOMEM; + goto exit_ddb_login; + } + + if (!strncasecmp(fnode_sess->portal_type, DEV_TYPE_IPV6, 4)) + options |= IPV6_DEFAULT_DDB_ENTRY; + + ret = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma); + if (ret == QLA_ERROR) + goto exit_ddb_login; + + qla4xxx_copy_to_fwddb_param(fnode_sess, fnode_conn, fw_ddb_entry); + fw_ddb_entry->cookie = DDB_VALID_COOKIE; + + if (strlen((char *)fw_ddb_entry->iscsi_name) == 0) + ret = qla4xxx_ddb_login_st(ha, fw_ddb_entry); + else + ret = qla4xxx_ddb_login_nt(ha, fw_ddb_entry, + fnode_sess->target_id); + + if (ret > 0) + ret = -EIO; + +exit_ddb_login: + if (fw_ddb_entry) + dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), + fw_ddb_entry, fw_ddb_entry_dma); + return ret; +} + +/** + * qla4xxx_sysfs_ddb_logout_sid - Logout session for the specified target + * @cls_sess: pointer to session to be logged out + * + * This performs session log out from the specified target + **/ +static int qla4xxx_sysfs_ddb_logout_sid(struct iscsi_cls_session *cls_sess) +{ + struct iscsi_session *sess; + struct ddb_entry *ddb_entry = NULL; + struct scsi_qla_host *ha; + struct dev_db_entry *fw_ddb_entry = NULL; + dma_addr_t fw_ddb_entry_dma; + unsigned long flags; + unsigned long wtime; + uint32_t ddb_state; + int options; + int ret = 0; + + sess = cls_sess->dd_data; + ddb_entry = sess->dd_data; + ha = ddb_entry->ha; + + if (ddb_entry->ddb_type != FLASH_DDB) { + ql4_printk(KERN_ERR, ha, "%s: Not a flash node session\n", + __func__); + ret = -ENXIO; + goto exit_ddb_logout; + } + + options = LOGOUT_OPTION_CLOSE_SESSION; + if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) == QLA_ERROR) { + ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", __func__); + ret = -EIO; + goto exit_ddb_logout; + } + + fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), + &fw_ddb_entry_dma, GFP_KERNEL); + if (!fw_ddb_entry) { + ql4_printk(KERN_ERR, ha, + "%s: Unable to allocate dma buffer\n", __func__); + ret = -ENOMEM; + goto exit_ddb_logout; + } + + wtime = jiffies + (HZ * LOGOUT_TOV); + do { + ret = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, + fw_ddb_entry, fw_ddb_entry_dma, + NULL, NULL, &ddb_state, NULL, + NULL, NULL); + if (ret == QLA_ERROR) + goto ddb_logout_clr_sess; + + if ((ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) || + (ddb_state == DDB_DS_SESSION_FAILED)) + goto ddb_logout_clr_sess; + + schedule_timeout_uninterruptible(HZ); + } while ((time_after(wtime, jiffies))); + +ddb_logout_clr_sess: + qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index); + /* + * we have decremented the reference count of the driver + * when we setup the session to have the driver unload + * to be seamless without actually destroying the + * session + **/ + try_module_get(qla4xxx_iscsi_transport.owner); + iscsi_destroy_endpoint(ddb_entry->conn->ep); + + spin_lock_irqsave(&ha->hardware_lock, flags); + qla4xxx_free_ddb(ha, ddb_entry); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + iscsi_session_teardown(ddb_entry->sess); + + ret = QLA_SUCCESS; + +exit_ddb_logout: + if (fw_ddb_entry) + dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), + fw_ddb_entry, fw_ddb_entry_dma); + return ret; +} + +/** + * qla4xxx_sysfs_ddb_logout - Logout from the specified target + * @fnode_sess: pointer to session attrs of flash ddb entry + * @fnode_conn: pointer to connection attrs of flash ddb entry + * + * This performs log out from the specified target + **/ +static int qla4xxx_sysfs_ddb_logout(struct iscsi_bus_flash_session *fnode_sess, + struct iscsi_bus_flash_conn *fnode_conn) +{ + struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess); + struct scsi_qla_host *ha = to_qla_host(shost); + struct ql4_tuple_ddb *flash_tddb = NULL; + struct ql4_tuple_ddb *tmp_tddb = NULL; + struct dev_db_entry *fw_ddb_entry = NULL; + struct ddb_entry *ddb_entry = NULL; + dma_addr_t fw_ddb_dma; + uint32_t next_idx = 0; + uint32_t state = 0, conn_err = 0; + uint16_t conn_id = 0; + int idx, index; + int status, ret = 0; + + fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL, + &fw_ddb_dma); + if (fw_ddb_entry == NULL) { + ql4_printk(KERN_ERR, ha, "%s:Out of memory\n", __func__); + ret = -ENOMEM; + goto exit_ddb_logout; + } + + flash_tddb = vzalloc(sizeof(*flash_tddb)); + if (!flash_tddb) { + ql4_printk(KERN_WARNING, ha, + "%s:Memory Allocation failed.\n", __func__); + ret = -ENOMEM; + goto exit_ddb_logout; + } + + tmp_tddb = vzalloc(sizeof(*tmp_tddb)); + if (!tmp_tddb) { + ql4_printk(KERN_WARNING, ha, + "%s:Memory Allocation failed.\n", __func__); + ret = -ENOMEM; + goto exit_ddb_logout; + } + + if (!fnode_sess->targetname) { + ql4_printk(KERN_ERR, ha, + "%s:Cannot logout from SendTarget entry\n", + __func__); + ret = -EPERM; + goto exit_ddb_logout; + } + + if (fnode_sess->is_boot_target) { + ql4_printk(KERN_ERR, ha, + "%s: Logout from boot target entry is not permitted.\n", + __func__); + ret = -EPERM; + goto exit_ddb_logout; + } + + strncpy(flash_tddb->iscsi_name, fnode_sess->targetname, + ISCSI_NAME_SIZE); + + if (!strncmp(fnode_sess->portal_type, DEV_TYPE_IPV6, 4)) + sprintf(flash_tddb->ip_addr, "%pI6", fnode_conn->ipaddress); + else + sprintf(flash_tddb->ip_addr, "%pI4", fnode_conn->ipaddress); + + flash_tddb->tpgt = fnode_sess->tpgt; + flash_tddb->port = fnode_conn->port; + + COPY_ISID(flash_tddb->isid, fnode_sess->isid); + + for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) { + ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx); + if (ddb_entry == NULL) + continue; + + if (ddb_entry->ddb_type != FLASH_DDB) + continue; + + index = ddb_entry->sess->target_id; + status = qla4xxx_get_fwddb_entry(ha, index, fw_ddb_entry, + fw_ddb_dma, NULL, &next_idx, + &state, &conn_err, NULL, + &conn_id); + if (status == QLA_ERROR) { + ret = -ENOMEM; + break; + } + + qla4xxx_convert_param_ddb(fw_ddb_entry, tmp_tddb, NULL); + + status = qla4xxx_compare_tuple_ddb(ha, flash_tddb, tmp_tddb, + true); + if (status == QLA_SUCCESS) { + ret = qla4xxx_sysfs_ddb_logout_sid(ddb_entry->sess); + break; + } + } + + if (idx == MAX_DDB_ENTRIES) + ret = -ESRCH; + +exit_ddb_logout: + if (flash_tddb) + vfree(flash_tddb); + if (tmp_tddb) + vfree(tmp_tddb); + if (fw_ddb_entry) + dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma); + + return ret; +} + +static int +qla4xxx_sysfs_ddb_get_param(struct iscsi_bus_flash_session *fnode_sess, + int param, char *buf) +{ + struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess); + struct scsi_qla_host *ha = to_qla_host(shost); + struct iscsi_bus_flash_conn *fnode_conn; + struct ql4_chap_table chap_tbl; + struct device *dev; + int parent_type, parent_index = 0xffff; + int rc = 0; + + dev = iscsi_find_flashnode_conn(fnode_sess, NULL, + iscsi_is_flashnode_conn_dev); + if (!dev) + return -EIO; + + fnode_conn = iscsi_dev_to_flash_conn(dev); + + switch (param) { + case ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6: + rc = sprintf(buf, "%u\n", fnode_conn->is_fw_assigned_ipv6); + break; + case ISCSI_FLASHNODE_PORTAL_TYPE: + rc = sprintf(buf, "%s\n", fnode_sess->portal_type); + break; + case ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE: + rc = sprintf(buf, "%u\n", fnode_sess->auto_snd_tgt_disable); + break; + case ISCSI_FLASHNODE_DISCOVERY_SESS: + rc = sprintf(buf, "%u\n", fnode_sess->discovery_sess); + break; + case ISCSI_FLASHNODE_ENTRY_EN: + rc = sprintf(buf, "%u\n", fnode_sess->entry_state); + break; + case ISCSI_FLASHNODE_HDR_DGST_EN: + rc = sprintf(buf, "%u\n", fnode_conn->hdrdgst_en); + break; + case ISCSI_FLASHNODE_DATA_DGST_EN: + rc = sprintf(buf, "%u\n", fnode_conn->datadgst_en); + break; + case ISCSI_FLASHNODE_IMM_DATA_EN: + rc = sprintf(buf, "%u\n", fnode_sess->imm_data_en); + break; + case ISCSI_FLASHNODE_INITIAL_R2T_EN: + rc = sprintf(buf, "%u\n", fnode_sess->initial_r2t_en); + break; + case ISCSI_FLASHNODE_DATASEQ_INORDER: + rc = sprintf(buf, "%u\n", fnode_sess->dataseq_inorder_en); + break; + case ISCSI_FLASHNODE_PDU_INORDER: + rc = sprintf(buf, "%u\n", fnode_sess->pdu_inorder_en); + break; + case ISCSI_FLASHNODE_CHAP_AUTH_EN: + rc = sprintf(buf, "%u\n", fnode_sess->chap_auth_en); + break; + case ISCSI_FLASHNODE_SNACK_REQ_EN: + rc = sprintf(buf, "%u\n", fnode_conn->snack_req_en); + break; + case ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN: + rc = sprintf(buf, "%u\n", fnode_sess->discovery_logout_en); + break; + case ISCSI_FLASHNODE_BIDI_CHAP_EN: + rc = sprintf(buf, "%u\n", fnode_sess->bidi_chap_en); + break; + case ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL: + rc = sprintf(buf, "%u\n", fnode_sess->discovery_auth_optional); + break; + case ISCSI_FLASHNODE_ERL: + rc = sprintf(buf, "%u\n", fnode_sess->erl); + break; + case ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT: + rc = sprintf(buf, "%u\n", fnode_conn->tcp_timestamp_stat); + break; + case ISCSI_FLASHNODE_TCP_NAGLE_DISABLE: + rc = sprintf(buf, "%u\n", fnode_conn->tcp_nagle_disable); + break; + case ISCSI_FLASHNODE_TCP_WSF_DISABLE: + rc = sprintf(buf, "%u\n", fnode_conn->tcp_wsf_disable); + break; + case ISCSI_FLASHNODE_TCP_TIMER_SCALE: + rc = sprintf(buf, "%u\n", fnode_conn->tcp_timer_scale); + break; + case ISCSI_FLASHNODE_TCP_TIMESTAMP_EN: + rc = sprintf(buf, "%u\n", fnode_conn->tcp_timestamp_en); + break; + case ISCSI_FLASHNODE_IP_FRAG_DISABLE: + rc = sprintf(buf, "%u\n", fnode_conn->fragment_disable); + break; + case ISCSI_FLASHNODE_MAX_RECV_DLENGTH: + rc = sprintf(buf, "%u\n", fnode_conn->max_recv_dlength); + break; + case ISCSI_FLASHNODE_MAX_XMIT_DLENGTH: + rc = sprintf(buf, "%u\n", fnode_conn->max_xmit_dlength); + break; + case ISCSI_FLASHNODE_FIRST_BURST: + rc = sprintf(buf, "%u\n", fnode_sess->first_burst); + break; + case ISCSI_FLASHNODE_DEF_TIME2WAIT: + rc = sprintf(buf, "%u\n", fnode_sess->time2wait); + break; + case ISCSI_FLASHNODE_DEF_TIME2RETAIN: + rc = sprintf(buf, "%u\n", fnode_sess->time2retain); + break; + case ISCSI_FLASHNODE_MAX_R2T: + rc = sprintf(buf, "%u\n", fnode_sess->max_r2t); + break; + case ISCSI_FLASHNODE_KEEPALIVE_TMO: + rc = sprintf(buf, "%u\n", fnode_conn->keepalive_timeout); + break; + case ISCSI_FLASHNODE_ISID: + rc = sprintf(buf, "%02x%02x%02x%02x%02x%02x\n", + fnode_sess->isid[0], fnode_sess->isid[1], + fnode_sess->isid[2], fnode_sess->isid[3], + fnode_sess->isid[4], fnode_sess->isid[5]); + break; + case ISCSI_FLASHNODE_TSID: + rc = sprintf(buf, "%u\n", fnode_sess->tsid); + break; + case ISCSI_FLASHNODE_PORT: + rc = sprintf(buf, "%d\n", fnode_conn->port); + break; + case ISCSI_FLASHNODE_MAX_BURST: + rc = sprintf(buf, "%u\n", fnode_sess->max_burst); + break; + case ISCSI_FLASHNODE_DEF_TASKMGMT_TMO: + rc = sprintf(buf, "%u\n", + fnode_sess->default_taskmgmt_timeout); + break; + case ISCSI_FLASHNODE_IPADDR: + if (!strncmp(fnode_sess->portal_type, DEV_TYPE_IPV6, 4)) + rc = sprintf(buf, "%pI6\n", fnode_conn->ipaddress); + else + rc = sprintf(buf, "%pI4\n", fnode_conn->ipaddress); + break; + case ISCSI_FLASHNODE_ALIAS: + if (fnode_sess->targetalias) + rc = sprintf(buf, "%s\n", fnode_sess->targetalias); + else + rc = sprintf(buf, "\n"); + break; + case ISCSI_FLASHNODE_REDIRECT_IPADDR: + if (!strncmp(fnode_sess->portal_type, DEV_TYPE_IPV6, 4)) + rc = sprintf(buf, "%pI6\n", + fnode_conn->redirect_ipaddr); + else + rc = sprintf(buf, "%pI4\n", + fnode_conn->redirect_ipaddr); + break; + case ISCSI_FLASHNODE_MAX_SEGMENT_SIZE: + rc = sprintf(buf, "%u\n", fnode_conn->max_segment_size); + break; + case ISCSI_FLASHNODE_LOCAL_PORT: + rc = sprintf(buf, "%u\n", fnode_conn->local_port); + break; + case ISCSI_FLASHNODE_IPV4_TOS: + rc = sprintf(buf, "%u\n", fnode_conn->ipv4_tos); + break; + case ISCSI_FLASHNODE_IPV6_TC: + if (!strncmp(fnode_sess->portal_type, DEV_TYPE_IPV6, 4)) + rc = sprintf(buf, "%u\n", + fnode_conn->ipv6_traffic_class); + else + rc = sprintf(buf, "\n"); + break; + case ISCSI_FLASHNODE_IPV6_FLOW_LABEL: + rc = sprintf(buf, "%u\n", fnode_conn->ipv6_flow_label); + break; + case ISCSI_FLASHNODE_LINK_LOCAL_IPV6: + if (!strncmp(fnode_sess->portal_type, DEV_TYPE_IPV6, 4)) + rc = sprintf(buf, "%pI6\n", + fnode_conn->link_local_ipv6_addr); + else + rc = sprintf(buf, "\n"); + break; + case ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX: + if ((fnode_sess->discovery_parent_idx) >= 0 && + (fnode_sess->discovery_parent_idx < MAX_DDB_ENTRIES)) + parent_index = fnode_sess->discovery_parent_idx; + + rc = sprintf(buf, "%u\n", parent_index); + break; + case ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE: + if (fnode_sess->discovery_parent_type == DDB_ISNS) + parent_type = ISCSI_DISC_PARENT_ISNS; + else if (fnode_sess->discovery_parent_type == DDB_NO_LINK) + parent_type = ISCSI_DISC_PARENT_UNKNOWN; + else if (fnode_sess->discovery_parent_type >= 0 && + fnode_sess->discovery_parent_type < MAX_DDB_ENTRIES) + parent_type = ISCSI_DISC_PARENT_SENDTGT; + else + parent_type = ISCSI_DISC_PARENT_UNKNOWN; + + rc = sprintf(buf, "%s\n", + iscsi_get_discovery_parent_name(parent_type)); + break; + case ISCSI_FLASHNODE_NAME: + if (fnode_sess->targetname) + rc = sprintf(buf, "%s\n", fnode_sess->targetname); + else + rc = sprintf(buf, "\n"); + break; + case ISCSI_FLASHNODE_TPGT: + rc = sprintf(buf, "%u\n", fnode_sess->tpgt); + break; + case ISCSI_FLASHNODE_TCP_XMIT_WSF: + rc = sprintf(buf, "%u\n", fnode_conn->tcp_xmit_wsf); + break; + case ISCSI_FLASHNODE_TCP_RECV_WSF: + rc = sprintf(buf, "%u\n", fnode_conn->tcp_recv_wsf); + break; + case ISCSI_FLASHNODE_CHAP_OUT_IDX: + rc = sprintf(buf, "%u\n", fnode_sess->chap_out_idx); + break; + case ISCSI_FLASHNODE_USERNAME: + if (fnode_sess->chap_auth_en) { + qla4xxx_get_uni_chap_at_index(ha, + chap_tbl.name, + chap_tbl.secret, + fnode_sess->chap_out_idx); + rc = sprintf(buf, "%s\n", chap_tbl.name); + } else { + rc = sprintf(buf, "\n"); + } + break; + case ISCSI_FLASHNODE_PASSWORD: + if (fnode_sess->chap_auth_en) { + qla4xxx_get_uni_chap_at_index(ha, + chap_tbl.name, + chap_tbl.secret, + fnode_sess->chap_out_idx); + rc = sprintf(buf, "%s\n", chap_tbl.secret); + } else { + rc = sprintf(buf, "\n"); + } + break; + case ISCSI_FLASHNODE_STATSN: + rc = sprintf(buf, "%u\n", fnode_conn->statsn); + break; + case ISCSI_FLASHNODE_EXP_STATSN: + rc = sprintf(buf, "%u\n", fnode_conn->exp_statsn); + break; + case ISCSI_FLASHNODE_IS_BOOT_TGT: + rc = sprintf(buf, "%u\n", fnode_sess->is_boot_target); + break; + default: + rc = -ENOSYS; + break; + } + return rc; +} + +/** + * qla4xxx_sysfs_ddb_set_param - Set parameter for firmware DDB entry + * @fnode_sess: pointer to session attrs of flash ddb entry + * @fnode_conn: pointer to connection attrs of flash ddb entry + * @data: Parameters and their values to update + * @len: len of data + * + * This sets the parameter of flash ddb entry and writes them to flash + **/ +static int +qla4xxx_sysfs_ddb_set_param(struct iscsi_bus_flash_session *fnode_sess, + struct iscsi_bus_flash_conn *fnode_conn, + void *data, int len) +{ + struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess); + struct scsi_qla_host *ha = to_qla_host(shost); + struct dev_db_entry *fw_ddb_entry = NULL; + struct iscsi_flashnode_param_info *fnode_param; + struct nlattr *attr; + int rc = QLA_ERROR; + uint32_t rem = len; + + fw_ddb_entry = kzalloc(sizeof(*fw_ddb_entry), GFP_KERNEL); + if (!fw_ddb_entry) { + DEBUG2(ql4_printk(KERN_ERR, ha, + "%s: Unable to allocate ddb buffer\n", + __func__)); + return -ENOMEM; + } + + nla_for_each_attr(attr, data, len, rem) { + fnode_param = nla_data(attr); + + switch (fnode_param->param) { + case ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6: + fnode_conn->is_fw_assigned_ipv6 = fnode_param->value[0]; + break; + case ISCSI_FLASHNODE_PORTAL_TYPE: + memcpy(fnode_sess->portal_type, fnode_param->value, + strlen(fnode_sess->portal_type)); + break; + case ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE: + fnode_sess->auto_snd_tgt_disable = + fnode_param->value[0]; + break; + case ISCSI_FLASHNODE_DISCOVERY_SESS: + fnode_sess->discovery_sess = fnode_param->value[0]; + break; + case ISCSI_FLASHNODE_ENTRY_EN: + fnode_sess->entry_state = fnode_param->value[0]; + break; + case ISCSI_FLASHNODE_HDR_DGST_EN: + fnode_conn->hdrdgst_en = fnode_param->value[0]; + break; + case ISCSI_FLASHNODE_DATA_DGST_EN: + fnode_conn->datadgst_en = fnode_param->value[0]; + break; + case ISCSI_FLASHNODE_IMM_DATA_EN: + fnode_sess->imm_data_en = fnode_param->value[0]; + break; + case ISCSI_FLASHNODE_INITIAL_R2T_EN: + fnode_sess->initial_r2t_en = fnode_param->value[0]; + break; + case ISCSI_FLASHNODE_DATASEQ_INORDER: + fnode_sess->dataseq_inorder_en = fnode_param->value[0]; + break; + case ISCSI_FLASHNODE_PDU_INORDER: + fnode_sess->pdu_inorder_en = fnode_param->value[0]; + break; + case ISCSI_FLASHNODE_CHAP_AUTH_EN: + fnode_sess->chap_auth_en = fnode_param->value[0]; + break; + case ISCSI_FLASHNODE_SNACK_REQ_EN: + fnode_conn->snack_req_en = fnode_param->value[0]; + break; + case ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN: + fnode_sess->discovery_logout_en = fnode_param->value[0]; + break; + case ISCSI_FLASHNODE_BIDI_CHAP_EN: + fnode_sess->bidi_chap_en = fnode_param->value[0]; + break; + case ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL: + fnode_sess->discovery_auth_optional = + fnode_param->value[0]; + break; + case ISCSI_FLASHNODE_ERL: + fnode_sess->erl = fnode_param->value[0]; + break; + case ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT: + fnode_conn->tcp_timestamp_stat = fnode_param->value[0]; + break; + case ISCSI_FLASHNODE_TCP_NAGLE_DISABLE: + fnode_conn->tcp_nagle_disable = fnode_param->value[0]; + break; + case ISCSI_FLASHNODE_TCP_WSF_DISABLE: + fnode_conn->tcp_wsf_disable = fnode_param->value[0]; + break; + case ISCSI_FLASHNODE_TCP_TIMER_SCALE: + fnode_conn->tcp_timer_scale = fnode_param->value[0]; + break; + case ISCSI_FLASHNODE_TCP_TIMESTAMP_EN: + fnode_conn->tcp_timestamp_en = fnode_param->value[0]; + break; + case ISCSI_FLASHNODE_IP_FRAG_DISABLE: + fnode_conn->fragment_disable = fnode_param->value[0]; + break; + case ISCSI_FLASHNODE_MAX_RECV_DLENGTH: + fnode_conn->max_recv_dlength = + *(unsigned *)fnode_param->value; + break; + case ISCSI_FLASHNODE_MAX_XMIT_DLENGTH: + fnode_conn->max_xmit_dlength = + *(unsigned *)fnode_param->value; + break; + case ISCSI_FLASHNODE_FIRST_BURST: + fnode_sess->first_burst = + *(unsigned *)fnode_param->value; + break; + case ISCSI_FLASHNODE_DEF_TIME2WAIT: + fnode_sess->time2wait = *(uint16_t *)fnode_param->value; + break; + case ISCSI_FLASHNODE_DEF_TIME2RETAIN: + fnode_sess->time2retain = + *(uint16_t *)fnode_param->value; + break; + case ISCSI_FLASHNODE_MAX_R2T: + fnode_sess->max_r2t = + *(uint16_t *)fnode_param->value; + break; + case ISCSI_FLASHNODE_KEEPALIVE_TMO: + fnode_conn->keepalive_timeout = + *(uint16_t *)fnode_param->value; + break; + case ISCSI_FLASHNODE_ISID: + memcpy(fnode_sess->isid, fnode_param->value, + sizeof(fnode_sess->isid)); + break; + case ISCSI_FLASHNODE_TSID: + fnode_sess->tsid = *(uint16_t *)fnode_param->value; + break; + case ISCSI_FLASHNODE_PORT: + fnode_conn->port = *(uint16_t *)fnode_param->value; + break; + case ISCSI_FLASHNODE_MAX_BURST: + fnode_sess->max_burst = *(unsigned *)fnode_param->value; + break; + case ISCSI_FLASHNODE_DEF_TASKMGMT_TMO: + fnode_sess->default_taskmgmt_timeout = + *(uint16_t *)fnode_param->value; + break; + case ISCSI_FLASHNODE_IPADDR: + memcpy(fnode_conn->ipaddress, fnode_param->value, + IPv6_ADDR_LEN); + break; + case ISCSI_FLASHNODE_ALIAS: + rc = iscsi_switch_str_param(&fnode_sess->targetalias, + (char *)fnode_param->value); + break; + case ISCSI_FLASHNODE_REDIRECT_IPADDR: + memcpy(fnode_conn->redirect_ipaddr, fnode_param->value, + IPv6_ADDR_LEN); + break; + case ISCSI_FLASHNODE_MAX_SEGMENT_SIZE: + fnode_conn->max_segment_size = + *(unsigned *)fnode_param->value; + break; + case ISCSI_FLASHNODE_LOCAL_PORT: + fnode_conn->local_port = + *(uint16_t *)fnode_param->value; + break; + case ISCSI_FLASHNODE_IPV4_TOS: + fnode_conn->ipv4_tos = fnode_param->value[0]; + break; + case ISCSI_FLASHNODE_IPV6_TC: + fnode_conn->ipv6_traffic_class = fnode_param->value[0]; + break; + case ISCSI_FLASHNODE_IPV6_FLOW_LABEL: + fnode_conn->ipv6_flow_label = fnode_param->value[0]; + break; + case ISCSI_FLASHNODE_NAME: + rc = iscsi_switch_str_param(&fnode_sess->targetname, + (char *)fnode_param->value); + break; + case ISCSI_FLASHNODE_TPGT: + fnode_sess->tpgt = *(uint16_t *)fnode_param->value; + break; + case ISCSI_FLASHNODE_LINK_LOCAL_IPV6: + memcpy(fnode_conn->link_local_ipv6_addr, + fnode_param->value, IPv6_ADDR_LEN); + break; + case ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE: + fnode_sess->discovery_parent_type = + *(uint16_t *)fnode_param->value; + break; + case ISCSI_FLASHNODE_TCP_XMIT_WSF: + fnode_conn->tcp_xmit_wsf = + *(uint8_t *)fnode_param->value; + break; + case ISCSI_FLASHNODE_TCP_RECV_WSF: + fnode_conn->tcp_recv_wsf = + *(uint8_t *)fnode_param->value; + break; + case ISCSI_FLASHNODE_STATSN: + fnode_conn->statsn = *(uint32_t *)fnode_param->value; + break; + case ISCSI_FLASHNODE_EXP_STATSN: + fnode_conn->exp_statsn = + *(uint32_t *)fnode_param->value; + break; + default: + ql4_printk(KERN_ERR, ha, + "%s: No such sysfs attribute\n", __func__); + rc = -ENOSYS; + goto exit_set_param; + } + } + + rc = qla4xxx_sysfs_ddb_apply(fnode_sess, fnode_conn); + +exit_set_param: + return rc; +} + +/** + * qla4xxx_sysfs_ddb_delete - Delete firmware DDB entry + * @fnode_sess: pointer to session attrs of flash ddb entry + * + * This invalidates the flash ddb entry at the given index + **/ +static int qla4xxx_sysfs_ddb_delete(struct iscsi_bus_flash_session *fnode_sess) +{ + struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess); + struct scsi_qla_host *ha = to_qla_host(shost); + uint32_t dev_db_start_offset; + uint32_t dev_db_end_offset; + struct dev_db_entry *fw_ddb_entry = NULL; + dma_addr_t fw_ddb_entry_dma; + uint16_t *ddb_cookie = NULL; + int target_id; + int rc = 0; + + if (!fnode_sess) { + rc = -EINVAL; + goto exit_ddb_del; + } + + if (fnode_sess->is_boot_target) { + rc = -EPERM; + DEBUG2(ql4_printk(KERN_ERR, ha, + "%s: Deletion of boot target entry is not permitted.\n", + __func__)); + goto exit_ddb_del; + } + + if (fnode_sess->flash_state == DEV_DB_NON_PERSISTENT) + goto sysfs_ddb_del; + + ddb_cookie = dma_alloc_coherent(&ha->pdev->dev, sizeof(*ddb_cookie), + &fw_ddb_entry_dma, GFP_KERNEL); + if (!ddb_cookie) { + rc = -ENOMEM; + DEBUG2(ql4_printk(KERN_ERR, ha, + "%s: Unable to allocate dma buffer\n", + __func__)); + goto exit_ddb_del; + } + + if (is_qla40XX(ha)) { + dev_db_start_offset = FLASH_OFFSET_DB_INFO; + } else { + dev_db_start_offset = FLASH_RAW_ACCESS_ADDR + + (ha->hw.flt_region_ddb << 2); + /* flt_ddb_size is DDB table size for both ports + * so divide it by 2 to calculate the offset for second port + */ + if (ha->port_num == 1) + dev_db_start_offset += (ha->hw.flt_ddb_size / 2); + } + + dev_db_end_offset = dev_db_start_offset + (ha->hw.flt_ddb_size / 2); + dev_db_start_offset += (fnode_sess->target_id * sizeof(*fw_ddb_entry)); + dev_db_start_offset += (void *)&(fw_ddb_entry->cookie) - + (void *)fw_ddb_entry; + + DEBUG2(ql4_printk(KERN_ERR, ha, "%s: start offset=%u, end offset=%u\n", + __func__, dev_db_start_offset, dev_db_end_offset)); + + if (dev_db_start_offset > dev_db_end_offset) { + rc = -EIO; + DEBUG2(ql4_printk(KERN_ERR, ha, "%s:Invalid DDB index %u\n", + __func__, fnode_sess->target_id)); + goto exit_ddb_del; + } + + /* invalidate the cookie */ + *ddb_cookie = 0xFFEE; + qla4xxx_set_flash(ha, fw_ddb_entry_dma, dev_db_start_offset, + sizeof(*ddb_cookie), FLASH_OPT_RMW_COMMIT); + +sysfs_ddb_del: + target_id = fnode_sess->target_id; + iscsi_destroy_flashnode_sess(fnode_sess); + ql4_printk(KERN_INFO, ha, + "%s: session and conn entries for flashnode %u of host %lu deleted\n", + __func__, target_id, ha->host_no); +exit_ddb_del: + if (ddb_cookie) + dma_free_coherent(&ha->pdev->dev, sizeof(*ddb_cookie), + ddb_cookie, fw_ddb_entry_dma); + return rc; +} + +/** + * qla4xxx_sysfs_ddb_export - Create sysfs entries for firmware DDBs + * @ha: pointer to adapter structure + * + * Export the firmware DDB for all send targets and normal targets to sysfs. + **/ +static int qla4xxx_sysfs_ddb_export(struct scsi_qla_host *ha) +{ + struct dev_db_entry *fw_ddb_entry = NULL; + dma_addr_t fw_ddb_entry_dma; + uint16_t max_ddbs; + uint16_t idx = 0; + int ret = QLA_SUCCESS; + + fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, + sizeof(*fw_ddb_entry), + &fw_ddb_entry_dma, GFP_KERNEL); + if (!fw_ddb_entry) { + DEBUG2(ql4_printk(KERN_ERR, ha, + "%s: Unable to allocate dma buffer\n", + __func__)); + return -ENOMEM; + } + + max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : + MAX_DEV_DB_ENTRIES; + + for (idx = 0; idx < max_ddbs; idx++) { + if (qla4xxx_flashdb_by_index(ha, fw_ddb_entry, fw_ddb_entry_dma, + idx)) + continue; + + ret = qla4xxx_sysfs_ddb_tgt_create(ha, fw_ddb_entry, &idx, 0); + if (ret) { + ret = -EIO; + break; + } + } + + dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry, + fw_ddb_entry_dma); + + return ret; +} + +static void qla4xxx_sysfs_ddb_remove(struct scsi_qla_host *ha) +{ + iscsi_destroy_all_flashnode(ha->host); +} + +/** + * qla4xxx_build_ddb_list - Build ddb list and setup sessions + * @ha: pointer to adapter structure + * @is_reset: Is this init path or reset path + * + * Create a list of sendtargets (st) from firmware DDBs, issue send targets + * using connection open, then create the list of normal targets (nt) + * from firmware DDBs. Based on the list of nt setup session and connection + * objects. + **/ +void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset) +{ + uint16_t tmo = 0; + struct list_head list_st, list_nt; + struct qla_ddb_index *st_ddb_idx, *st_ddb_idx_tmp; + unsigned long wtime; + + if (!test_bit(AF_LINK_UP, &ha->flags)) { + set_bit(AF_BUILD_DDB_LIST, &ha->flags); + ha->is_reset = is_reset; + return; + } + + INIT_LIST_HEAD(&list_st); + INIT_LIST_HEAD(&list_nt); + + qla4xxx_build_st_list(ha, &list_st); + + /* Before issuing conn open mbox, ensure all IPs states are configured + * Note, conn open fails if IPs are not configured + */ + qla4xxx_wait_for_ip_configuration(ha); + + /* Go thru the STs and fire the sendtargets by issuing conn open mbx */ + list_for_each_entry_safe(st_ddb_idx, st_ddb_idx_tmp, &list_st, list) { + qla4xxx_conn_open(ha, st_ddb_idx->fw_ddb_idx); + } + + /* Wait to ensure all sendtargets are done for min 12 sec wait */ + tmo = ((ha->def_timeout > LOGIN_TOV) && + (ha->def_timeout < LOGIN_TOV * 10) ? + ha->def_timeout : LOGIN_TOV); + + DEBUG2(ql4_printk(KERN_INFO, ha, + "Default time to wait for build ddb %d\n", tmo)); + + wtime = jiffies + (HZ * tmo); + do { + if (list_empty(&list_st)) + break; + + qla4xxx_remove_failed_ddb(ha, &list_st); + schedule_timeout_uninterruptible(HZ / 10); + } while (time_after(wtime, jiffies)); + + /* Free up the sendtargets list */ + qla4xxx_free_ddb_list(&list_st); + + qla4xxx_build_nt_list(ha, &list_nt, is_reset); + + qla4xxx_free_ddb_list(&list_nt); + + qla4xxx_free_ddb_index(ha); +} + +/** + * qla4xxx_wait_login_resp_boot_tgt - Wait for iSCSI boot target login + * response. + * @ha: pointer to adapter structure + * + * When the boot entry is normal iSCSI target then DF_BOOT_TGT flag will be + * set in DDB and we will wait for login response of boot targets during + * probe. + **/ +static void qla4xxx_wait_login_resp_boot_tgt(struct scsi_qla_host *ha) +{ + struct ddb_entry *ddb_entry; + struct dev_db_entry *fw_ddb_entry = NULL; + dma_addr_t fw_ddb_entry_dma; + unsigned long wtime; + uint32_t ddb_state; + int max_ddbs, idx, ret; + + max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : + MAX_DEV_DB_ENTRIES; + + fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), + &fw_ddb_entry_dma, GFP_KERNEL); + if (!fw_ddb_entry) { + ql4_printk(KERN_ERR, ha, + "%s: Unable to allocate dma buffer\n", __func__); + goto exit_login_resp; + } + + wtime = jiffies + (HZ * BOOT_LOGIN_RESP_TOV); + + for (idx = 0; idx < max_ddbs; idx++) { + ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx); + if (ddb_entry == NULL) + continue; + + if (test_bit(DF_BOOT_TGT, &ddb_entry->flags)) { + DEBUG2(ql4_printk(KERN_INFO, ha, + "%s: DDB index [%d]\n", __func__, + ddb_entry->fw_ddb_index)); + do { + ret = qla4xxx_get_fwddb_entry(ha, + ddb_entry->fw_ddb_index, + fw_ddb_entry, fw_ddb_entry_dma, + NULL, NULL, &ddb_state, NULL, + NULL, NULL); + if (ret == QLA_ERROR) + goto exit_login_resp; + + if ((ddb_state == DDB_DS_SESSION_ACTIVE) || + (ddb_state == DDB_DS_SESSION_FAILED)) + break; + + schedule_timeout_uninterruptible(HZ); + + } while ((time_after(wtime, jiffies))); + + if (!time_after(wtime, jiffies)) { + DEBUG2(ql4_printk(KERN_INFO, ha, + "%s: Login response wait timer expired\n", + __func__)); + goto exit_login_resp; + } + } + } + +exit_login_resp: + if (fw_ddb_entry) + dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), + fw_ddb_entry, fw_ddb_entry_dma); +} + +/** + * qla4xxx_probe_adapter - callback function to probe HBA + * @pdev: pointer to pci_dev structure + * @pci_device_id: pointer to pci_device entry + * + * This routine will probe for Qlogic 4xxx iSCSI host adapters. + * It returns zero if successful. It also initializes all data necessary for + * the driver. + **/ +static int qla4xxx_probe_adapter(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int ret = -ENODEV, status; + struct Scsi_Host *host; + struct scsi_qla_host *ha; + uint8_t init_retry_count = 0; + char buf[34]; + struct qla4_8xxx_legacy_intr_set *nx_legacy_intr; + uint32_t dev_state; + + if (pci_enable_device(pdev)) + return -1; host = iscsi_host_alloc(&qla4xxx_driver_template, sizeof(*ha), 0); if (host == NULL) { @@ -5452,6 +7094,10 @@ skip_retry_init: ql4_printk(KERN_ERR, ha, "%s: No iSCSI boot target configured\n", __func__); + if (qla4xxx_sysfs_ddb_export(ha)) + ql4_printk(KERN_ERR, ha, + "%s: Error exporting ddb to sysfs\n", __func__); + /* Perform the build ddb list and login to each */ qla4xxx_build_ddb_list(ha, INIT_ADAPTER); iscsi_host_for_each_session(ha->host, qla4xxx_login_flash_ddb); @@ -5577,6 +7223,7 @@ static void qla4xxx_remove_adapter(struct pci_dev *pdev) qla4xxx_destroy_fw_ddb_session(ha); qla4_8xxx_free_sysfs_attr(ha); + qla4xxx_sysfs_ddb_remove(ha); scsi_remove_host(ha->host); qla4xxx_free_adapter(ha); -- cgit v1.2.3 From c962c18bb72a7d9a70586908fed431f7c29b75c3 Mon Sep 17 00:00:00 2001 From: Adheer Chandravanshi Date: Mon, 25 Mar 2013 08:08:32 -0400 Subject: [SCSI] qla4xxx: Replace dev type macros with generic portal type macros Signed-off-by: Adheer Chandravanshi Signed-off-by: Vikas Chaudhary Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_def.h | 3 --- drivers/scsi/qla4xxx/ql4_os.c | 26 ++++++++++++++------------ 2 files changed, 14 insertions(+), 15 deletions(-) (limited to 'drivers/scsi/qla4xxx') diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index b487b0aa4dee..ddf16a86bbf5 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -159,9 +159,6 @@ #define LSDW(x) ((u32)((u64)(x))) #define MSDW(x) ((u32)((((u64)(x)) >> 16) >> 16)) -#define DEV_TYPE_IPV4 "ipv4" -#define DEV_TYPE_IPV6 "ipv6" - #define DEV_DB_NON_PERSISTENT 0 #define DEV_DB_PERSISTENT 1 diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 497ac681d733..95a951c6e579 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -2021,11 +2021,13 @@ static int qla4xxx_copy_from_fwddb_param(struct iscsi_bus_flash_session *sess, options = le16_to_cpu(fw_ddb_entry->options); conn->is_fw_assigned_ipv6 = test_bit(OPT_IS_FW_ASSIGNED_IPV6, &options); if (test_bit(OPT_IPV6_DEVICE, &options)) { - rc = iscsi_switch_str_param(&sess->portal_type, DEV_TYPE_IPV6); + rc = iscsi_switch_str_param(&sess->portal_type, + PORTAL_TYPE_IPV6); if (rc) goto exit_copy; } else { - rc = iscsi_switch_str_param(&sess->portal_type, DEV_TYPE_IPV4); + rc = iscsi_switch_str_param(&sess->portal_type, + PORTAL_TYPE_IPV4); if (rc) goto exit_copy; } @@ -2161,7 +2163,7 @@ static int qla4xxx_copy_to_fwddb_param(struct iscsi_bus_flash_session *sess, options = le16_to_cpu(fw_ddb_entry->options); SET_BITVAL(conn->is_fw_assigned_ipv6, options, BIT_11); - if (!strncmp(sess->portal_type, DEV_TYPE_IPV6, 4)) + if (!strncmp(sess->portal_type, PORTAL_TYPE_IPV6, 4)) options |= BIT_8; else options &= ~BIT_8; @@ -5578,8 +5580,8 @@ static int qla4xxx_sysfs_ddb_add(struct Scsi_Host *shost, const char *buf, uint32_t options = 0; uint32_t rval = QLA_ERROR; - if (strncasecmp(DEV_TYPE_IPV4, buf, 4) && - strncasecmp(DEV_TYPE_IPV6, buf, 4)) { + if (strncasecmp(PORTAL_TYPE_IPV4, buf, 4) && + strncasecmp(PORTAL_TYPE_IPV6, buf, 4)) { DEBUG2(ql4_printk(KERN_ERR, ha, "%s: Invalid portal type\n", __func__)); goto exit_ddb_add; @@ -5663,7 +5665,7 @@ static int qla4xxx_sysfs_ddb_apply(struct iscsi_bus_flash_session *fnode_sess, goto exit_ddb_apply; } - if (!strncasecmp(fnode_sess->portal_type, DEV_TYPE_IPV6, 4)) + if (!strncasecmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4)) options |= IPV6_DEFAULT_DDB_ENTRY; rval = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma); @@ -5858,7 +5860,7 @@ static int qla4xxx_sysfs_ddb_login(struct iscsi_bus_flash_session *fnode_sess, goto exit_ddb_login; } - if (!strncasecmp(fnode_sess->portal_type, DEV_TYPE_IPV6, 4)) + if (!strncasecmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4)) options |= IPV6_DEFAULT_DDB_ENTRY; ret = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma); @@ -6038,7 +6040,7 @@ static int qla4xxx_sysfs_ddb_logout(struct iscsi_bus_flash_session *fnode_sess, strncpy(flash_tddb->iscsi_name, fnode_sess->targetname, ISCSI_NAME_SIZE); - if (!strncmp(fnode_sess->portal_type, DEV_TYPE_IPV6, 4)) + if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4)) sprintf(flash_tddb->ip_addr, "%pI6", fnode_conn->ipaddress); else sprintf(flash_tddb->ip_addr, "%pI4", fnode_conn->ipaddress); @@ -6220,7 +6222,7 @@ qla4xxx_sysfs_ddb_get_param(struct iscsi_bus_flash_session *fnode_sess, fnode_sess->default_taskmgmt_timeout); break; case ISCSI_FLASHNODE_IPADDR: - if (!strncmp(fnode_sess->portal_type, DEV_TYPE_IPV6, 4)) + if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4)) rc = sprintf(buf, "%pI6\n", fnode_conn->ipaddress); else rc = sprintf(buf, "%pI4\n", fnode_conn->ipaddress); @@ -6232,7 +6234,7 @@ qla4xxx_sysfs_ddb_get_param(struct iscsi_bus_flash_session *fnode_sess, rc = sprintf(buf, "\n"); break; case ISCSI_FLASHNODE_REDIRECT_IPADDR: - if (!strncmp(fnode_sess->portal_type, DEV_TYPE_IPV6, 4)) + if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4)) rc = sprintf(buf, "%pI6\n", fnode_conn->redirect_ipaddr); else @@ -6249,7 +6251,7 @@ qla4xxx_sysfs_ddb_get_param(struct iscsi_bus_flash_session *fnode_sess, rc = sprintf(buf, "%u\n", fnode_conn->ipv4_tos); break; case ISCSI_FLASHNODE_IPV6_TC: - if (!strncmp(fnode_sess->portal_type, DEV_TYPE_IPV6, 4)) + if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4)) rc = sprintf(buf, "%u\n", fnode_conn->ipv6_traffic_class); else @@ -6259,7 +6261,7 @@ qla4xxx_sysfs_ddb_get_param(struct iscsi_bus_flash_session *fnode_sess, rc = sprintf(buf, "%u\n", fnode_conn->ipv6_flow_label); break; case ISCSI_FLASHNODE_LINK_LOCAL_IPV6: - if (!strncmp(fnode_sess->portal_type, DEV_TYPE_IPV6, 4)) + if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4)) rc = sprintf(buf, "%pI6\n", fnode_conn->link_local_ipv6_addr); else -- cgit v1.2.3 From 0ce2d5345a145015bc35f8251cf9d82a8f193a86 Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Mon, 25 Mar 2013 08:08:33 -0400 Subject: [SCSI] qla4xxx: Update driver version to 5.03.00-k7 Signed-off-by: Vikas Chaudhary Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi/qla4xxx') diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h index 0cd824fe1513..18ad425e2bd1 100644 --- a/drivers/scsi/qla4xxx/ql4_version.h +++ b/drivers/scsi/qla4xxx/ql4_version.h @@ -5,4 +5,4 @@ * See LICENSE.qla4xxx for copyright and licensing details. */ -#define QLA4XXX_DRIVER_VERSION "5.03.00-k6" +#define QLA4XXX_DRIVER_VERSION "5.03.00-k7" -- cgit v1.2.3 From 039acc1e70ba354a430023c3c997f680d7c098b9 Mon Sep 17 00:00:00 2001 From: Adheer Chandravanshi Date: Fri, 5 Apr 2013 07:06:06 -0400 Subject: [SCSI] qla4xxx: Use correct flash ddb offset for ISP40XX Use correct flash ddb offset to add and delete flash target entries for ISP40XX Signed-off-by: Adheer Chandravanshi Signed-off-by: Vikas Chaudhary Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_mbx.c | 7 ++++-- drivers/scsi/qla4xxx/ql4_os.c | 57 ++++++++++++++++++++++++++++-------------- 2 files changed, 43 insertions(+), 21 deletions(-) (limited to 'drivers/scsi/qla4xxx') diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index 8985997de576..a501beab3ffe 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -1421,7 +1421,7 @@ int qla4xxx_flashdb_by_index(struct scsi_qla_host *ha, struct dev_db_entry *fw_ddb_entry, dma_addr_t fw_ddb_entry_dma, uint16_t ddb_index) { - uint32_t dev_db_start_offset = FLASH_OFFSET_DB_INFO; + uint32_t dev_db_start_offset; uint32_t dev_db_end_offset; int status = QLA_ERROR; @@ -1429,6 +1429,7 @@ int qla4xxx_flashdb_by_index(struct scsi_qla_host *ha, if (is_qla40XX(ha)) { dev_db_start_offset = FLASH_OFFSET_DB_INFO; + dev_db_end_offset = FLASH_OFFSET_DB_END; } else { dev_db_start_offset = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_region_ddb << 2); @@ -1437,9 +1438,11 @@ int qla4xxx_flashdb_by_index(struct scsi_qla_host *ha, */ if (ha->port_num == 1) dev_db_start_offset += (ha->hw.flt_ddb_size / 2); + + dev_db_end_offset = dev_db_start_offset + + (ha->hw.flt_ddb_size / 2); } - dev_db_end_offset = dev_db_start_offset + (ha->hw.flt_ddb_size / 2); dev_db_start_offset += (ddb_index * sizeof(*fw_ddb_entry)); if (dev_db_start_offset > dev_db_end_offset) { diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 95a951c6e579..5f7a2bc32069 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -6582,6 +6582,8 @@ static int qla4xxx_sysfs_ddb_delete(struct iscsi_bus_flash_session *fnode_sess) struct dev_db_entry *fw_ddb_entry = NULL; dma_addr_t fw_ddb_entry_dma; uint16_t *ddb_cookie = NULL; + size_t ddb_size; + void *pddb = NULL; int target_id; int rc = 0; @@ -6601,18 +6603,12 @@ static int qla4xxx_sysfs_ddb_delete(struct iscsi_bus_flash_session *fnode_sess) if (fnode_sess->flash_state == DEV_DB_NON_PERSISTENT) goto sysfs_ddb_del; - ddb_cookie = dma_alloc_coherent(&ha->pdev->dev, sizeof(*ddb_cookie), - &fw_ddb_entry_dma, GFP_KERNEL); - if (!ddb_cookie) { - rc = -ENOMEM; - DEBUG2(ql4_printk(KERN_ERR, ha, - "%s: Unable to allocate dma buffer\n", - __func__)); - goto exit_ddb_del; - } - if (is_qla40XX(ha)) { dev_db_start_offset = FLASH_OFFSET_DB_INFO; + dev_db_end_offset = FLASH_OFFSET_DB_END; + dev_db_start_offset += (fnode_sess->target_id * + sizeof(*fw_ddb_entry)); + ddb_size = sizeof(*fw_ddb_entry); } else { dev_db_start_offset = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_region_ddb << 2); @@ -6621,12 +6617,17 @@ static int qla4xxx_sysfs_ddb_delete(struct iscsi_bus_flash_session *fnode_sess) */ if (ha->port_num == 1) dev_db_start_offset += (ha->hw.flt_ddb_size / 2); - } - dev_db_end_offset = dev_db_start_offset + (ha->hw.flt_ddb_size / 2); - dev_db_start_offset += (fnode_sess->target_id * sizeof(*fw_ddb_entry)); - dev_db_start_offset += (void *)&(fw_ddb_entry->cookie) - - (void *)fw_ddb_entry; + dev_db_end_offset = dev_db_start_offset + + (ha->hw.flt_ddb_size / 2); + + dev_db_start_offset += (fnode_sess->target_id * + sizeof(*fw_ddb_entry)); + dev_db_start_offset += (void *)&(fw_ddb_entry->cookie) - + (void *)fw_ddb_entry; + + ddb_size = sizeof(*ddb_cookie); + } DEBUG2(ql4_printk(KERN_ERR, ha, "%s: start offset=%u, end offset=%u\n", __func__, dev_db_start_offset, dev_db_end_offset)); @@ -6638,10 +6639,28 @@ static int qla4xxx_sysfs_ddb_delete(struct iscsi_bus_flash_session *fnode_sess) goto exit_ddb_del; } + pddb = dma_alloc_coherent(&ha->pdev->dev, ddb_size, + &fw_ddb_entry_dma, GFP_KERNEL); + if (!pddb) { + rc = -ENOMEM; + DEBUG2(ql4_printk(KERN_ERR, ha, + "%s: Unable to allocate dma buffer\n", + __func__)); + goto exit_ddb_del; + } + + if (is_qla40XX(ha)) { + fw_ddb_entry = pddb; + memset(fw_ddb_entry, 0, ddb_size); + ddb_cookie = &fw_ddb_entry->cookie; + } else { + ddb_cookie = pddb; + } + /* invalidate the cookie */ *ddb_cookie = 0xFFEE; qla4xxx_set_flash(ha, fw_ddb_entry_dma, dev_db_start_offset, - sizeof(*ddb_cookie), FLASH_OPT_RMW_COMMIT); + ddb_size, FLASH_OPT_RMW_COMMIT); sysfs_ddb_del: target_id = fnode_sess->target_id; @@ -6650,9 +6669,9 @@ sysfs_ddb_del: "%s: session and conn entries for flashnode %u of host %lu deleted\n", __func__, target_id, ha->host_no); exit_ddb_del: - if (ddb_cookie) - dma_free_coherent(&ha->pdev->dev, sizeof(*ddb_cookie), - ddb_cookie, fw_ddb_entry_dma); + if (pddb) + dma_free_coherent(&ha->pdev->dev, ddb_size, pddb, + fw_ddb_entry_dma); return rc; } -- cgit v1.2.3 From 37719c2a54caff1f3d7861a17e06327f74002bb2 Mon Sep 17 00:00:00 2001 From: Adheer Chandravanshi Date: Fri, 5 Apr 2013 07:06:07 -0400 Subject: [SCSI] qla4xxx: Restrict logout from boot target session using session id Signed-off-by: Adheer Chandravanshi Signed-off-by: Vikas Chaudhary Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_os.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/scsi/qla4xxx') diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 5f7a2bc32069..f82efcb82684 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -5916,6 +5916,14 @@ static int qla4xxx_sysfs_ddb_logout_sid(struct iscsi_cls_session *cls_sess) goto exit_ddb_logout; } + if (test_bit(DF_BOOT_TGT, &ddb_entry->flags)) { + ql4_printk(KERN_ERR, ha, + "%s: Logout from boot target entry is not permitted.\n", + __func__); + ret = -EPERM; + goto exit_ddb_logout; + } + options = LOGOUT_OPTION_CLOSE_SESSION; if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) == QLA_ERROR) { ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", __func__); -- cgit v1.2.3 From a957a7d7b5c69752c3c11182c41ef96aa52bb911 Mon Sep 17 00:00:00 2001 From: Adheer Chandravanshi Date: Fri, 5 Apr 2013 07:06:08 -0400 Subject: [SCSI] qla4xxx: Use correct value for max flash node entries Use correct value for max flash node entries supported based on adapter type. Signed-off-by: Adheer Chandravanshi Signed-off-by: Vikas Chaudhary Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_os.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/scsi/qla4xxx') diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index f82efcb82684..a47f99957ba8 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -5587,7 +5587,7 @@ static int qla4xxx_sysfs_ddb_add(struct Scsi_Host *shost, const char *buf, goto exit_ddb_add; } - max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : + max_ddbs = is_qla40XX(ha) ? MAX_PRST_DEV_DB_ENTRIES : MAX_DEV_DB_ENTRIES; fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), @@ -6707,7 +6707,7 @@ static int qla4xxx_sysfs_ddb_export(struct scsi_qla_host *ha) return -ENOMEM; } - max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : + max_ddbs = is_qla40XX(ha) ? MAX_PRST_DEV_DB_ENTRIES : MAX_DEV_DB_ENTRIES; for (idx = 0; idx < max_ddbs; idx++) { -- cgit v1.2.3 From 78a4544885037ad95ca1962ffeda767d60dd78b1 Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Fri, 5 Apr 2013 07:06:09 -0400 Subject: [SCSI] qla4xxx: Added print statements to display AENs Added print statements for following AENs: 1. MBOX_ASTS_INITIALIZATION_FAILED 2. MBOX_ASTS_SYSTEM_WARNING_EVENT 3. MBOX_ASTS_DCBX_CONF_CHANGE 4. MBOX_ASTS_IPV6_DEFAULT_ROUTER_CHANGED Signed-off-by: Vikas Chaudhary Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_fw.h | 4 ++++ drivers/scsi/qla4xxx/ql4_isr.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) (limited to 'drivers/scsi/qla4xxx') diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h index 5945829d662f..c7b8892b5a83 100644 --- a/drivers/scsi/qla4xxx/ql4_fw.h +++ b/drivers/scsi/qla4xxx/ql4_fw.h @@ -493,12 +493,16 @@ struct qla_flt_region { #define MBOX_ASTS_SUBNET_STATE_CHANGE 0x8027 #define MBOX_ASTS_RESPONSE_QUEUE_FULL 0x8028 #define MBOX_ASTS_IP_ADDR_STATE_CHANGED 0x8029 +#define MBOX_ASTS_IPV6_DEFAULT_ROUTER_CHANGED 0x802A #define MBOX_ASTS_IPV6_PREFIX_EXPIRED 0x802B #define MBOX_ASTS_IPV6_ND_PREFIX_IGNORED 0x802C #define MBOX_ASTS_IPV6_LCL_PREFIX_IGNORED 0x802D #define MBOX_ASTS_ICMPV6_ERROR_MSG_RCVD 0x802E +#define MBOX_ASTS_INITIALIZATION_FAILED 0x8031 +#define MBOX_ASTS_SYSTEM_WARNING_EVENT 0x8036 #define MBOX_ASTS_IDC_COMPLETE 0x8100 #define MBOX_ASTS_IDC_REQUEST_NOTIFICATION 0x8101 +#define MBOX_ASTS_DCBX_CONF_CHANGE 0x8110 #define MBOX_ASTS_TXSCVR_INSERTED 0x8130 #define MBOX_ASTS_TXSCVR_REMOVED 0x8131 diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c index 7bef448e2946..482287f4005f 100644 --- a/drivers/scsi/qla4xxx/ql4_isr.c +++ b/drivers/scsi/qla4xxx/ql4_isr.c @@ -875,6 +875,43 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, } break; + case MBOX_ASTS_IPV6_DEFAULT_ROUTER_CHANGED: + DEBUG2(ql4_printk(KERN_INFO, ha, + "scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x mbox_sts[5]=%08x\n", + ha->host_no, mbox_sts[0], mbox_sts[1], + mbox_sts[2], mbox_sts[3], mbox_sts[4], + mbox_sts[5])); + DEBUG2(ql4_printk(KERN_INFO, ha, + "scsi%ld: AEN %04x Received IPv6 default router changed notification\n", + ha->host_no, mbox_sts[0])); + break; + + case MBOX_ASTS_INITIALIZATION_FAILED: + DEBUG2(ql4_printk(KERN_INFO, ha, + "scsi%ld: AEN %04x, mbox_sts[3]=%08x\n", + ha->host_no, mbox_sts[0], + mbox_sts[3])); + break; + + case MBOX_ASTS_SYSTEM_WARNING_EVENT: + DEBUG2(ql4_printk(KERN_WARNING, ha, + "scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x mbox_sts[5]=%08x\n", + ha->host_no, mbox_sts[0], mbox_sts[1], + mbox_sts[2], mbox_sts[3], mbox_sts[4], + mbox_sts[5])); + break; + + case MBOX_ASTS_DCBX_CONF_CHANGE: + DEBUG2(ql4_printk(KERN_INFO, ha, + "scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x mbox_sts[5]=%08x\n", + ha->host_no, mbox_sts[0], mbox_sts[1], + mbox_sts[2], mbox_sts[3], mbox_sts[4], + mbox_sts[5])); + DEBUG2(ql4_printk(KERN_INFO, ha, + "scsi%ld: AEN %04x Received DCBX configuration changed notification\n", + ha->host_no, mbox_sts[0])); + break; + default: DEBUG2(printk(KERN_WARNING "scsi%ld: AEN %04x UNKNOWN\n", -- cgit v1.2.3 From 5f28897d2827a924b746c4d85e35cf85810b8951 Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Fri, 5 Apr 2013 07:06:10 -0400 Subject: [SCSI] qla4xxx: Update driver version to 5.03.00-k8 Signed-off-by: Vikas Chaudhary Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi/qla4xxx') diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h index 18ad425e2bd1..83e0fec35d56 100644 --- a/drivers/scsi/qla4xxx/ql4_version.h +++ b/drivers/scsi/qla4xxx/ql4_version.h @@ -5,4 +5,4 @@ * See LICENSE.qla4xxx for copyright and licensing details. */ -#define QLA4XXX_DRIVER_VERSION "5.03.00-k7" +#define QLA4XXX_DRIVER_VERSION "5.03.00-k8" -- cgit v1.2.3