diff options
-rw-r--r-- | drivers/scsi/qla2xxx/qla_attr.c | 30 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_dbg.c | 67 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_dbg.h | 15 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_def.h | 64 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_fw.h | 14 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_gbl.h | 41 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_gs.c | 6 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_init.c | 192 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_inline.h | 26 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_iocb.c | 158 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_isr.c | 335 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_mbx.c | 147 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_mid.c | 349 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 423 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_sup.c | 33 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_version.h | 4 |
16 files changed, 1443 insertions, 461 deletions
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index b2238422937..cd53627cc76 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1143,8 +1143,11 @@ static int qla24xx_vport_create(struct fc_vport *fc_vport, bool disable) { int ret = 0; + int cnt = 0; + uint8_t qos = QLA_DEFAULT_QUE_QOS; scsi_qla_host_t *base_vha = shost_priv(fc_vport->shost); scsi_qla_host_t *vha = NULL; + struct qla_hw_data *ha = base_vha->hw; ret = qla24xx_vport_create_req_sanity_check(fc_vport); if (ret) { @@ -1200,6 +1203,22 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable) qla24xx_vport_disable(fc_vport, disable); + /* Create a queue pair for the vport */ + if (ha->mqenable) { + if (ha->npiv_info) { + for (; cnt < ha->nvram_npiv_size; cnt++) { + if (ha->npiv_info[cnt].port_name == + vha->port_name && + ha->npiv_info[cnt].node_name == + vha->node_name) { + qos = ha->npiv_info[cnt].q_qos; + break; + } + } + } + qla25xx_create_queues(vha, qos); + } + return 0; vport_create_failed_2: qla24xx_disable_vp(vha); @@ -1213,11 +1232,20 @@ qla24xx_vport_delete(struct fc_vport *fc_vport) { scsi_qla_host_t *vha = fc_vport->dd_data; fc_port_t *fcport, *tfcport; + struct qla_hw_data *ha = vha->hw; + uint16_t id = vha->vp_idx; while (test_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags) || test_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags)) msleep(1000); + if (ha->mqenable) { + if (qla25xx_delete_queues(vha, 0) != QLA_SUCCESS) + qla_printk(KERN_WARNING, ha, + "Queue delete failed.\n"); + vha->req_ques[0] = ha->req_q_map[0]->id; + } + qla24xx_disable_vp(vha); fc_remove_host(vha->host); @@ -1240,7 +1268,7 @@ qla24xx_vport_delete(struct fc_vport *fc_vport) } scsi_host_put(vha->host); - + qla_printk(KERN_INFO, ha, "vport %d deleted\n", id); return 0; } diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index f15f903aec5..1cf77772623 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -23,11 +23,10 @@ qla2xxx_prep_dump(struct qla_hw_data *ha, struct qla2xxx_fw_dump *fw_dump) } static inline void * -qla2xxx_copy_queues(scsi_qla_host_t *vha, void *ptr) +qla2xxx_copy_queues(struct qla_hw_data *ha, void *ptr) { - struct req_que *req = vha->hw->req; - struct rsp_que *rsp = vha->hw->rsp; - + struct req_que *req = ha->req_q_map[0]; + struct rsp_que *rsp = ha->rsp_q_map[0]; /* Request queue. */ memcpy(ptr, req->ring, req->length * sizeof(request_t)); @@ -327,6 +326,7 @@ qla2300_fw_dump(scsi_qla_host_t *vha, int hardware_locked) unsigned long flags; struct qla2300_fw_dump *fw; void *nxt; + struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); flags = 0; @@ -461,7 +461,7 @@ qla2300_fw_dump(scsi_qla_host_t *vha, int hardware_locked) ha->fw_memory_size - 0x11000 + 1, &nxt); if (rval == QLA_SUCCESS) - qla2xxx_copy_queues(vha, nxt); + qla2xxx_copy_queues(ha, nxt); if (rval != QLA_SUCCESS) { qla_printk(KERN_WARNING, ha, @@ -471,7 +471,7 @@ qla2300_fw_dump(scsi_qla_host_t *vha, int hardware_locked) } else { qla_printk(KERN_INFO, ha, "Firmware dump saved to temp buffer (%ld/%p).\n", - vha->host_no, ha->fw_dump); + base_vha->host_no, ha->fw_dump); ha->fw_dumped = 1; } @@ -497,6 +497,7 @@ qla2100_fw_dump(scsi_qla_host_t *vha, int hardware_locked) uint16_t __iomem *dmp_reg; unsigned long flags; struct qla2100_fw_dump *fw; + struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); risc_address = 0; mb0 = mb2 = 0; @@ -667,7 +668,7 @@ qla2100_fw_dump(scsi_qla_host_t *vha, int hardware_locked) } if (rval == QLA_SUCCESS) - qla2xxx_copy_queues(vha, &fw->risc_ram[cnt]); + qla2xxx_copy_queues(ha, &fw->risc_ram[cnt]); if (rval != QLA_SUCCESS) { qla_printk(KERN_WARNING, ha, @@ -677,7 +678,7 @@ qla2100_fw_dump(scsi_qla_host_t *vha, int hardware_locked) } else { qla_printk(KERN_INFO, ha, "Firmware dump saved to temp buffer (%ld/%p).\n", - vha->host_no, ha->fw_dump); + base_vha->host_no, ha->fw_dump); ha->fw_dumped = 1; } @@ -701,6 +702,7 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) struct qla24xx_fw_dump *fw; uint32_t ext_mem_cnt; void *nxt; + struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); risc_address = ext_mem_cnt = 0; flags = 0; @@ -910,7 +912,7 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) if (rval != QLA_SUCCESS) goto qla24xx_fw_dump_failed_0; - nxt = qla2xxx_copy_queues(vha, nxt); + nxt = qla2xxx_copy_queues(ha, nxt); if (ha->eft) memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size)); @@ -923,7 +925,7 @@ qla24xx_fw_dump_failed_0: } else { qla_printk(KERN_INFO, ha, "Firmware dump saved to temp buffer (%ld/%p).\n", - vha->host_no, ha->fw_dump); + base_vha->host_no, ha->fw_dump); ha->fw_dumped = 1; } @@ -940,6 +942,7 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) uint32_t risc_address; struct qla_hw_data *ha = vha->hw; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + struct device_reg_25xxmq __iomem *reg25; uint32_t __iomem *dmp_reg; uint32_t *iter_reg; uint16_t __iomem *mbx_reg; @@ -948,6 +951,11 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) uint32_t ext_mem_cnt; void *nxt; struct qla2xxx_fce_chain *fcec; + struct qla2xxx_mq_chain *mq = NULL; + uint32_t qreg_size; + uint8_t req_cnt, rsp_cnt, que_cnt; + uint32_t que_idx; + struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); risc_address = ext_mem_cnt = 0; flags = 0; @@ -992,6 +1000,29 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) fw->pcie_regs[1] = htonl(RD_REG_DWORD(dmp_reg++)); fw->pcie_regs[2] = htonl(RD_REG_DWORD(dmp_reg)); fw->pcie_regs[3] = htonl(RD_REG_DWORD(®->iobase_window)); + + /* Multi queue registers */ + if (ha->mqenable) { + qreg_size = sizeof(struct qla2xxx_mq_chain); + mq = kzalloc(qreg_size, GFP_KERNEL); + if (!mq) + goto qla25xx_fw_dump_failed_0; + req_cnt = find_first_zero_bit(ha->req_qid_map, ha->max_queues); + rsp_cnt = find_first_zero_bit(ha->rsp_qid_map, ha->max_queues); + que_cnt = req_cnt > rsp_cnt ? req_cnt : rsp_cnt; + mq->count = htonl(que_cnt); + mq->chain_size = htonl(qreg_size); + mq->type = __constant_htonl(DUMP_CHAIN_MQ); + for (cnt = 0; cnt < que_cnt; cnt++) { + reg25 = (struct device_reg_25xxmq *) ((void *) + ha->mqiobase + cnt * QLA_QUE_PAGE); + que_idx = cnt * 4; + mq->qregs[que_idx] = htonl(reg25->req_q_in); + mq->qregs[que_idx+1] = htonl(reg25->req_q_out); + mq->qregs[que_idx+2] = htonl(reg25->rsp_q_in); + mq->qregs[que_idx+3] = htonl(reg25->rsp_q_out); + } + } WRT_REG_DWORD(®->iobase_window, 0x00); RD_REG_DWORD(®->iobase_window); @@ -1219,7 +1250,7 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) goto qla25xx_fw_dump_failed_0; /* Fibre Channel Trace Buffer. */ - nxt = qla2xxx_copy_queues(vha, nxt); + nxt = qla2xxx_copy_queues(ha, nxt); if (ha->eft) memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size)); @@ -1229,7 +1260,14 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT); - fcec = nxt + ntohl(ha->fw_dump->eft_size); + if (ha->mqenable) { + nxt = nxt + ntohl(ha->fw_dump->eft_size); + memcpy(nxt, mq, qreg_size); + kfree(mq); + fcec = nxt + qreg_size; + } else { + fcec = nxt + ntohl(ha->fw_dump->eft_size); + } fcec->type = __constant_htonl(DUMP_CHAIN_FCE | DUMP_CHAIN_LAST); fcec->chain_size = htonl(sizeof(struct qla2xxx_fce_chain) + fce_calc_size(ha->fce_bufs)); @@ -1252,7 +1290,7 @@ qla25xx_fw_dump_failed_0: } else { qla_printk(KERN_INFO, ha, "Firmware dump saved to temp buffer (%ld/%p).\n", - vha->host_no, ha->fw_dump); + base_vha->host_no, ha->fw_dump); ha->fw_dumped = 1; } @@ -1260,7 +1298,6 @@ qla25xx_fw_dump_failed: if (!hardware_locked) spin_unlock_irqrestore(&ha->hardware_lock, flags); } - /****************************************************************************/ /* Driver Debug Functions. */ /****************************************************************************/ @@ -1307,3 +1344,5 @@ qla2x00_dump_buffer(uint8_t * b, uint32_t size) if (cnt % 16) printk("\n"); } + + diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index 2e9c0c097f5..c1794a70a45 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -4,6 +4,9 @@ * * See LICENSE.qla2xxx for copyright and licensing details. */ + +#include "qla_def.h" + /* * Driver debug definitions. */ @@ -23,6 +26,7 @@ /* #define QL_DEBUG_LEVEL_14 */ /* Output RSCN trace msgs */ /* #define QL_DEBUG_LEVEL_15 */ /* Output NPIV trace msgs */ /* #define QL_DEBUG_LEVEL_16 */ /* Output ISP84XX trace msgs */ +/* #define QL_DEBUG_LEVEL_17 */ /* Output MULTI-Q trace messages */ /* * Macros use for debugging the driver. @@ -43,6 +47,7 @@ #define DEBUG2_11(x) do { if (ql2xextended_error_logging) { x; } } while (0) #define DEBUG2_13(x) do { if (ql2xextended_error_logging) { x; } } while (0) #define DEBUG2_16(x) do { if (ql2xextended_error_logging) { x; } } while (0) +#define DEBUG2_17(x) do { if (ql2xextended_error_logging) { x; } } while (0) #if defined(QL_DEBUG_LEVEL_3) #define DEBUG3(x) do {x;} while (0) @@ -127,7 +132,6 @@ #else #define DEBUG16(x) do {} while (0) #endif - /* * Firmware Dump structure definition */ @@ -266,8 +270,17 @@ struct qla2xxx_fce_chain { uint32_t eregs[8]; }; +struct qla2xxx_mq_chain { + uint32_t type; + uint32_t chain_size; + + uint32_t count; + uint32_t qregs[4 * QLA_MQ_SIZE]; +}; + #define DUMP_CHAIN_VARIANT 0x80000000 #define DUMP_CHAIN_FCE 0x7FFFFAF0 +#define DUMP_CHAIN_MQ 0x7FFFFAF1 #define DUMP_CHAIN_LAST 0x80000000 struct qla2xxx_fw_dump { diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index edead280251..5ecf29283b6 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -369,9 +369,17 @@ struct device_reg_2xxx { } u_end; }; +struct device_reg_25xxmq { + volatile uint32_t req_q_in; + volatile uint32_t req_q_out; + volatile uint32_t rsp_q_in; + volatile uint32_t rsp_q_out; +}; + typedef union { struct device_reg_2xxx isp; struct device_reg_24xx isp24; + struct device_reg_25xxmq isp25mq; } device_reg_t; #define ISP_REQ_Q_IN(ha, reg) \ @@ -2037,6 +2045,7 @@ typedef struct vport_params { #define VP_RET_CODE_NOT_FOUND 6 struct qla_hw_data; +struct req_que; /* * ISP operations @@ -2059,7 +2068,8 @@ struct isp_operations { void (*enable_intrs) (struct qla_hw_data *); void (*disable_intrs) (struct qla_hw_data *); - int (*abort_command) (struct scsi_qla_host *, srb_t *); + int (*abort_command) (struct scsi_qla_host *, srb_t *, + struct req_que *); int (*target_reset) (struct fc_port *, unsigned int); int (*lun_reset) (struct fc_port *, unsigned int); int (*fabric_login) (struct scsi_qla_host *, uint16_t, uint8_t, @@ -2102,16 +2112,18 @@ struct isp_operations { #define QLA_MSIX_DEFAULT 0x00 #define QLA_MSIX_RSP_Q 0x01 -#define QLA_MSIX_ENTRIES 2 #define QLA_MIDX_DEFAULT 0 #define QLA_MIDX_RSP_Q 1 +#define QLA_PCI_MSIX_CONTROL 0xa2 struct scsi_qla_host; +struct rsp_que; struct qla_msix_entry { int have_irq; - uint32_t msix_vector; - uint16_t msix_entry; + uint32_t vector; + uint16_t entry; + struct rsp_que *rsp; }; #define WATCH_INTERVAL 1 /* number of seconds */ @@ -2162,6 +2174,23 @@ struct qla_statistics { uint64_t output_bytes; }; +/* Multi queue support */ +#define MBC_INITIALIZE_MULTIQ 0x1f +#define QLA_QUE_PAGE 0X1000 +#define QLA_MQ_SIZE 32 +#define QLA_MAX_HOST_QUES 16 +#define QLA_MAX_QUEUES 256 +#define ISP_QUE_REG(ha, id) \ + ((ha->mqenable) ? \ + ((void *)(ha->mqiobase) +\ + (QLA_QUE_PAGE * id)) :\ + ((void *)(ha->iobase))) +#define QLA_REQ_QUE_ID(tag) \ + ((tag < QLA_MAX_QUEUES && tag > 0) ? tag : 0) +#define QLA_DEFAULT_QUE_QOS 5 +#define QLA_PRECONFIG_VPORTS 32 +#define QLA_MAX_VPORTS_QLA24XX 128 +#define QLA_MAX_VPORTS_QLA25XX 256 /* Response queue data structure */ struct rsp_que { dma_addr_t dma; @@ -2171,9 +2200,12 @@ struct rsp_que { uint16_t out_ptr; uint16_t length; uint16_t options; - uint16_t msix_vector; uint16_t rid; + uint16_t id; + uint16_t vp_idx; struct qla_hw_data *hw; + struct qla_msix_entry *msix; + struct req_que *req; }; /* Request queue data structure */ @@ -2187,10 +2219,10 @@ struct req_que { uint16_t length; uint16_t options; uint16_t rid; + uint16_t id; uint16_t qos; uint16_t vp_idx; - struct rsp_que *asso_que; - /* Outstandings ISP commands. */ + struct rsp_que *rsp; srb_t *outstanding_cmds[MAX_OUTSTANDING_COMMANDS]; uint32_t current_outstanding_cmd; int max_q_depth; @@ -2240,8 +2272,17 @@ struct qla_hw_data { resource_size_t pio_address; #define MIN_IOBASE_LEN 0x100 - struct req_que *req; - struct rsp_que *rsp; +/* Multi queue data structs */ + device_reg_t *mqiobase; + uint16_t msix_count; + uint8_t mqenable; + struct req_que **req_q_map; + struct rsp_que **rsp_q_map; + unsigned long req_qid_map[(QLA_MAX_QUEUES / 8) / sizeof(unsigned long)]; + unsigned long rsp_qid_map[(QLA_MAX_QUEUES / 8) / sizeof(unsigned long)]; + uint16_t max_queues; + struct qla_npiv_entry *npiv_info; + uint16_t nvram_npiv_size; uint16_t switch_cap; #define FLOGI_SEQ_DEL BIT_8 @@ -2502,7 +2543,7 @@ struct qla_hw_data { uint16_t zio_timer; struct fc_host_statistics fc_host_stat; - struct qla_msix_entry msix_entries[QLA_MSIX_ENTRIES]; + struct qla_msix_entry *msix_entries; struct list_head vp_list; /* list of VP */ unsigned long vp_idx_map[(MAX_MULTI_ID_FABRIC / 8) / @@ -2524,7 +2565,6 @@ typedef struct scsi_qla_host { struct list_head list; struct list_head vp_fcports; /* list of fcports */ struct list_head work_list; - /* Commonly used flags and state information. */ struct Scsi_Host *host; unsigned long host_no; @@ -2640,9 +2680,9 @@ typedef struct scsi_qla_host { #define VP_ERR_FAB_LOGOUT 4 #define VP_ERR_ADAP_NORESOURCES 5 struct qla_hw_data *hw; + int req_ques[QLA_MAX_HOST_QUES]; } scsi_qla_host_t; - /* * Macros to help code, maintain, etc. */ diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index d1d14202575..ee1f1e794c2 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -299,7 +299,8 @@ struct init_cb_24xx { uint32_t response_q_address[2]; uint32_t prio_request_q_address[2]; - uint8_t reserved_2[8]; + uint16_t msix; + uint8_t reserved_2[6]; uint16_t atio_q_inpointer; uint16_t atio_q_length; @@ -372,8 +373,9 @@ struct init_cb_24xx { * BIT 17-31 = Reserved */ uint32_t firmware_options_3; - - uint8_t reserved_3[24]; + uint16_t qos; + uint16_t rid; + uint8_t reserved_3[20]; }; /* @@ -754,7 +756,8 @@ struct abort_entry_24xx { uint32_t handle_to_abort; /* System handle to abort. */ - uint8_t reserved_1[32]; + uint16_t req_que_no; + uint8_t reserved_1[30]; uint8_t port_id[3]; /* PortID of destination port. */ uint8_t vp_index; @@ -1258,7 +1261,8 @@ struct qla_npiv_header { struct qla_npiv_entry { uint16_t flags; uint16_t vf_id; - uint16_t qos; + uint8_t q_qos; + uint8_t f_qos; uint16_t unused1; uint8_t port_name[WWN_SIZE]; uint8_t node_name[WWN_SIZE]; diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index c0cc686d6cc..d9712b54349 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -63,6 +63,7 @@ extern int ql2xallocfwdump; extern int ql2xextended_error_logging; extern int ql2xqfullrampup; extern int ql2xiidmaenable; +extern int ql2xmaxqueues; extern int qla2x00_loop_reset(scsi_qla_host_t *); extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); @@ -97,7 +98,7 @@ extern void qla2x00_do_dpc_all_vps(scsi_qla_host_t *); extern int qla24xx_vport_create_req_sanity_check(struct fc_vport *); extern scsi_qla_host_t * qla24xx_create_vhost(struct fc_vport *); -extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *); +extern void qla2x00_sp_compl(struct qla_hw_data *, srb_t *); extern char *qla2x00_get_fw_version_str(struct scsi_qla_host *, char *); @@ -109,8 +110,9 @@ extern struct fw_blob *qla2x00_request_firmware(scsi_qla_host_t *); extern int qla2x00_wait_for_hba_online(scsi_qla_host_t *); extern void qla2xxx_wake_dpc(struct scsi_qla_host *); -extern void qla2x00_alert_all_vps(struct qla_hw_data *, uint16_t *); -extern void qla2x00_async_event(scsi_qla_host_t *, uint16_t *); +extern void qla2x00_alert_all_vps(struct rsp_que *, uint16_t *); +extern void qla2x00_async_event(scsi_qla_host_t *, struct rsp_que *, + uint16_t *); extern int qla2x00_vp_abort_isp(scsi_qla_host_t *); /* @@ -122,8 +124,10 @@ extern void qla2x00_build_scsi_iocbs_32(srb_t *, cmd_entry_t *, uint16_t); extern void qla2x00_build_scsi_iocbs_64(srb_t *, cmd_entry_t *, uint16_t); extern int qla2x00_start_scsi(srb_t *sp); extern int qla24xx_start_scsi(srb_t *sp); -int qla2x00_marker(scsi_qla_host_t *, uint16_t, uint16_t, uint8_t); -int __qla2x00_marker(scsi_qla_host_t *, uint16_t, uint16_t, uint8_t); +int qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *, + uint16_t, uint16_t, uint8_t); +int __qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *, + uint16_t, uint16_t, uint8_t); /* * Global Function Prototypes in qla_mbx.c source file. @@ -157,7 +161,7 @@ extern int qla2x00_issue_iocb(scsi_qla_host_t *, void *, dma_addr_t, size_t); extern int -qla2x00_abort_command(scsi_qla_host_t *, srb_t *); +qla2x00_abort_command(scsi_qla_host_t *, srb_t *, struct req_que *); extern int qla2x00_abort_target(struct fc_port *, unsigned int); @@ -228,7 +232,7 @@ extern int qla24xx_get_isp_stats(scsi_qla_host_t *, struct link_statistics *, dma_addr_t); -extern int qla24xx_abort_command(scsi_qla_host_t *, srb_t *); +extern int qla24xx_abort_command(scsi_qla_host_t *, srb_t *, struct req_que *); extern int qla24xx_abort_target(struct fc_port *, unsigned int); extern int qla24xx_lun_reset(struct fc_port *, unsigned int); @@ -267,10 +271,10 @@ extern int qla84xx_verify_chip(struct scsi_qla_host *, uint16_t *); extern irqreturn_t qla2100_intr_handler(int, void *); extern irqreturn_t qla2300_intr_handler(int, void *); extern irqreturn_t qla24xx_intr_handler(int, void *); -extern void qla2x00_process_response_queue(struct scsi_qla_host *); -extern void qla24xx_process_response_queue(struct scsi_qla_host *); +extern void qla2x00_process_response_queue(struct rsp_que *); +extern void qla24xx_process_response_queue(struct rsp_que *); -extern int qla2x00_request_irqs(struct qla_hw_data *); +extern int qla2x00_request_irqs(struct qla_hw_data *, struct rsp_que *); extern void qla2x00_free_irqs(scsi_qla_host_t *); /* @@ -370,4 +374,21 @@ extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *); */ extern int qla2x00_dfs_setup(scsi_qla_host_t *); extern int qla2x00_dfs_remove(scsi_qla_host_t *); + +/* Globa function prototypes for multi-q */ +extern int qla25xx_request_irq(struct rsp_que *); +extern int qla25xx_init_req_que(struct scsi_qla_host *, struct req_que *, + uint8_t); +extern int qla25xx_init_rsp_que(struct scsi_qla_host *, struct rsp_que *, + uint8_t); +extern int qla25xx_create_req_que(struct qla_hw_data *, uint16_t, uint8_t, + uint16_t, uint8_t, uint8_t); +extern int qla25xx_create_rsp_que(struct qla_hw_data *, uint16_t, uint8_t, + uint16_t); +extern int qla25xx_update_req_que(struct scsi_qla_host *, uint8_t, uint8_t); +extern void qla2x00_init_response_q_entries(struct rsp_que *); +extern int qla25xx_delete_req_que(struct scsi_qla_host *, struct req_que *); +extern int qla25xx_delete_rsp_que(struct scsi_qla_host *, struct rsp_que *); +extern int qla25xx_create_queues(struct scsi_qla_host *, uint8_t); +extern int qla25xx_delete_queues(struct scsi_qla_host *, uint8_t); #endif /* _QLA_GBL_H */ diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index db8de063e1c..0a6f7297399 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -1668,12 +1668,6 @@ qla2x00_fdmi_register(scsi_qla_host_t *vha) { int rval; - if (IS_QLA2100(vha->hw) || IS_QLA2200(vha->hw)) { - DEBUG2(printk("scsi(%ld): FDMI unsupported on " - "ISP2100/ISP2200.\n", vha->host_no)); - return QLA_SUCCESS; - } - rval = qla2x00_mgmt_svr_login(vha); if (rval) return rval; diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 7bee87f90f6..b1495ec0bf3 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -5,6 +5,7 @@ * See LICENSE.qla2xxx for copyright and licensing details. */ #include "qla_def.h" +#include "qla_gbl.h" #include <linux/delay.h> #include <linux/vmalloc.h> @@ -21,7 +22,6 @@ static int qla2x00_isp_firmware(scsi_qla_host_t *); static void qla2x00_resize_request_q(scsi_qla_host_t *); static int qla2x00_setup_chip(scsi_qla_host_t *); -static void qla2x00_init_response_q_entries(scsi_qla_host_t *); static int qla2x00_init_rings(scsi_qla_host_t *); static int qla2x00_fw_ready(scsi_qla_host_t *); static int qla2x00_configure_hba(scsi_qla_host_t *); @@ -39,6 +39,7 @@ static int qla2x00_find_new_loop_id(scsi_qla_host_t *, fc_port_t *); static struct qla_chip_state_84xx *qla84xx_get_chip(struct scsi_qla_host *); static int qla84xx_init_chip(scsi_qla_host_t *); +static int qla25xx_init_queues(struct qla_hw_data *); /****************************************************************************/ /* QLogic ISP2x00 Hardware Support Functions. */ @@ -59,6 +60,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha) { int rval; struct qla_hw_data *ha = vha->hw; + struct req_que *req = ha->req_q_map[0]; /* Clear adapter flags. */ vha->flags.online = 0; vha->flags.reset_active = 0; @@ -73,6 +75,9 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha) ha->beacon_blink_led = 0; set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags); + set_bit(0, ha->req_qid_map); + set_bit(0, ha->rsp_qid_map); + qla_printk(KERN_INFO, ha, "Configuring PCI space...\n"); rval = ha->isp_ops->pci_config(vha); if (rval) { @@ -90,7 +95,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha) return (rval); } - ha->isp_ops->get_flash_version(vha, ha->req->ring); + ha->isp_ops->get_flash_version(vha, req->ring); qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n"); @@ -603,6 +608,7 @@ qla2x00_chip_diag(scsi_qla_host_t *vha) uint16_t data; uint32_t cnt; uint16_t mb[5]; + struct req_que *req = ha->req_q_map[0]; /* Assume a failed state */ rval = QLA_FUNCTION_FAILED; @@ -671,11 +677,11 @@ qla2x00_chip_diag(scsi_qla_host_t *vha) ha->product_id[3] = mb[4]; /* Adjust fw RISC transfer size */ - if (ha->req->length > 1024) + if (req->length > 1024) ha->fw_transfer_size = REQUEST_ENTRY_SIZE * 1024; else ha->fw_transfer_size = REQUEST_ENTRY_SIZE * - ha->req->length; + req->length; if (IS_QLA2200(ha) && RD_MAILBOX_REG(ha, reg, 7) == QLA2200A_RISC_ROM_VER) { @@ -725,11 +731,12 @@ qla24xx_chip_diag(scsi_qla_host_t *vha) { int rval; struct qla_hw_data *ha = vha->hw; + struct req_que *req = ha->req_q_map[0]; /* Perform RISC reset. */ qla24xx_reset_risc(vha); - ha->fw_transfer_size = REQUEST_ENTRY_SIZE * ha->req->length; + ha->fw_transfer_size = REQUEST_ENTRY_SIZE * req->length; rval = qla2x00_mbx_reg_test(vha); if (rval) { @@ -750,10 +757,12 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) { int rval; uint32_t dump_size, fixed_size, mem_size, req_q_size, rsp_q_size, - eft_size, fce_size; + eft_size, fce_size, mq_size; dma_addr_t tc_dma; void *tc; struct qla_hw_data *ha = vha->hw; + struct req_que *req = ha->req_q_map[0]; + struct rsp_que *rsp = ha->rsp_q_map[0]; if (ha->fw_dump) { qla_printk(KERN_WARNING, ha, @@ -762,7 +771,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) } ha->fw_dumped = 0; - fixed_size = mem_size = eft_size = fce_size = 0; + fixed_size = mem_size = eft_size = fce_size = mq_size = 0; if (IS_QLA2100(ha) || IS_QLA2200(ha)) { fixed_size = sizeof(struct qla2100_fw_dump); } else if (IS_QLA23XX(ha)) { @@ -771,10 +780,12 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) sizeof(uint16_t); } else if (IS_FWI2_CAPABLE(ha)) { fixed_size = IS_QLA25XX(ha) ? - offsetof(struct qla25xx_fw_dump, ext_mem): - offsetof(struct qla24xx_fw_dump, ext_mem); + offsetof(struct qla25xx_fw_dump, ext_mem) : + offsetof(struct qla24xx_fw_dump, ext_mem); mem_size = (ha->fw_memory_size - 0x100000 + 1) * sizeof(uint32_t); + if (ha->mqenable) + mq_size = sizeof(struct qla2xxx_mq_chain); /* Allocate memory for Fibre Channel Event Buffer. */ if (!IS_QLA25XX(ha)) @@ -785,7 +796,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) if (!tc) { qla_printk(KERN_WARNING, ha, "Unable to allocate " "(%d KB) for FCE.\n", FCE_SIZE / 1024); - goto try_eft; + goto cont_alloc; } memset(tc, 0, FCE_SIZE); @@ -797,7 +808,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) dma_free_coherent(&ha->pdev->dev, FCE_SIZE, tc, tc_dma); ha->flags.fce_enabled = 0; - goto try_eft; + goto cont_alloc; } qla_printk(KERN_INFO, ha, "Allocated (%d KB) for FCE...\n", @@ -835,12 +846,12 @@ try_eft: ha->eft = tc; } cont_alloc: - req_q_size = ha->req->length * sizeof(request_t); - rsp_q_size = ha->rsp->length * sizeof(response_t); + req_q_size = req->length * sizeof(request_t); + rsp_q_size = rsp->length * sizeof(response_t); dump_size = offsetof(struct qla2xxx_fw_dump, isp); dump_size += fixed_size + mem_size + req_q_size + rsp_q_size + - eft_size + fce_size; + mq_size + eft_size + fce_size; ha->fw_dump = vmalloc(dump_size); if (!ha->fw_dump) { @@ -855,7 +866,6 @@ cont_alloc: } return; } - qla_printk(KERN_INFO, ha, "Allocated (%d KB) for firmware dump...\n", dump_size / 1024); @@ -894,7 +904,7 @@ qla2x00_resize_request_q(scsi_qla_host_t *vha) dma_addr_t request_dma; request_t *request_ring; struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req; + struct req_que *req = ha->req_q_map[0]; /* Valid only on recent ISPs. */ if (IS_QLA2100(ha) || IS_QLA2200(ha)) @@ -1030,12 +1040,11 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) * * Returns 0 on success. */ -static void -qla2x00_init_response_q_entries(scsi_qla_host_t *vha) +void +qla2x00_init_response_q_entries(struct rsp_que *rsp) { uint16_t cnt; response_t *pkt; - struct rsp_que *rsp = vha->hw->rsp; pkt = rsp->ring_ptr; for (cnt = 0; cnt < rsp->length; cnt++) { @@ -1151,8 +1160,8 @@ qla2x00_config_rings(struct scsi_qla_host *vha) { struct qla_hw_data *ha = vha->hw; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - struct req_que *req = ha->req; - struct rsp_que *rsp = ha->rsp; + struct req_que *req = ha->req_q_map[0]; + struct rsp_que *rsp = ha->rsp_q_map[0]; /* Setup ring parameters in initialization control block. */ ha->init_cb->request_q_outpointer = __constant_cpu_to_le16(0); @@ -1175,12 +1184,15 @@ void qla24xx_config_rings(struct scsi_qla_host *vha) { struct qla_hw_data *ha = vha->hw; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + device_reg_t __iomem *reg = ISP_QUE_REG(ha, 0); + struct device_reg_2xxx __iomem *ioreg = &ha->iobase->isp; + struct qla_msix_entry *msix; struct init_cb_24xx *icb; - struct req_que *req = ha->req; - struct rsp_que *rsp = ha->rsp; + uint16_t rid = 0; + struct req_que *req = ha->req_q_map[0]; + struct rsp_que *rsp = ha->rsp_q_map[0]; - /* Setup ring parameters in initialization control block. */ +/* Setup ring parameters in initialization control block. */ icb = (struct init_cb_24xx *)ha->init_cb; icb->request_q_outpointer = __constant_cpu_to_le16(0); icb->response_q_inpointer = __constant_cpu_to_le16(0); @@ -1191,11 +1203,40 @@ qla24xx_config_rings(struct scsi_qla_host *vha) icb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma)); icb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma)); - WRT_REG_DWORD(®->req_q_in, 0); - WRT_REG_DWORD(®->req_q_out, 0); - WRT_REG_DWORD(®->rsp_q_in, 0); - WRT_REG_DWORD(®->rsp_q_out, 0); - RD_REG_DWORD(®->rsp_q_out); + if (ha->mqenable) { + icb->qos = __constant_cpu_to_le16(QLA_DEFAULT_QUE_QOS); + icb->rid = __constant_cpu_to_le16(rid); + if (ha->flags.msix_enabled) { + msix = &ha->msix_entries[1]; + DEBUG2_17(printk(KERN_INFO + "Reistering vector 0x%x for base que\n", msix->entry)); + icb->msix = cpu_to_le16(msix->entry); + } + /* Use alternate PCI bus number */ + if (MSB(rid)) + icb->firmware_options_2 |= + __constant_cpu_to_le32(BIT_19); + /* Use alternate PCI devfn */ + if (LSB(rid)) + icb->firmware_options_2 |= + __constant_cpu_to_le32(BIT_18); + + icb->firmware_options_2 |= __constant_cpu_to_le32(BIT_22); + icb->firmware_options_2 |= __constant_cpu_to_le32(BIT_23); + ha->rsp_q_map[0]->options = icb->firmware_options_2; + + WRT_REG_DWORD(®->isp25mq.req_q_in, 0); + WRT_REG_DWORD(®->isp25mq.req_q_out, 0); + WRT_REG_DWORD(®->isp25mq.rsp_q_in, 0); + WRT_REG_DWORD(®->isp25mq.rsp_q_out, 0); + } else { + WRT_REG_DWORD(®->isp24.req_q_in, 0); + WRT_REG_DWORD(®->isp24.req_q_out, 0); + WRT_REG_DWORD(®->isp24.rsp_q_in, 0); + WRT_REG_DWORD(®->isp24.rsp_q_out, 0); + } + /* PCI posting */ + RD_REG_DWORD(&ioreg->hccr); } /** @@ -1214,8 +1255,8 @@ qla2x00_init_rings(scsi_qla_host_t *vha) unsigned long flags = 0; int cnt; struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req; - struct rsp_que *rsp = ha->rsp; + struct req_que *req = ha->req_q_map[0]; + struct rsp_que *rsp = ha->rsp_q_map[0]; struct mid_init_cb_24xx *mid_init_cb = (struct mid_init_cb_24xx *) ha->init_cb; @@ -1239,7 +1280,7 @@ qla2x00_init_rings(scsi_qla_host_t *vha) rsp->ring_index = 0; /* Initialize response queue entries */ - qla2x00_init_response_q_entries(vha); + qla2x00_init_response_q_entries(rsp); ha->isp_ops->config_rings(vha); @@ -2039,10 +2080,8 @@ qla2x00_configure_loop(scsi_qla_host_t *vha) if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) { if (test_bit(LOCAL_LOOP_UPDATE, &save_flags)) set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); - if (test_bit(RSCN_UPDATE, &save_flags)) { + if (test_bit(RSCN_UPDATE, &save_flags)) set_bit(RSCN_UPDATE, &vha->dpc_flags); - vha->flags.rscn_queue_overflow = 1; - } } return (rval); @@ -3169,10 +3208,11 @@ qla2x00_local_device_login(scsi_qla_host_t *vha, fc_port_t *fcport) int qla2x00_loop_resync(scsi_qla_host_t *vha) { - int rval; + int rval = QLA_SUCCESS; uint32_t wait_time; - - rval = QLA_SUCCESS; + struct qla_hw_data *ha = vha->hw; + struct req_que *req = ha->req_q_map[0]; + struct rsp_que *rsp = ha->rsp_q_map[0]; atomic_set(&vha->loop_state, LOOP_UPDATE); clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags); @@ -3184,7 +3224,8 @@ qla2x00_loop_resync(scsi_qla_host_t *vha) atomic_set(&vha->loop_state, LOOP_UPDATE); /* Issue a marker after FW becomes ready. */ - qla2x00_marker(vha, 0, 0, MK_SYNC_ALL); + qla2x00_marker(vha, req, rsp, 0, 0, + MK_SYNC_ALL); vha->marker_needed = 0; /* Remap devices on Loop. */ @@ -3237,6 +3278,7 @@ qla2x00_abort_isp(scsi_qla_host_t *vha) uint8_t status = 0; struct qla_hw_data *ha = vha->hw; struct scsi_qla_host *vp; + struct req_que *req = ha->req_q_map[0]; if (vha->flags.online) { vha->flags.online = 0; @@ -3262,7 +3304,7 @@ qla2x00_abort_isp(scsi_qla_host_t *vha) /* Requeue all commands in outstanding command list. */ qla2x00_abort_all_cmds(vha, DID_RESET << 16); - ha->isp_ops->get_flash_version(vha, ha->req->ring); + ha->isp_ops->get_flash_version(vha, req->ring); ha->isp_ops->nvram_config(vha); @@ -3376,6 +3418,8 @@ qla2x00_restart_isp(scsi_qla_host_t *vha) uint8_t status = 0; uint32_t wait_time; struct qla_hw_data *ha = vha->hw; + struct req_que *req = ha->req_q_map[0]; + struct rsp_que *rsp = ha->rsp_q_map[0]; /* If firmware needs to be loaded */ if (qla2x00_isp_firmware(vha)) { @@ -3387,13 +3431,16 @@ qla2x00_restart_isp(scsi_qla_host_t *vha) if (!status && !(status = qla2x00_init_rings(vha))) { clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags); + /* Initialize the queues in use */ + qla25xx_init_queues(ha); + status = qla2x00_fw_ready(vha); if (!status) { DEBUG(printk("%s(): Start configure loop, " "status = %d\n", __func__, status)); /* Issue a marker after FW becomes ready. */ - qla2x00_marker(vha, 0, 0, MK_SYNC_ALL); + qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL); vha->flags.online = 1; /* Wait at most MAX_TARGET RSCNs for a stable link. */ @@ -3419,6 +3466,46 @@ qla2x00_restart_isp(scsi_qla_host_t *vha) return (status); } +static int +qla25xx_init_queues(struct qla_hw_data *ha) +{ + struct rsp_que *rsp = NULL; + struct req_que *req = NULL; + struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); + int ret = -1; + int i; + + for (i = 1; i < ha->max_queues; i++) { + rsp = ha->rsp_q_map[i]; + if (rsp) { + rsp->options &= ~BIT_0; + ret = qla25xx_init_rsp_que(base_vha, rsp, rsp->options); + if (ret != QLA_SUCCESS) + DEBUG2_17(printk(KERN_WARNING + "%s Rsp que:%d init failed\n", __func__, + rsp->id)); + else + DEBUG2_17(printk(KERN_INFO + "%s Rsp que:%d inited\n", __func__, + rsp->id)); + } + req = ha->req_q_map[i]; + if (req) { + req->options &= ~BIT_0; + ret = qla25xx_init_req_que(base_vha, req, req->options); + if (ret != QLA_SUCCESS) + DEBUG2_17(printk(KERN_WARNING + "%s Req que:%d init failed\n", __func__, + req->id)); + else + DEBUG2_17(printk(KERN_WARNING + "%s Rsp que:%d inited\n", __func__, + req->id)); + } + } + return ret; +} + /* * qla2x00_reset_adapter * Reset adapter. @@ -3736,7 +3823,7 @@ qla24xx_nvram_config(scsi_qla_host_t *vha) static int qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr) { - int rval; + int rval = QLA_SUCCESS; int segments, fragment; uint32_t faddr; uint32_t *dcode, dlen; @@ -3744,11 +3831,12 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr) uint32_t risc_size; uint32_t i; struct qla_hw_data *ha = vha->hw; + struct req_que *req = ha->req_q_map[0]; rval = QLA_SUCCESS; segments = FA_RISC_CODE_SEGMENTS; faddr = ha->flt_region_fw; - dcode = (uint32_t *)ha->req->ring; + dcode = (uint32_t *)req->ring; *srisc_addr = 0; /* Validate firmware image by checking version. */ @@ -3790,7 +3878,7 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr) for (i = 0; i < dlen; i++) dcode[i] = swab32(dcode[i]); - rval = qla2x00_load_ram(vha, ha->req->dma, risc_addr, + rval = qla2x00_load_ram(vha, req->dma, risc_addr, dlen); if (rval) { DEBUG(printk("scsi(%ld):[ERROR] Failed to load " @@ -3826,6 +3914,7 @@ qla2x00_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) uint32_t risc_addr, risc_size, fwclen, wlen, *seg; struct fw_blob *blob; struct qla_hw_data *ha = vha->hw; + struct req_que *req = ha->req_q_map[0]; /* Load firmware blob. */ blob = qla2x00_request_firmware(vha); @@ -3838,7 +3927,7 @@ qla2x00_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) rval = QLA_SUCCESS; - wcode = (uint16_t *)ha->req->ring; + wcode = (uint16_t *)req->ring; *srisc_addr = 0; fwcode = (uint16_t *)blob->fw->data; fwclen = 0; @@ -3891,7 +3980,7 @@ qla2x00_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) for (i = 0; i < wlen; i++) wcode[i] = swab16(fwcode[i]); - rval = qla2x00_load_ram(vha, ha->req->dma, risc_addr, + rval = qla2x00_load_ram(vha, req->dma, risc_addr, wlen); if (rval) { DEBUG(printk("scsi(%ld):[ERROR] Failed to load " @@ -3930,6 +4019,7 @@ qla24xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) struct fw_blob *blob; uint32_t *fwcode, fwclen; struct qla_hw_data *ha = vha->hw; + struct req_que *req = ha->req_q_map[0]; /* Load firmware blob. */ blob = qla2x00_request_firmware(vha); @@ -3947,7 +4037,7 @@ qla24xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) rval = QLA_SUCCESS; segments = FA_RISC_CODE_SEGMENTS; - dcode = (uint32_t *)ha->req->ring; + dcode = (uint32_t *)req->ring; *srisc_addr = 0; fwcode = (uint32_t *)blob->fw->data; fwclen = 0; @@ -4001,7 +4091,7 @@ qla24xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) for (i = 0; i < dlen; i++) dcode[i] = swab32(fwcode[i]); - rval = qla2x00_load_ram(vha, ha->req->dma, risc_addr, + rval = qla2x00_load_ram(vha, req->dma, risc_addr, dlen); if (rval) { DEBUG(printk("scsi(%ld):[ERROR] Failed to load " @@ -4060,6 +4150,8 @@ qla24xx_configure_vhba(scsi_qla_host_t *vha) uint16_t mb[MAILBOX_REGISTER_COUNT]; struct qla_hw_data *ha = vha->hw; struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); + struct req_que *req = ha->req_q_map[0]; + struct rsp_que *rsp = ha->rsp_q_map[0]; if (!vha->vp_idx) return -EINVAL; @@ -4067,7 +4159,7 @@ qla24xx_configure_vhba(scsi_qla_host_t *vha) rval = qla2x00_fw_ready(base_vha); if (rval == QLA_SUCCESS) { clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags); - qla2x00_marker(vha, 0, 0, MK_SYNC_ALL); + qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL); } vha->flags.management_server_logged_in = 0; diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index 8ce35472068..507a6e954f5 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -41,32 +41,6 @@ qla2x00_poll(struct rsp_que *rsp) local_irq_restore(flags); } -/** - * qla2x00_issue_marker() - Issue a Marker IOCB if necessary. - * @ha: HA context - * @ha_locked: is function called with the hardware lock - * - * Returns non-zero if a failure occurred, else zero. - */ -static inline int -qla2x00_issue_marker(scsi_qla_host_t *vha, int ha_locked) -{ - /* Send marker if required */ - if (vha->marker_needed != 0) { - if (ha_locked) { - if (__qla2x00_marker(vha, 0, 0, MK_SYNC_ALL) != - QLA_SUCCESS) - return (QLA_FUNCTION_FAILED); - } else { - if (qla2x00_marker(vha, 0, 0, MK_SYNC_ALL) != - QLA_SUCCESS) - return (QLA_FUNCTION_FAILED); - } - vha->marker_needed = 0; - } - return (QLA_SUCCESS); -} - static inline uint8_t * host_to_fcp_swap(uint8_t *fcp, uint32_t bsize) { diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 0c145c9e0cd..6d2bd97c3b1 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -11,8 +11,9 @@ #include <scsi/scsi_tcq.h> -static request_t *qla2x00_req_pkt(scsi_qla_host_t *); -static void qla2x00_isp_cmd(scsi_qla_host_t *); +static request_t *qla2x00_req_pkt(struct scsi_qla_host *, struct req_que *, + struct rsp_que *rsp); +static void qla2x00_isp_cmd(struct scsi_qla_host *, struct req_que *); /** * qla2x00_get_cmd_direction() - Determine control_flag data direction. @@ -91,10 +92,9 @@ qla2x00_calc_iocbs_64(uint16_t dsds) * Returns a pointer to the Continuation Type 0 IOCB packet. */ static inline cont_entry_t * -qla2x00_prep_cont_type0_iocb(scsi_qla_host_t *vha) +qla2x00_prep_cont_type0_iocb(struct req_que *req, struct scsi_qla_host *vha) { cont_entry_t *cont_pkt; - struct req_que *req = vha->hw->req; /* Adjust ring index. */ req->ring_index++; if (req->ring_index == req->length) { @@ -120,10 +120,9 @@ qla2x00_prep_cont_type0_iocb(scsi_qla_host_t *vha) * Returns a pointer to the continuation type 1 IOCB packet. */ static inline cont_a64_entry_t * -qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha) +qla2x00_prep_cont_type1_iocb(struct req_que *req, scsi_qla_host_t *vha) { cont_a64_entry_t *cont_pkt; - struct req_que *req = vha->hw->req; /* Adjust ring index. */ req->ring_index++; @@ -160,6 +159,8 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt, struct scsi_cmnd *cmd; struct scatterlist *sg; int i; + struct req_que *req; + uint16_t que_id; cmd = sp->cmd; @@ -174,6 +175,8 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt, } vha = sp->vha; + que_id = vha->req_ques[0]; + req = vha->hw->req_q_map[que_id]; cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp)); @@ -191,7 +194,7 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt, * Seven DSDs are available in the Continuation * Type 0 IOCB. */ - cont_pkt = qla2x00_prep_cont_type0_iocb(vha); + cont_pkt = qla2x00_prep_cont_type0_iocb(req, vha); cur_dsd = (uint32_t *)&cont_pkt->dseg_0_address; avail_dsds = 7; } @@ -219,6 +222,8 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt, struct scsi_cmnd *cmd; struct scatterlist *sg; int i; + struct req_que *req; + uint16_t que_id; cmd = sp->cmd; @@ -233,6 +238,8 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt, } vha = sp->vha; + que_id = vha->req_ques[0]; + req = vha->hw->req_q_map[que_id]; cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp)); @@ -251,7 +258,7 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt, * Five DSDs are available in the Continuation * Type 1 IOCB. */ - cont_pkt = qla2x00_prep_cont_type1_iocb(vha); + cont_pkt = qla2x00_prep_cont_type1_iocb(req, vha); cur_dsd = (uint32_t *)cont_pkt->dseg_0_address; avail_dsds = 5; } @@ -287,6 +294,7 @@ qla2x00_start_scsi(srb_t *sp) struct device_reg_2xxx __iomem *reg; struct qla_hw_data *ha; struct req_que *req; + struct rsp_que *rsp; /* Setup device pointers. */ ret = 0; @@ -294,13 +302,15 @@ qla2x00_start_scsi(srb_t *sp) ha = vha->hw; reg = &ha->iobase->isp; cmd = sp->cmd; - req = ha->req; + req = ha->req_q_map[0]; + rsp = ha->rsp_q_map[0]; /* So we know we haven't pci_map'ed anything yet */ tot_dsds = 0; /* Send marker if required */ if (vha->marker_needed != 0) { - if (qla2x00_marker(vha, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) + if (qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL) + != QLA_SUCCESS) return (QLA_FUNCTION_FAILED); vha->marker_needed = 0; } @@ -392,8 +402,8 @@ qla2x00_start_scsi(srb_t *sp) /* Manage unprocessed RIO/ZIO commands in response queue. */ if (vha->flags.process_response_queue && - ha->rsp->ring_ptr->signature != RESPONSE_PROCESSED) - qla2x00_process_response_queue(vha); + rsp->ring_ptr->signature != RESPONSE_PROCESSED) + qla2x00_process_response_queue(rsp); spin_unlock_irqrestore(&ha->hardware_lock, flags); return (QLA_SUCCESS); @@ -419,8 +429,9 @@ queuing_error: * Returns non-zero if a failure occurred, else zero. */ int -__qla2x00_marker(scsi_qla_host_t *vha, uint16_t loop_id, uint16_t lun, - uint8_t type) +__qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req, + struct rsp_que *rsp, uint16_t loop_id, + uint16_t lun, uint8_t type) { mrk_entry_t *mrk; struct mrk_entry_24xx *mrk24; @@ -428,7 +439,7 @@ __qla2x00_marker(scsi_qla_host_t *vha, uint16_t loop_id, uint16_t lun, scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); mrk24 = NULL; - mrk = (mrk_entry_t *)qla2x00_req_pkt(base_vha); + mrk = (mrk_entry_t *)qla2x00_req_pkt(vha, req, rsp); if (mrk == NULL) { DEBUG2_3(printk("%s(%ld): failed to allocate Marker IOCB.\n", __func__, base_vha->host_no)); @@ -453,22 +464,22 @@ __qla2x00_marker(scsi_qla_host_t *vha, uint16_t loop_id, uint16_t lun, } wmb(); - qla2x00_isp_cmd(base_vha); + qla2x00_isp_cmd(vha, req); return (QLA_SUCCESS); } int -qla2x00_marker(scsi_qla_host_t *vha, uint16_t loop_id, uint16_t lun, - uint8_t type) +qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req, + struct rsp_que *rsp, uint16_t loop_id, uint16_t lun, + uint8_t type) { int ret; unsigned long flags = 0; - struct qla_hw_data *ha = vha->hw; - spin_lock_irqsave(&ha->hardware_lock, flags); - ret = __qla2x00_marker(vha, loop_id, lun, type); - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_lock_irqsave(&vha->hw->hardware_lock, flags); + ret = __qla2x00_marker(vha, req, rsp, loop_id, lun, type); + spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); return (ret); } @@ -482,27 +493,32 @@ qla2x00_marker(scsi_qla_host_t *vha, uint16_t loop_id, uint16_t lun, * Returns NULL if function failed, else, a pointer to the request packet. */ static request_t * -qla2x00_req_pkt(scsi_qla_host_t *vha) +qla2x00_req_pkt(struct scsi_qla_host *vha, struct req_que *req, + struct rsp_que *rsp) { struct qla_hw_data *ha = vha->hw; - device_reg_t __iomem *reg = ha->iobase; + device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id); request_t *pkt = NULL; uint16_t cnt; uint32_t *dword_ptr; uint32_t timer; uint16_t req_cnt = 1; - struct req_que *req = ha->req; /* Wait 1 second for slot. */ for (timer = HZ; timer; timer--) { if ((req_cnt + 2) >= req->cnt) { /* Calculate number of free request entries. */ - if (IS_FWI2_CAPABLE(ha)) - cnt = (uint16_t)RD_REG_DWORD( - ®->isp24.req_q_out); - else - cnt = qla2x00_debounce_register( - ISP_REQ_Q_OUT(ha, ®->isp)); + if (ha->mqenable) + cnt = (uint16_t) + RD_REG_DWORD(®->isp25mq.req_q_out); + else { + if (IS_FWI2_CAPABLE(ha)) + cnt = (uint16_t)RD_REG_DWORD( + ®->isp24.req_q_out); + else + cnt = qla2x00_debounce_register( + ISP_REQ_Q_OUT(ha, ®->isp)); + } if (req->ring_index < cnt) req->cnt = cnt - req->ring_index; else @@ -536,7 +552,7 @@ qla2x00_req_pkt(scsi_qla_host_t *vha) /* Check for pending interrupts. */ /* During init we issue marker directly */ if (!vha->marker_needed && !vha->flags.init_done) - qla2x00_poll(ha->rsp); + qla2x00_poll(rsp); spin_lock_irq(&ha->hardware_lock); } if (!pkt) { @@ -553,11 +569,10 @@ qla2x00_req_pkt(scsi_qla_host_t *vha) * Note: The caller must hold the hardware lock before calling this routine. */ static void -qla2x00_isp_cmd(scsi_qla_host_t *vha) +qla2x00_isp_cmd(struct scsi_qla_host *vha, struct req_que *req) { struct qla_hw_data *ha = vha->hw; - device_reg_t __iomem *reg = ha->iobase; - struct req_que *req = ha->req; + device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id); DEBUG5(printk("%s(): IOCB data:\n", __func__)); DEBUG5(qla2x00_dump_buffer( @@ -572,12 +587,17 @@ qla2x00_isp_cmd(scsi_qla_host_t *vha) req->ring_ptr++; /* Set chip new ring index. */ - if (IS_FWI2_CAPABLE(ha)) { - WRT_REG_DWORD(®->isp24.req_q_in, req->ring_index); - RD_REG_DWORD_RELAXED(®->isp24.req_q_in); - } else { - WRT_REG_WORD(ISP_REQ_Q_IN(ha, ®->isp), req->ring_index); - RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, ®->isp)); + if (ha->mqenable) + RD_REG_DWORD(®->isp25mq.req_q_out); + else { + if (IS_FWI2_CAPABLE(ha)) { + WRT_REG_DWORD(®->isp24.req_q_in, req->ring_index); + RD_REG_DWORD_RELAXED(®->isp24.req_q_in); + } else { + WRT_REG_WORD(ISP_REQ_Q_IN(ha, ®->isp), + req->ring_index); + RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, ®->isp)); + } } } @@ -622,6 +642,8 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt, struct scsi_cmnd *cmd; struct scatterlist *sg; int i; + uint16_t que_id; + struct req_que *req; cmd = sp->cmd; @@ -636,6 +658,8 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt, } vha = sp->vha; + que_id = vha->req_ques[0]; + req = vha->hw->req_q_map[que_id]; /* Set transfer direction */ if (cmd->sc_data_direction == DMA_TO_DEVICE) { @@ -666,7 +690,7 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt, * Five DSDs are available in the Continuation * Type 1 IOCB. */ - cont_pkt = qla2x00_prep_cont_type1_iocb(vha); + cont_pkt = qla2x00_prep_cont_type1_iocb(req, vha); cur_dsd = (uint32_t *)cont_pkt->dseg_0_address; avail_dsds = 5; } @@ -691,8 +715,6 @@ qla24xx_start_scsi(srb_t *sp) { int ret, nseg; unsigned long flags; - scsi_qla_host_t *vha; - struct scsi_cmnd *cmd; uint32_t *clr_ptr; uint32_t index; uint32_t handle; @@ -700,23 +722,32 @@ qla24xx_start_scsi(srb_t *sp) uint16_t cnt; uint16_t req_cnt; uint16_t tot_dsds; - struct device_reg_24xx __iomem *reg; - struct qla_hw_data *ha; - struct req_que *req; + struct req_que *req = NULL; + struct rsp_que *rsp = NULL; + struct scsi_cmnd *cmd = sp->cmd; + struct scsi_qla_host *vha = sp->vha; + struct qla_hw_data *ha = vha->hw; + device_reg_t __iomem *reg; + uint16_t que_id; /* Setup device pointers. */ ret = 0; - vha = sp->vha; - ha = vha->hw; - reg = &ha->iobase->isp24; - cmd = sp->cmd; - req = ha->req; + que_id = vha->req_ques[0]; + + req = ha->req_q_map[que_id]; + reg = ISP_QUE_REG(ha, req->id); + + if (req->rsp) + rsp = req->rsp; + else + rsp = ha->rsp_q_map[que_id]; /* So we know we haven't pci_map'ed anything yet */ tot_dsds = 0; /* Send marker if required */ if (vha->marker_needed != 0) { - if (qla2x00_marker(vha, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) + if (qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL) + != QLA_SUCCESS) return QLA_FUNCTION_FAILED; vha->marker_needed = 0; } @@ -749,7 +780,13 @@ qla24xx_start_scsi(srb_t *sp) req_cnt = qla24xx_calc_iocbs(tot_dsds); if (req->cnt < (req_cnt + 2)) { - cnt = (uint16_t)RD_REG_DWORD_RELAXED(®->req_q_out); + if (ha->mqenable) + cnt = (uint16_t) + RD_REG_DWORD_RELAXED(®->isp25mq.req_q_out); + else + cnt = (uint16_t) + RD_REG_DWORD_RELAXED(®->isp24.req_q_out); + if (req->ring_index < cnt) req->cnt = cnt - req->ring_index; else @@ -809,13 +846,17 @@ qla24xx_start_scsi(srb_t *sp) sp->flags |= SRB_DMA_VALID; /* Set chip new ring index. */ - WRT_REG_DWORD(®->req_q_in, req->ring_index); - RD_REG_DWORD_RELAXED(®->req_q_in); /* PCI Posting. */ + if (ha->mqenable) + WRT_REG_DWORD(®->isp25mq.req_q_in, req->ring_index); + else { + WRT_REG_DWORD(®->isp24.req_q_in, req->ring_index); + RD_REG_DWORD_RELAXED(®->isp24.req_q_in); + } /* Manage unprocessed RIO/ZIO commands in response queue. */ if (vha->flags.process_response_queue && - ha->rsp->ring_ptr->signature != RESPONSE_PROCESSED) - qla24xx_process_response_queue(vha); + rsp->ring_ptr->signature != RESPONSE_PROCESSED) + qla24xx_process_response_queue(rsp); spin_unlock_irqrestore(&ha->hardware_lock, flags); return QLA_SUCCESS; @@ -828,3 +869,4 @@ queuing_error: return QLA_FUNCTION_FAILED; } + diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 89d327117aa..eb4b43d7697 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -10,10 +10,12 @@ #include <scsi/scsi_tcq.h> static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t); -static void qla2x00_process_completed_request(struct scsi_qla_host *, uint32_t); -static void qla2x00_status_entry(scsi_qla_host_t *, void *); +static void qla2x00_process_completed_request(struct scsi_qla_host *, + struct req_que *, uint32_t); +static void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *); static void qla2x00_status_cont_entry(scsi_qla_host_t *, sts_cont_entry_t *); -static void qla2x00_error_entry(scsi_qla_host_t *, sts_entry_t *); +static void qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *, + sts_entry_t *); static struct scsi_qla_host *qla2x00_get_rsp_host(struct rsp_que *); /** @@ -83,7 +85,7 @@ qla2100_intr_handler(int irq, void *dev_id) mb[1] = RD_MAILBOX_REG(ha, reg, 1); mb[2] = RD_MAILBOX_REG(ha, reg, 2); mb[3] = RD_MAILBOX_REG(ha, reg, 3); - qla2x00_async_event(vha, mb); + qla2x00_async_event(vha, rsp, mb); } else { /*EMPTY*/ DEBUG2(printk("scsi(%ld): Unrecognized " @@ -94,7 +96,7 @@ qla2100_intr_handler(int irq, void *dev_id) WRT_REG_WORD(®->semaphore, 0); RD_REG_WORD(®->semaphore); } else { - qla2x00_process_response_queue(vha); + qla2x00_process_response_queue(rsp); WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); RD_REG_WORD(®->hccr); @@ -190,21 +192,21 @@ qla2300_intr_handler(int irq, void *dev_id) mb[1] = RD_MAILBOX_REG(ha, reg, 1); mb[2] = RD_MAILBOX_REG(ha, reg, 2); mb[3] = RD_MAILBOX_REG(ha, reg, 3); - qla2x00_async_event(vha, mb); + qla2x00_async_event(vha, rsp, mb); break; case 0x13: - qla2x00_process_response_queue(vha); + qla2x00_process_response_queue(rsp); break; case 0x15: mb[0] = MBA_CMPLT_1_16BIT; mb[1] = MSW(stat); - qla2x00_async_event(vha, mb); + qla2x00_async_event(vha, rsp, mb); break; case 0x16: mb[0] = MBA_SCSI_COMPLETION; mb[1] = MSW(stat); mb[2] = RD_MAILBOX_REG(ha, reg, 2); - qla2x00_async_event(vha, mb); + qla2x00_async_event(vha, rsp, mb); break; default: DEBUG2(printk("scsi(%ld): Unrecognized interrupt type " @@ -270,7 +272,7 @@ qla2x00_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) * @mb: Mailbox registers (0 - 3) */ void -qla2x00_async_event(scsi_qla_host_t *vha, uint16_t *mb) +qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) { #define LS_UNKNOWN 2 static char *link_speeds[5] = { "1", "2", "?", "4", "8" }; @@ -344,7 +346,8 @@ qla2x00_async_event(scsi_qla_host_t *vha, uint16_t *mb) break; for (cnt = 0; cnt < handle_cnt; cnt++) - qla2x00_process_completed_request(vha, handles[cnt]); + qla2x00_process_completed_request(vha, rsp->req, + handles[cnt]); break; case MBA_RESET: /* Reset */ @@ -554,6 +557,10 @@ qla2x00_async_event(scsi_qla_host_t *vha, uint16_t *mb) break; case MBA_PORT_UPDATE: /* Port database update */ + /* Only handle SCNs for our Vport index. */ + if (vha->vp_idx && vha->vp_idx != (mb[3] & 0xff)) + break; + /* * If PORT UPDATE is global (received LIP_OCCURRED/LIP_RESET * event etc. earlier indicating loop is down) then process @@ -641,9 +648,9 @@ qla2x00_async_event(scsi_qla_host_t *vha, uint16_t *mb) vha->host_no)); if (IS_FWI2_CAPABLE(ha)) - qla24xx_process_response_queue(vha); + qla24xx_process_response_queue(rsp); else - qla2x00_process_response_queue(vha); + qla2x00_process_response_queue(rsp); break; case MBA_DISCARD_RND_FRAME: @@ -694,15 +701,21 @@ qla2x00_async_event(scsi_qla_host_t *vha, uint16_t *mb) } if (!vha->vp_idx && ha->num_vhosts) - qla2x00_alert_all_vps(ha, mb); + qla2x00_alert_all_vps(rsp, mb); } static void qla2x00_adjust_sdev_qdepth_up(struct scsi_device *sdev, void *data) { fc_port_t *fcport = data; - struct qla_hw_data *ha = fcport->vha->hw; - if (ha->req->max_q_depth <= sdev->queue_depth) + struct scsi_qla_host *vha = fcport->vha; + struct qla_hw_data *ha = vha->hw; + struct req_que *req = NULL; + + req = ha->req_q_map[vha->req_ques[0]]; + if (!req) + return; + if (req->max_q_depth <= sdev->queue_depth) return; if (sdev->ordered_tags) @@ -735,14 +748,14 @@ qla2x00_adjust_sdev_qdepth_down(struct scsi_device *sdev, void *data) } static inline void -qla2x00_ramp_up_queue_depth(scsi_qla_host_t *vha, srb_t *sp) +qla2x00_ramp_up_queue_depth(scsi_qla_host_t *vha, struct req_que *req, + srb_t *sp) { fc_port_t *fcport; struct scsi_device *sdev; - struct qla_hw_data *ha = vha->hw; sdev = sp->cmd->device; - if (sdev->queue_depth >= ha->req->max_q_depth) + if (sdev->queue_depth >= req->max_q_depth) return; fcport = sp->fcport; @@ -763,11 +776,11 @@ qla2x00_ramp_up_queue_depth(scsi_qla_host_t *vha, srb_t *sp) * @index: SRB index */ static void -qla2x00_process_completed_request(struct scsi_qla_host *vha, uint32_t index) +qla2x00_process_completed_request(struct scsi_qla_host *vha, + struct req_que *req, uint32_t index) { srb_t *sp; struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req; /* Validate handle. */ if (index >= MAX_OUTSTANDING_COMMANDS) { @@ -791,8 +804,8 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha, uint32_t index) /* Save ISP completion status */ sp->cmd->result = DID_OK << 16; - qla2x00_ramp_up_queue_depth(vha, sp); - qla2x00_sp_compl(vha, sp); + qla2x00_ramp_up_queue_depth(vha, req, sp); + qla2x00_sp_compl(ha, sp); } else { DEBUG2(printk("scsi(%ld): Invalid ISP SCSI completion handle\n", vha->host_no)); @@ -808,14 +821,16 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha, uint32_t index) * @ha: SCSI driver HA context */ void -qla2x00_process_response_queue(struct scsi_qla_host *vha) +qla2x00_process_response_queue(struct rsp_que *rsp) { - struct qla_hw_data *ha = vha->hw; + struct scsi_qla_host *vha; + struct qla_hw_data *ha = rsp->hw; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; sts_entry_t *pkt; uint16_t handle_cnt; uint16_t cnt; - struct rsp_que *rsp = ha->rsp; + + vha = qla2x00_get_rsp_host(rsp); if (!vha->flags.online) return; @@ -835,7 +850,7 @@ qla2x00_process_response_queue(struct scsi_qla_host *vha) DEBUG3(printk(KERN_INFO "scsi(%ld): Process error entry.\n", vha->host_no)); - qla2x00_error_entry(vha, pkt); + qla2x00_error_entry(vha, rsp, pkt); ((response_t *)pkt)->signature = RESPONSE_PROCESSED; wmb(); continue; @@ -843,19 +858,19 @@ qla2x00_process_response_queue(struct scsi_qla_host *vha) switch (pkt->entry_type) { case STATUS_TYPE: - qla2x00_status_entry(vha, pkt); + qla2x00_status_entry(vha, rsp, pkt); break; case STATUS_TYPE_21: handle_cnt = ((sts21_entry_t *)pkt)->handle_count; for (cnt = 0; cnt < handle_cnt; cnt++) { - qla2x00_process_completed_request(vha, + qla2x00_process_completed_request(vha, rsp->req, ((sts21_entry_t *)pkt)->handle[cnt]); } break; case STATUS_TYPE_22: handle_cnt = ((sts22_entry_t *)pkt)->handle_count; for (cnt = 0; cnt < handle_cnt; cnt++) { - qla2x00_process_completed_request(vha, + qla2x00_process_completed_request(vha, rsp->req, ((sts22_entry_t *)pkt)->handle[cnt]); } break; @@ -914,7 +929,7 @@ qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len) * @pkt: Entry pointer */ static void -qla2x00_status_entry(scsi_qla_host_t *vha, void *pkt) +qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) { srb_t *sp; fc_port_t *fcport; @@ -928,7 +943,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, void *pkt) uint32_t sense_len, rsp_info_len, resid_len, fw_resid_len; uint8_t *rsp_info, *sense_data; struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req; + struct req_que *req = rsp->req; sts = (sts_entry_t *) pkt; sts24 = (struct sts_entry_24xx *) pkt; @@ -942,7 +957,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, void *pkt) /* Fast path completion. */ if (comp_status == CS_COMPLETE && scsi_status == 0) { - qla2x00_process_completed_request(vha, sts->handle); + qla2x00_process_completed_request(vha, req, sts->handle); return; } @@ -1012,7 +1027,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, void *pkt) rsp_info[5], rsp_info[6], rsp_info[7])); cp->result = DID_BUS_BUSY << 16; - qla2x00_sp_compl(vha, sp); + qla2x00_sp_compl(ha, sp); return; } } @@ -1276,7 +1291,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, void *pkt) /* Place command on done queue. */ if (vha->status_srb == NULL) - qla2x00_sp_compl(vha, sp); + qla2x00_sp_compl(ha, sp); } /** @@ -1325,7 +1340,7 @@ qla2x00_status_cont_entry(scsi_qla_host_t *vha, sts_cont_entry_t *pkt) /* Place command on done queue. */ if (sp->request_sense_length == 0) { vha->status_srb = NULL; - qla2x00_sp_compl(vha, sp); + qla2x00_sp_compl(ha, sp); } } } @@ -1336,11 +1351,11 @@ qla2x00_status_cont_entry(scsi_qla_host_t *vha, sts_cont_entry_t *pkt) * @pkt: Entry pointer */ static void -qla2x00_error_entry(scsi_qla_host_t *vha, sts_entry_t *pkt) +qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt) { srb_t *sp; struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req; + struct req_que *req = rsp->req; #if defined(QL_DEBUG_LEVEL_2) if (pkt->entry_status & RF_INV_E_ORDER) qla_printk(KERN_ERR, ha, "%s: Invalid Entry Order\n", __func__); @@ -1377,7 +1392,7 @@ qla2x00_error_entry(scsi_qla_host_t *vha, sts_entry_t *pkt) } else { sp->cmd->result = DID_ERROR << 16; } - qla2x00_sp_compl(vha, sp); + qla2x00_sp_compl(ha, sp); } else if (pkt->entry_type == COMMAND_A64_TYPE || pkt->entry_type == COMMAND_TYPE || pkt->entry_type == COMMAND_TYPE_7) { @@ -1428,12 +1443,14 @@ qla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) * @ha: SCSI driver HA context */ void -qla24xx_process_response_queue(struct scsi_qla_host *vha) +qla24xx_process_response_queue(struct rsp_que *rsp) { - struct qla_hw_data *ha = vha->hw; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + struct qla_hw_data *ha = rsp->hw; + device_reg_t __iomem *reg = ISP_QUE_REG(ha, rsp->id); struct sts_entry_24xx *pkt; - struct rsp_que *rsp = ha->rsp; + struct scsi_qla_host *vha; + + vha = qla2x00_get_rsp_host(rsp); if (!vha->flags.online) return; @@ -1453,7 +1470,7 @@ qla24xx_process_response_queue(struct scsi_qla_host *vha) DEBUG3(printk(KERN_INFO "scsi(%ld): Process error entry.\n", vha->host_no)); - qla2x00_error_entry(vha, (sts_entry_t *) pkt); + qla2x00_error_entry(vha, rsp, (sts_entry_t *) pkt); ((response_t *)pkt)->signature = RESPONSE_PROCESSED; wmb(); continue; @@ -1461,7 +1478,7 @@ qla24xx_process_response_queue(struct scsi_qla_host *vha) switch (pkt->entry_type) { case STATUS_TYPE: - qla2x00_status_entry(vha, pkt); + qla2x00_status_entry(vha, rsp, pkt); break; case STATUS_CONT_TYPE: qla2x00_status_cont_entry(vha, (sts_cont_entry_t *)pkt); @@ -1483,7 +1500,10 @@ qla24xx_process_response_queue(struct scsi_qla_host *vha) } /* Adjust ring index */ - WRT_REG_DWORD(®->rsp_q_out, rsp->ring_index); + if (ha->mqenable) + WRT_REG_DWORD(®->isp25mq.rsp_q_out, rsp->ring_index); + else + WRT_REG_DWORD(®->isp24.rsp_q_out, rsp->ring_index); } static void @@ -1607,10 +1627,11 @@ qla24xx_intr_handler(int irq, void *dev_id) mb[1] = RD_REG_WORD(®->mailbox1); mb[2] = RD_REG_WORD(®->mailbox2); mb[3] = RD_REG_WORD(®->mailbox3); - qla2x00_async_event(vha, mb); + qla2x00_async_event(vha, rsp, mb); break; case 0x13: - qla24xx_process_response_queue(vha); + case 0x14: + qla24xx_process_response_queue(rsp); break; default: DEBUG2(printk("scsi(%ld): Unrecognized interrupt type " @@ -1635,7 +1656,6 @@ qla24xx_intr_handler(int irq, void *dev_id) static irqreturn_t qla24xx_msix_rsp_q(int irq, void *dev_id) { - scsi_qla_host_t *vha; struct qla_hw_data *ha; struct rsp_que *rsp; struct device_reg_24xx __iomem *reg; @@ -1651,8 +1671,7 @@ qla24xx_msix_rsp_q(int irq, void *dev_id) spin_lock_irq(&ha->hardware_lock); - vha = qla2x00_get_rsp_host(rsp); - qla24xx_process_response_queue(vha); + qla24xx_process_response_queue(rsp); WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); spin_unlock_irq(&ha->hardware_lock); @@ -1661,6 +1680,41 @@ qla24xx_msix_rsp_q(int irq, void *dev_id) } static irqreturn_t +qla25xx_msix_rsp_q(int irq, void *dev_id) +{ + struct qla_hw_data *ha; + struct rsp_que *rsp; + struct device_reg_24xx __iomem *reg; + uint16_t msix_disabled_hccr = 0; + + rsp = (struct rsp_que *) dev_id; + if (!rsp) { + printk(KERN_INFO + "%s(): NULL response queue pointer\n", __func__); + return IRQ_NONE; + } + ha = rsp->hw; + reg = &ha->iobase->isp24; + + spin_lock_irq(&ha->hardware_lock); + + msix_disabled_hccr = rsp->options; + if (!rsp->id) + msix_disabled_hccr &= __constant_cpu_to_le32(BIT_22); + else + msix_disabled_hccr &= BIT_6; + + qla24xx_process_response_queue(rsp); + + if (!msix_disabled_hccr) + WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); + + spin_unlock_irq(&ha->hardware_lock); + + return IRQ_HANDLED; +} + +static irqreturn_t qla24xx_msix_default(int irq, void *dev_id) { scsi_qla_host_t *vha; @@ -1723,10 +1777,11 @@ qla24xx_msix_default(int irq, void *dev_id) mb[1] = RD_REG_WORD(®->mailbox1); mb[2] = RD_REG_WORD(®->mailbox2); mb[3] = RD_REG_WORD(®->mailbox3); - qla2x00_async_event(vha, mb); + qla2x00_async_event(vha, rsp, mb); break; case 0x13: - qla24xx_process_response_queue(vha); + case 0x14: + qla24xx_process_response_queue(rsp); break; default: DEBUG2(printk("scsi(%ld): Unrecognized interrupt type " @@ -1756,12 +1811,25 @@ struct qla_init_msix_entry { irq_handler_t handler; }; -static struct qla_init_msix_entry imsix_entries[QLA_MSIX_ENTRIES] = { - { QLA_MSIX_DEFAULT, QLA_MIDX_DEFAULT, - "qla2xxx (default)", qla24xx_msix_default }, +static struct qla_init_msix_entry base_queue = { + .entry = 0, + .index = 0, + .name = "qla2xxx (default)", + .handler = qla24xx_msix_default, +}; + +static struct qla_init_msix_entry base_rsp_queue = { + .entry = 1, + .index = 1, + .name = "qla2xxx (rsp_q)", + .handler = qla24xx_msix_rsp_q, +}; - { QLA_MSIX_RSP_Q, QLA_MIDX_RSP_Q, - "qla2xxx (rsp_q)", qla24xx_msix_rsp_q }, +static struct qla_init_msix_entry multi_rsp_queue = { + .entry = 1, + .index = 1, + .name = "qla2xxx (multi_q)", + .handler = qla25xx_msix_rsp_q, }; static void @@ -1769,63 +1837,115 @@ qla24xx_disable_msix(struct qla_hw_data *ha) { int i; struct qla_msix_entry *qentry; - struct rsp_que *rsp = ha->rsp; - for (i = 0; i < QLA_MSIX_ENTRIES; i++) { - qentry = &ha->msix_entries[imsix_entries[i].index]; + for (i = 0; i < ha->msix_count; i++) { + qentry = &ha->msix_entries[i]; if (qentry->have_irq) - free_irq(qentry->msix_vector, rsp); + free_irq(qentry->vector, qentry->rsp); } pci_disable_msix(ha->pdev); + kfree(ha->msix_entries); + ha->msix_entries = NULL; + ha->flags.msix_enabled = 0; } static int -qla24xx_enable_msix(struct qla_hw_data *ha) +qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) { int i, ret; - struct rsp_que *rsp = ha->rsp; - struct msix_entry entries[QLA_MSIX_ENTRIES]; + struct msix_entry *entries; struct qla_msix_entry *qentry; + struct qla_init_msix_entry *msix_queue; + + entries = kzalloc(sizeof(struct msix_entry) * ha->msix_count, + GFP_KERNEL); + if (!entries) + return -ENOMEM; - for (i = 0; i < QLA_MSIX_ENTRIES; i++) - entries[i].entry = imsix_entries[i].entry; + for (i = 0; i < ha->msix_count; i++) + entries[i].entry = i; - ret = pci_enable_msix(ha->pdev, entries, ARRAY_SIZE(entries)); + ret = pci_enable_msix(ha->pdev, entries, ha->msix_count); if (ret) { qla_printk(KERN_WARNING, ha, - "MSI-X: Failed to enable support -- %d/%d\n", - QLA_MSIX_ENTRIES, ret); + "MSI-X: Failed to enable support -- %d/%d\n" + " Retry with %d vectors\n", ha->msix_count, ret, ret); + ha->msix_count = ret; + ret = pci_enable_msix(ha->pdev, entries, ha->msix_count); + if (ret) { + qla_printk(KERN_WARNING, ha, "MSI-X: Failed to enable" + " support, giving up -- %d/%d\n", + ha->msix_count, ret); + goto msix_out; + } + ha->max_queues = ha->msix_count - 1; + } + ha->msix_entries = kzalloc(sizeof(struct qla_msix_entry) * + ha->msix_count, GFP_KERNEL); + if (!ha->msix_entries) { + ret = -ENOMEM; goto msix_out; } ha->flags.msix_enabled = 1; - for (i = 0; i < QLA_MSIX_ENTRIES; i++) { - qentry = &ha->msix_entries[imsix_entries[i].index]; - qentry->msix_vector = entries[i].vector; - qentry->msix_entry = entries[i].entry; + for (i = 0; i < ha->msix_count; i++) { + qentry = &ha->msix_entries[i]; + qentry->vector = entries[i].vector; + qentry->entry = entries[i].entry; qentry->have_irq = 0; - ret = request_irq(qentry->msix_vector, - imsix_entries[i].handler, 0, imsix_entries[i].name, rsp); - if (ret) { - qla_printk(KERN_WARNING, ha, - "MSI-X: Unable to register handler -- %x/%d.\n", - imsix_entries[i].index, ret); - qla24xx_disable_msix(ha); - goto msix_out; - } - qentry->have_irq = 1; + qentry->rsp = NULL; } + /* Enable MSI-X for AENs for queue 0 */ + qentry = &ha->msix_entries[0]; + ret = request_irq(qentry->vector, base_queue.handler, 0, + base_queue.name, rsp); + if (ret) { + qla_printk(KERN_WARNING, ha, + "MSI-X: Unable to register handler -- %x/%d.\n", + qentry->vector, ret); + qla24xx_disable_msix(ha); + goto msix_out; + } + qentry->have_irq = 1; + qentry->rsp = rsp; + + /* Enable MSI-X vector for response queue update for queue 0 */ + if (ha->max_queues > 1 && ha->mqiobase) { + ha->mqenable = 1; + msix_queue = &multi_rsp_queue; + qla_printk(KERN_INFO, ha, + "MQ enabled, Number of Queue Resources: %d \n", + ha->max_queues); + } else { + ha->mqenable = 0; + msix_queue = &base_rsp_queue; + } + + qentry = &ha->msix_entries[1]; + ret = request_irq(qentry->vector, msix_queue->handler, 0, + msix_queue->name, rsp); + if (ret) { + qla_printk(KERN_WARNING, ha, + "MSI-X: Unable to register handler -- %x/%d.\n", + qentry->vector, ret); + qla24xx_disable_msix(ha); + ha->mqenable = 0; + goto msix_out; + } + qentry->have_irq = 1; + qentry->rsp = rsp; + msix_out: + kfree(entries); return ret; } int -qla2x00_request_irqs(struct qla_hw_data *ha) +qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp) { int ret; device_reg_t __iomem *reg = ha->iobase; - struct rsp_que *rsp = ha->rsp; /* If possible, enable MSI-X. */ if (!IS_QLA2432(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha)) @@ -1852,7 +1972,7 @@ qla2x00_request_irqs(struct qla_hw_data *ha) goto skip_msi; } - ret = qla24xx_enable_msix(ha); + ret = qla24xx_enable_msix(ha, rsp); if (!ret) { DEBUG2(qla_printk(KERN_INFO, ha, "MSI-X: Enabled (0x%X, 0x%X).\n", ha->chip_revision, @@ -1903,7 +2023,7 @@ void qla2x00_free_irqs(scsi_qla_host_t *vha) { struct qla_hw_data *ha = vha->hw; - struct rsp_que *rsp = ha->rsp; + struct rsp_que *rsp = ha->rsp_q_map[0]; if (ha->flags.msix_enabled) qla24xx_disable_msix(ha); @@ -1919,16 +2039,41 @@ qla2x00_get_rsp_host(struct rsp_que *rsp) srb_t *sp; struct qla_hw_data *ha = rsp->hw; struct scsi_qla_host *vha = NULL; - struct sts_entry_24xx *pkt = (struct sts_entry_24xx *) rsp->ring_ptr; - - if (pkt && pkt->handle < MAX_OUTSTANDING_COMMANDS) { - sp = ha->req->outstanding_cmds[pkt->handle]; - if (sp) - vha = sp->vha; + struct sts_entry_24xx *pkt; + struct req_que *req; + + if (rsp->id) { + pkt = (struct sts_entry_24xx *) rsp->ring_ptr; + req = rsp->req; + if (pkt && pkt->handle < MAX_OUTSTANDING_COMMANDS) { + sp = req->outstanding_cmds[pkt->handle]; + if (sp) + vha = sp->vha; + } } if (!vha) - /* Invalid entry, handle it in base queue */ + /* handle it in base queue */ vha = pci_get_drvdata(ha->pdev); return vha; } + +int qla25xx_request_irq(struct rsp_que *rsp) +{ + struct qla_hw_data *ha = rsp->hw; + struct qla_init_msix_entry *intr = &multi_rsp_queue; + struct qla_msix_entry *msix = rsp->msix; + int ret; + + ret = request_irq(msix->vector, intr->handler, 0, intr->name, rsp); + if (ret) { + qla_printk(KERN_WARNING, ha, + "MSI-X: Unable to register handler -- %x/%d.\n", + msix->vector, ret); + return ret; + } + msix->have_irq = 1; + msix->rsp = rsp; + return ret; +} + diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index bbe7181fb3d..c54bc977c7b 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -153,7 +153,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) break; /* Check for pending interrupts. */ - qla2x00_poll(ha->rsp); + qla2x00_poll(ha->rsp_q_map[0]); if (command != MBC_LOAD_RISC_RAM_EXTENDED && !ha->flags.mbox_int) @@ -223,7 +223,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) "interrupt.\n", __func__, base_vha->host_no)); /* polling mode for non isp_abort commands. */ - qla2x00_poll(ha->rsp); + qla2x00_poll(ha->rsp_q_map[0]); } if (rval == QLA_FUNCTION_TIMEOUT && @@ -713,8 +713,6 @@ qla2x00_issue_iocb_timeout(scsi_qla_host_t *vha, void *buffer, /*EMPTY*/ DEBUG(printk("qla2x00_issue_iocb(%ld): failed rval 0x%x\n", vha->host_no, rval)); - DEBUG2(printk("qla2x00_issue_iocb(%ld): failed rval 0x%x\n", - vha->host_no, rval)); } else { sts_entry_t *sts_entry = (sts_entry_t *) buffer; @@ -749,16 +747,15 @@ qla2x00_issue_iocb(scsi_qla_host_t *vha, void *buffer, dma_addr_t phys_addr, * Kernel context. */ int -qla2x00_abort_command(scsi_qla_host_t *vha, srb_t *sp) +qla2x00_abort_command(scsi_qla_host_t *vha, srb_t *sp, struct req_que *req) { unsigned long flags = 0; fc_port_t *fcport; int rval; - uint32_t handle; + uint32_t handle = 0; mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req; DEBUG11(printk("qla2x00_abort_command(%ld): entered.\n", vha->host_no)); @@ -808,11 +805,15 @@ qla2x00_abort_target(struct fc_port *fcport, unsigned int l) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; scsi_qla_host_t *vha; + struct req_que *req; + struct rsp_que *rsp; DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->vha->host_no)); l = l; vha = fcport->vha; + req = vha->hw->req_q_map[0]; + rsp = vha->hw->rsp_q_map[0]; mcp->mb[0] = MBC_ABORT_TARGET; mcp->out_mb = MBX_9|MBX_2|MBX_1|MBX_0; if (HAS_EXTENDED_IDS(vha->hw)) { @@ -835,7 +836,8 @@ qla2x00_abort_target(struct fc_port *fcport, unsigned int l) } /* Issue marker IOCB. */ - rval2 = qla2x00_marker(vha, fcport->loop_id, 0, MK_SYNC_ID); + rval2 = qla2x00_marker(vha, req, rsp, fcport->loop_id, 0, + MK_SYNC_ID); if (rval2 != QLA_SUCCESS) { DEBUG2_3_11(printk("%s(%ld): failed to issue Marker IOCB " "(%x).\n", __func__, vha->host_no, rval2)); @@ -853,10 +855,14 @@ qla2x00_lun_reset(struct fc_port *fcport, unsigned int l) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; scsi_qla_host_t *vha; + struct req_que *req; + struct rsp_que *rsp; DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->vha->host_no)); vha = fcport->vha; + req = vha->hw->req_q_map[0]; + rsp = vha->hw->rsp_q_map[0]; mcp->mb[0] = MBC_LUN_RESET; mcp->out_mb = MBX_9|MBX_3|MBX_2|MBX_1|MBX_0; if (HAS_EXTENDED_IDS(vha->hw)) @@ -877,7 +883,8 @@ qla2x00_lun_reset(struct fc_port *fcport, unsigned int l) } /* Issue marker IOCB. */ - rval2 = qla2x00_marker(vha, fcport->loop_id, l, MK_SYNC_ID_LUN); + rval2 = qla2x00_marker(vha, req, rsp, fcport->loop_id, l, + MK_SYNC_ID_LUN); if (rval2 != QLA_SUCCESS) { DEBUG2_3_11(printk("%s(%ld): failed to issue Marker IOCB " "(%x).\n", __func__, vha->host_no, rval2)); @@ -1743,6 +1750,7 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, lg->port_id[1] = area; lg->port_id[2] = domain; lg->vp_index = vha->vp_idx; + rval = qla2x00_issue_iocb(vha, lg, lg_dma, 0); if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("%s(%ld): failed to issue Logout IOCB " @@ -1753,9 +1761,9 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, lg->entry_status)); rval = QLA_FUNCTION_FAILED; } else if (lg->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) { - DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB " + DEBUG2_3_11(printk("%s(%ld %d): failed to complete IOCB " "-- completion status (%x) ioparam=%x/%x.\n", __func__, - vha->host_no, le16_to_cpu(lg->comp_status), + vha->host_no, vha->vp_idx, le16_to_cpu(lg->comp_status), le32_to_cpu(lg->io_parameter[0]), le32_to_cpu(lg->io_parameter[1]))); } else { @@ -2173,7 +2181,7 @@ qla24xx_get_isp_stats(scsi_qla_host_t *vha, struct link_statistics *stats, } int -qla24xx_abort_command(scsi_qla_host_t *vha, srb_t *sp) +qla24xx_abort_command(scsi_qla_host_t *vha, srb_t *sp, struct req_que *req) { int rval; fc_port_t *fcport; @@ -2183,7 +2191,6 @@ qla24xx_abort_command(scsi_qla_host_t *vha, srb_t *sp) dma_addr_t abt_dma; uint32_t handle; struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req; DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); @@ -2216,6 +2223,9 @@ qla24xx_abort_command(scsi_qla_host_t *vha, srb_t *sp) abt->port_id[1] = fcport->d_id.b.area; abt->port_id[2] = fcport->d_id.b.domain; abt->vp_index = fcport->vp_idx; + + abt->req_que_no = cpu_to_le16(req->id); + rval = qla2x00_issue_iocb(vha, abt, abt_dma, 0); if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("%s(%ld): failed to issue IOCB (%x).\n", @@ -2255,11 +2265,15 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport, dma_addr_t tsk_dma; scsi_qla_host_t *vha; struct qla_hw_data *ha; + struct req_que *req; + struct rsp_que *rsp; DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->vha->host_no)); vha = fcport->vha; ha = vha->hw; + req = ha->req_q_map[0]; + rsp = ha->rsp_q_map[0]; tsk = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &tsk_dma); if (tsk == NULL) { DEBUG2_3(printk("%s(%ld): failed to allocate Task Management " @@ -2301,7 +2315,7 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport, } /* Issue marker IOCB. */ - rval2 = qla2x00_marker(vha, fcport->loop_id, l, + rval2 = qla2x00_marker(vha, req, rsp, fcport->loop_id, l, type == TCF_LUN_RESET ? MK_SYNC_ID_LUN: MK_SYNC_ID); if (rval2 != QLA_SUCCESS) { DEBUG2_3_11(printk("%s(%ld): failed to issue Marker IOCB " @@ -3069,3 +3083,108 @@ verify_done: return rval; } + +int +qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req, + uint8_t options) +{ + int rval; + unsigned long flags; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + struct device_reg_25xxmq __iomem *reg; + struct qla_hw_data *ha = vha->hw; + + mcp->mb[0] = MBC_INITIALIZE_MULTIQ; + mcp->mb[1] = options; + mcp->mb[2] = MSW(LSD(req->dma)); + mcp->mb[3] = LSW(LSD(req->dma)); + mcp->mb[6] = MSW(MSD(req->dma)); + mcp->mb[7] = LSW(MSD(req->dma)); + mcp->mb[5] = req->length; + if (req->rsp) + mcp->mb[10] = req->rsp->id; + mcp->mb[12] = req->qos; + mcp->mb[11] = req->vp_idx; + mcp->mb[13] = req->rid; + + reg = (struct device_reg_25xxmq *)((void *)(ha->mqiobase) + + QLA_QUE_PAGE * req->id); + + mcp->mb[4] = req->id; + /* que in ptr index */ + mcp->mb[8] = 0; + /* que out ptr index */ + mcp->mb[9] = 0; + mcp->out_mb = MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8|MBX_7| + MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_0; + mcp->flags = MBX_DMA_OUT; + mcp->tov = 60; + + spin_lock_irqsave(&ha->hardware_lock, flags); + if (!(options & BIT_0)) { + WRT_REG_DWORD(®->req_q_in, 0); + WRT_REG_DWORD(®->req_q_out, 0); + } + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + rval = (int)qla2x00_mailbox_command(vha, mcp); + if (rval != QLA_SUCCESS) + DEBUG2_3_11(printk(KERN_WARNING "%s(%ld): failed=%x mb0=%x.\n", + __func__, vha->host_no, rval, mcp->mb[0])); + return rval; +} + +int +qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp, + uint8_t options) +{ + int rval; + unsigned long flags; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + struct device_reg_25xxmq __iomem *reg; + struct qla_hw_data *ha = vha->hw; + + mcp->mb[0] = MBC_INITIALIZE_MULTIQ; + mcp->mb[1] = options; + mcp->mb[2] = MSW(LSD(rsp->dma)); + mcp->mb[3] = LSW(LSD(rsp->dma)); + mcp->mb[6] = MSW(MSD(rsp->dma)); + mcp->mb[7] = LSW(MSD(rsp->dma)); + mcp->mb[5] = rsp->length; + mcp->mb[11] = rsp->vp_idx; + mcp->mb[14] = rsp->msix->vector; + mcp->mb[13] = rsp->rid; + + reg = (struct device_reg_25xxmq *)((void *)(ha->mqiobase) + + QLA_QUE_PAGE * rsp->id); + + mcp->mb[4] = rsp->id; + /* que in ptr index */ + mcp->mb[8] = 0; + /* que out ptr index */ + mcp->mb[9] = 0; + mcp->out_mb = MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8|MBX_7 + |MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_0; + mcp->flags = MBX_DMA_OUT; + mcp->tov = 60; + + spin_lock_irqsave(&ha->hardware_lock, flags); + if (!(options & BIT_0)) { + WRT_REG_DWORD(®->rsp_q_out, 0); + WRT_REG_DWORD(®->rsp_q_in, 0); + } + + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + rval = (int)qla2x00_mailbox_command(vha, mcp); + if (rval != QLA_SUCCESS) + DEBUG2_3_11(printk(KERN_WARNING "%s(%ld): failed=%x " + "mb0=%x.\n", __func__, + vha->host_no, rval, mcp->mb[0])); + return rval; +} + diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index da3db3abb82..386ffeae5b5 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -101,6 +101,7 @@ qla2x00_mark_vp_devices_dead(scsi_qla_host_t *vha) "loop_id=0x%04x :%x\n", vha->host_no, fcport->loop_id, fcport->vp_idx)); + atomic_set(&fcport->state, FCS_DEVICE_DEAD); qla2x00_mark_device_lost(vha, fcport, 0, 0); atomic_set(&fcport->state, FCS_UNCONFIGURED); } @@ -191,9 +192,10 @@ qla24xx_configure_vp(scsi_qla_host_t *vha) } void -qla2x00_alert_all_vps(struct qla_hw_data *ha, uint16_t *mb) +qla2x00_alert_all_vps(struct rsp_que *rsp, uint16_t *mb) { scsi_qla_host_t *vha; + struct qla_hw_data *ha = rsp->hw; int i = 0; list_for_each_entry(vha, &ha->vp_list, list) { @@ -210,7 +212,7 @@ qla2x00_alert_all_vps(struct qla_hw_data *ha, uint16_t *mb) DEBUG15(printk("scsi(%ld)%s: Async_event for" " VP[%d], mb = 0x%x, vha=%p\n", vha->host_no, __func__, i, *mb, vha)); - qla2x00_async_event(vha, mb); + qla2x00_async_event(vha, rsp, mb); break; } } @@ -282,8 +284,7 @@ qla2x00_do_dpc_vp(scsi_qla_host_t *vha) clear_bit(RESET_ACTIVE, &vha->dpc_flags); } - if (atomic_read(&vha->vp_state) == VP_ACTIVE && - test_and_clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) { + if (test_and_clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) { if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags))) { qla2x00_loop_resync(vha); clear_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags); @@ -367,7 +368,6 @@ qla24xx_create_vhost(struct fc_vport *fc_vport) host = vha->host; fc_vport->dd_data = vha; - /* New host info */ u64_to_wwn(fc_vport->node_name, vha->node_name); u64_to_wwn(fc_vport->port_name, vha->port_name); @@ -396,7 +396,9 @@ qla24xx_create_vhost(struct fc_vport *fc_vport) qla2x00_start_timer(vha, qla2x00_timer, WATCH_INTERVAL); - host->can_queue = ha->req->length + 128; + memset(vha->req_ques, 0, sizeof(vha->req_ques) * QLA_MAX_HOST_QUES); + vha->req_ques[0] = ha->req_q_map[0]->id; + host->can_queue = ha->req_q_map[0]->length + 128; host->this_id = 255; host->cmd_per_lun = 3; host->max_cmd_len = MAX_CMDSZ; @@ -416,3 +418,338 @@ qla24xx_create_vhost(struct fc_vport *fc_vport) create_vhost_failed: return NULL; } + +static void +qla25xx_free_req_que(struct scsi_qla_host *vha, struct req_que *req) +{ + struct qla_hw_data *ha = vha->hw; + uint16_t que_id = req->id; + + dma_free_coherent(&ha->pdev->dev, (req->length + 1) * + sizeof(request_t), req->ring, req->dma); + req->ring = NULL; + req->dma = 0; + if (que_id) { + ha->req_q_map[que_id] = NULL; + mutex_lock(&ha->vport_lock); + clear_bit(que_id, ha->req_qid_map); + mutex_unlock(&ha->vport_lock); + } + kfree(req); + req = NULL; +} + +static void +qla25xx_free_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp) +{ + struct qla_hw_data *ha = vha->hw; + uint16_t que_id = rsp->id; + + if (rsp->msix && rsp->msix->have_irq) { + free_irq(rsp->msix->vector, rsp); + rsp->msix->have_irq = 0; + rsp->msix->rsp = NULL; + } + dma_free_coherent(&ha->pdev->dev, (rsp->length + 1) * + sizeof(response_t), rsp->ring, rsp->dma); + rsp->ring = NULL; + rsp->dma = 0; + if (que_id) { + ha->rsp_q_map[que_id] = NULL; + mutex_lock(&ha->vport_lock); + clear_bit(que_id, ha->rsp_qid_map); + mutex_unlock(&ha->vport_lock); + } + kfree(rsp); + rsp = NULL; +} + +int +qla25xx_delete_req_que(struct scsi_qla_host *vha, struct req_que *req) +{ + int ret = -1; + + if (req) { + req->options |= BIT_0; + ret = qla25xx_init_req_que(vha, req, req->options); + } + if (ret == QLA_SUCCESS) + qla25xx_free_req_que(vha, req); + + return ret; +} + +int +qla25xx_delete_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp) +{ + int ret = -1; + + if (rsp) { + rsp->options |= BIT_0; + ret = qla25xx_init_rsp_que(vha, rsp, rsp->options); + } + if (ret == QLA_SUCCESS) + qla25xx_free_rsp_que(vha, rsp); + + return ret; +} + +int qla25xx_update_req_que(struct scsi_qla_host *vha, uint8_t que, uint8_t qos) +{ + int ret = 0; + struct qla_hw_data *ha = vha->hw; + struct req_que *req = ha->req_q_map[que]; + + req->options |= BIT_3; + req->qos = qos; + ret = qla25xx_init_req_que(vha, req, req->options); + if (ret != QLA_SUCCESS) + DEBUG2_17(printk(KERN_WARNING "%s failed\n", __func__)); + /* restore options bit */ + req->options &= ~BIT_3; + return ret; +} + + +/* Delete all queues for a given vhost */ +int +qla25xx_delete_queues(struct scsi_qla_host *vha, uint8_t que_no) +{ + int cnt, ret = 0; + struct req_que *req = NULL; + struct rsp_que *rsp = NULL; + struct qla_hw_data *ha = vha->hw; + + if (que_no) { + /* Delete request queue */ + req = ha->req_q_map[que_no]; + if (req) { + rsp = req->rsp; + ret = qla25xx_delete_req_que(vha, req); + if (ret != QLA_SUCCESS) { + qla_printk(KERN_WARNING, ha, + "Couldn't delete req que %d\n", req->id); + return ret; + } + /* Delete associated response queue */ + if (rsp) { + ret = qla25xx_delete_rsp_que(vha, rsp); + if (ret != QLA_SUCCESS) { + qla_printk(KERN_WARNING, ha, + "Couldn't delete rsp que %d\n", + rsp->id); + return ret; + } + } + } + } else { /* delete all queues of this host */ + for (cnt = 0; cnt < QLA_MAX_HOST_QUES; cnt++) { + /* Delete request queues */ + req = ha->req_q_map[vha->req_ques[cnt]]; + if (req && req->id) { + rsp = req->rsp; + ret = qla25xx_delete_req_que(vha, req); + if (ret != QLA_SUCCESS) { + qla_printk(KERN_WARNING, ha, + "Couldn't delete req que %d\n", + vha->req_ques[cnt]); + return ret; + } + vha->req_ques[cnt] = ha->req_q_map[0]->id; + /* Delete associated response queue */ + if (rsp && rsp->id) { + ret = qla25xx_delete_rsp_que(vha, rsp); + if (ret != QLA_SUCCESS) { + qla_printk(KERN_WARNING, ha, + "Couldn't delete rsp que %d\n", + rsp->id); + return ret; + } + } + } + } + } + qla_printk(KERN_INFO, ha, "Queues deleted for vport:%d\n", + vha->vp_idx); + return ret; +} + +int +qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options, + uint8_t vp_idx, uint16_t rid, uint8_t rsp_que, uint8_t qos) +{ + int ret = 0; + struct req_que *req = NULL; + struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); + uint16_t que_id = 0; + + req = kzalloc(sizeof(struct req_que), GFP_KERNEL); + if (req == NULL) { + qla_printk(KERN_WARNING, ha, "could not allocate memory" + "for request que\n"); + goto que_failed; + } + + req->length = REQUEST_ENTRY_CNT_24XX; + req->ring = dma_alloc_coherent(&ha->pdev->dev, + (req->length + 1) * sizeof(request_t), + &req->dma, GFP_KERNEL); + if (req->ring == NULL) { + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - request_ring\n"); + goto que_failed; + } + + mutex_lock(&ha->vport_lock); + que_id = find_first_zero_bit(ha->req_qid_map, ha->max_queues); + if (que_id >= ha->max_queues) { + mutex_unlock(&ha->vport_lock); + qla_printk(KERN_INFO, ha, "No resources to create " + "additional request queue\n"); + goto que_failed; + } + set_bit(que_id, ha->req_qid_map); + ha->req_q_map[que_id] = req; + req->rid = rid; + req->vp_idx = vp_idx; + req->qos = qos; + + if (ha->rsp_q_map[rsp_que]) + req->rsp = ha->rsp_q_map[rsp_que]; + /* Use alternate PCI bus number */ + if (MSB(req->rid)) + options |= BIT_4; + /* Use alternate PCI devfn */ + if (LSB(req->rid)) + options |= BIT_5; + req->options = options; + req->ring_ptr = req->ring; + req->ring_index = 0; + req->cnt = req->length; + req->id = que_id; + mutex_unlock(&ha->vport_lock); + + ret = qla25xx_init_req_que(base_vha, req, options); + if (ret != QLA_SUCCESS) { + qla_printk(KERN_WARNING, ha, "%s failed\n", __func__); + mutex_lock(&ha->vport_lock); + clear_bit(que_id, ha->req_qid_map); + mutex_unlock(&ha->vport_lock); + goto que_failed; + } + + return req->id; + +que_failed: + qla25xx_free_req_que(base_vha, req); + return 0; +} + +/* create response queue */ +int +qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options, + uint8_t vp_idx, uint16_t rid) +{ + int ret = 0; + struct rsp_que *rsp = NULL; + struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); + uint16_t que_id = 0;; + + rsp = kzalloc(sizeof(struct rsp_que), GFP_KERNEL); + if (rsp == NULL) { + qla_printk(KERN_WARNING, ha, "could not allocate memory for" + " response que\n"); + goto que_failed; + } + + rsp->length = RESPONSE_ENTRY_CNT_2300; + rsp->ring = dma_alloc_coherent(&ha->pdev->dev, + (rsp->length + 1) * sizeof(response_t), + &rsp->dma, GFP_KERNEL); + if (rsp->ring == NULL) { + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - response_ring\n"); + goto que_failed; + } + + mutex_lock(&ha->vport_lock); + que_id = find_first_zero_bit(ha->rsp_qid_map, ha->max_queues); + if (que_id >= ha->max_queues) { + mutex_unlock(&ha->vport_lock); + qla_printk(KERN_INFO, ha, "No resources to create " + "additional response queue\n"); + goto que_failed; + } + set_bit(que_id, ha->rsp_qid_map); + + if (ha->flags.msix_enabled) + rsp->msix = &ha->msix_entries[que_id + 1]; + else + qla_printk(KERN_WARNING, ha, "msix not enabled\n"); + + ha->rsp_q_map[que_id] = rsp; + rsp->rid = rid; + rsp->vp_idx = vp_idx; + rsp->hw = ha; + /* Use alternate PCI bus number */ + if (MSB(rsp->rid)) + options |= BIT_4; + /* Use alternate PCI devfn */ + if (LSB(rsp->rid)) + options |= BIT_5; + rsp->options = options; + rsp->ring_ptr = rsp->ring; + rsp->ring_index = 0; + rsp->id = que_id; + mutex_unlock(&ha->vport_lock); + + ret = qla25xx_request_irq(rsp); + if (ret) + goto que_failed; + + ret = qla25xx_init_rsp_que(base_vha, rsp, options); + if (ret != QLA_SUCCESS) { + qla_printk(KERN_WARNING, ha, "%s failed\n", __func__); + mutex_lock(&ha->vport_lock); + clear_bit(que_id, ha->rsp_qid_map); + mutex_unlock(&ha->vport_lock); + goto que_failed; + } + + qla2x00_init_response_q_entries(rsp); + + return rsp->id; + +que_failed: + qla25xx_free_rsp_que(base_vha, rsp); + return 0; +} + +int +qla25xx_create_queues(struct scsi_qla_host *vha, uint8_t qos) +{ + uint16_t options = 0; + uint8_t ret = 0; + struct qla_hw_data *ha = vha->hw; + + options |= BIT_1; + ret = qla25xx_create_rsp_que(ha, options, vha->vp_idx, 0); + if (!ret) { + qla_printk(KERN_WARNING, ha, "Response Que create failed\n"); + return ret; + } else + qla_printk(KERN_INFO, ha, "Response Que:%d created.\n", ret); + + options = 0; + if (qos & BIT_7) + options |= BIT_8; + ret = qla25xx_create_req_que(ha, options, vha->vp_idx, 0, ret, + qos & ~BIT_7); + if (ret) { + vha->req_ques[0] = ret; + qla_printk(KERN_INFO, ha, "Request Que:%d created.\n", ret); + } else + qla_printk(KERN_WARNING, ha, "Request Que create failed\n"); + + return ret; +} diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index f6365884c97..9142025db3d 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -92,7 +92,12 @@ MODULE_PARM_DESC(ql2xiidmaenable, "Enables iIDMA settings " "Default is 1 - perform iIDMA. 0 - no iIDMA."); - +int ql2xmaxqueues = 1; +module_param(ql2xmaxqueues, int, S_IRUGO|S_IRUSR); +MODULE_PARM_DESC(ql2xmaxqueues, + "Enables MQ settings " + "Default is 1 for single queue. Set it to number \ + of queues in MQ mode."); /* * SCSI host template entry points */ @@ -210,11 +215,77 @@ static int qla2x00_do_dpc(void *data); static void qla2x00_rst_aen(scsi_qla_host_t *); -static int qla2x00_mem_alloc(struct qla_hw_data *, uint16_t, uint16_t); +static int qla2x00_mem_alloc(struct qla_hw_data *, uint16_t, uint16_t, + struct req_que **, struct rsp_que **); static void qla2x00_mem_free(struct qla_hw_data *); static void qla2x00_sp_free_dma(srb_t *); /* -------------------------------------------------------------------------- */ +static int qla2x00_alloc_queues(struct qla_hw_data *ha) +{ + ha->req_q_map = kzalloc(sizeof(struct req_que *) * ha->max_queues, + GFP_KERNEL); + if (!ha->req_q_map) { + qla_printk(KERN_WARNING, ha, + "Unable to allocate memory for request queue ptrs\n"); + goto fail_req_map; + } + + ha->rsp_q_map = kzalloc(sizeof(struct rsp_que *) * ha->max_queues, + GFP_KERNEL); + if (!ha->rsp_q_map) { + qla_printk(KERN_WARNING, ha, + "Unable to allocate memory for response queue ptrs\n"); + goto fail_rsp_map; + } + set_bit(0, ha->rsp_qid_map); + set_bit(0, ha->req_qid_map); + return 1; + +fail_rsp_map: + kfree(ha->req_q_map); + ha->req_q_map = NULL; +fail_req_map: + return -ENOMEM; +} + +static void qla2x00_free_que(struct qla_hw_data *ha, struct req_que *req, + struct rsp_que *rsp) +{ + if (rsp && rsp->ring) + dma_free_coherent(&ha->pdev->dev, + (rsp->length + 1) * sizeof(response_t), + rsp->ring, rsp->dma); + + kfree(rsp); + rsp = NULL; + if (req && req->ring) + dma_free_coherent(&ha->pdev->dev, + (req->length + 1) * sizeof(request_t), + req->ring, req->dma); + + kfree(req); + req = NULL; +} + +static void qla2x00_free_queues(struct qla_hw_data *ha) +{ + struct req_que *req; + struct rsp_que *rsp; + int cnt; + + for (cnt = 0; cnt < ha->max_queues; cnt++) { + rsp = ha->rsp_q_map[cnt]; + req = ha->req_q_map[cnt]; + qla2x00_free_que(ha, req, rsp); + } + kfree(ha->rsp_q_map); + ha->rsp_q_map = NULL; + + kfree(ha->req_q_map); + ha->req_q_map = NULL; +} + static char * qla2x00_pci_info_str(struct scsi_qla_host *vha, char *str) { @@ -629,34 +700,40 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *vha) void qla2x00_abort_fcport_cmds(fc_port_t *fcport) { - int cnt; + int cnt, que, id; unsigned long flags; srb_t *sp; scsi_qla_host_t *vha = fcport->vha; struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req; + struct req_que *req; spin_lock_irqsave(&ha->hardware_lock, flags); - for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { - sp = req->outstanding_cmds[cnt]; - if (!sp) - continue; - if (sp->fcport != fcport) + for (que = 0; que < QLA_MAX_HOST_QUES; que++) { + id = vha->req_ques[que]; + req = ha->req_q_map[id]; + if (!req) continue; + for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { + sp = req->outstanding_cmds[cnt]; + if (!sp) + continue; + if (sp->fcport != fcport) + continue; - spin_unlock_irqrestore(&ha->hardware_lock, flags); - if (ha->isp_ops->abort_command(vha, sp)) { - DEBUG2(qla_printk(KERN_WARNING, ha, - "Abort failed -- %lx\n", sp->cmd->serial_number)); - } else { - if (qla2x00_eh_wait_on_command(sp->cmd) != - QLA_SUCCESS) + spin_unlock_irqrestore(&ha->hardware_lock, flags); + if (ha->isp_ops->abort_command(vha, sp, req)) { DEBUG2(qla_printk(KERN_WARNING, ha, - "Abort failed while waiting -- %lx\n", - sp->cmd->serial_number)); - + "Abort failed -- %lx\n", + sp->cmd->serial_number)); + } else { + if (qla2x00_eh_wait_on_command(sp->cmd) != + QLA_SUCCESS) + DEBUG2(qla_printk(KERN_WARNING, ha, + "Abort failed while waiting -- %lx\n", + sp->cmd->serial_number)); + } + spin_lock_irqsave(&ha->hardware_lock, flags); } - spin_lock_irqsave(&ha->hardware_lock, flags); } spin_unlock_irqrestore(&ha->hardware_lock, flags); } @@ -698,13 +775,13 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) { scsi_qla_host_t *vha = shost_priv(cmd->device->host); srb_t *sp; - int ret, i; + int ret, i, que; unsigned int id, lun; unsigned long serial; unsigned long flags; int wait = 0; struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req; + struct req_que *req; qla2x00_block_error_handler(cmd); @@ -719,31 +796,34 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) /* Check active list for command command. */ spin_lock_irqsave(&ha->hardware_lock, flags); - for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) { - sp = req->outstanding_cmds[i]; - - if (sp == NULL) + for (que = 0; que < QLA_MAX_HOST_QUES; que++) { + req = ha->req_q_map[vha->req_ques[que]]; + if (!req) continue; + for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) { + sp = req->outstanding_cmds[i]; - if (sp->cmd != cmd) - continue; + if (sp == NULL) + continue; - DEBUG2(printk("%s(%ld): aborting sp %p from RISC. pid=%ld.\n", - __func__, vha->host_no, sp, serial)); + if (sp->cmd != cmd) + continue; - spin_unlock_irqrestore(&ha->hardware_lock, flags); - if (ha->isp_ops->abort_command(vha, sp)) { - DEBUG2(printk("%s(%ld): abort_command " - "mbx failed.\n", __func__, vha->host_no)); - ret = FAILED; - } else { - DEBUG3(printk("%s(%ld): abort_command " - "mbx success.\n", __func__, vha->host_no)); - wait = 1; - } - spin_lock_irqsave(&ha->hardware_lock, flags); + DEBUG2(printk("%s(%ld): aborting sp %p from RISC." + " pid=%ld.\n", __func__, vha->host_no, sp, serial)); - break; + spin_unlock_irqrestore(&ha->hardware_lock, flags); + if (ha->isp_ops->abort_command(vha, sp, req)) { + DEBUG2(printk("%s(%ld): abort_command " + "mbx failed.\n", __func__, vha->host_no)); + } else { + DEBUG3(printk("%s(%ld): abort_command " + "mbx success.\n", __func__, vha->host_no)); + wait = 1; + } + spin_lock_irqsave(&ha->hardware_lock, flags); + break; + } } spin_unlock_irqrestore(&ha->hardware_lock, flags); @@ -774,41 +854,46 @@ static int qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *vha, unsigned int t, unsigned int l, enum nexus_wait_type type) { - int cnt, match, status; + int cnt, match, status, que; srb_t *sp; unsigned long flags; struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req; + struct req_que *req; status = QLA_SUCCESS; spin_lock_irqsave(&ha->hardware_lock, flags); - for (cnt = 1; status == QLA_SUCCESS && cnt < MAX_OUTSTANDING_COMMANDS; - cnt++) { - sp = req->outstanding_cmds[cnt]; - if (!sp) + for (que = 0; que < QLA_MAX_HOST_QUES; que++) { + req = ha->req_q_map[vha->req_ques[que]]; + if (!req) continue; + for (cnt = 1; status == QLA_SUCCESS && + cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { + sp = req->outstanding_cmds[cnt]; + if (!sp) + continue; - if (vha->vp_idx != sp->fcport->vha->vp_idx) - continue; - match = 0; - switch (type) { - case WAIT_HOST: - match = 1; - break; - case WAIT_TARGET: - match = sp->cmd->device->id == t; - break; - case WAIT_LUN: - match = (sp->cmd->device->id == t && - sp->cmd->device->lun == l); - break; - } - if (!match) - continue; + if (vha->vp_idx != sp->fcport->vha->vp_idx) + continue; + match = 0; + switch (type) { + case WAIT_HOST: + match = 1; + break; + case WAIT_TARGET: + match = sp->cmd->device->id == t; + break; + case WAIT_LUN: + match = (sp->cmd->device->id == t && + sp->cmd->device->lun == l); + break; + } + if (!match) + continue; - spin_unlock_irqrestore(&ha->hardware_lock, flags); - status = qla2x00_eh_wait_on_command(sp->cmd); - spin_lock_irqsave(&ha->hardware_lock, flags); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + status = qla2x00_eh_wait_on_command(sp->cmd); + spin_lock_irqsave(&ha->hardware_lock, flags); + } } spin_unlock_irqrestore(&ha->hardware_lock, flags); @@ -1074,7 +1159,6 @@ qla2x00_loop_reset(scsi_qla_host_t *vha) } } } - /* Issue marker command only when we are going to start the I/O */ vha->marker_needed = 1; @@ -1084,19 +1168,24 @@ qla2x00_loop_reset(scsi_qla_host_t *vha) void qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res) { - int cnt; + int que, cnt; unsigned long flags; srb_t *sp; struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req; + struct req_que *req; spin_lock_irqsave(&ha->hardware_lock, flags); - for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { - sp = req->outstanding_cmds[cnt]; - if (sp) { - req->outstanding_cmds[cnt] = NULL; - sp->cmd->result = res; - qla2x00_sp_compl(vha, sp); + for (que = 0; que < QLA_MAX_HOST_QUES; que++) { + req = ha->req_q_map[vha->req_ques[que]]; + if (!req) + continue; + for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { + sp = req->outstanding_cmds[cnt]; + if (sp && sp->vha == vha) { + req->outstanding_cmds[cnt] = NULL; + sp->cmd->result = res; + qla2x00_sp_compl(ha, sp); + } } } spin_unlock_irqrestore(&ha->hardware_lock, flags); @@ -1121,11 +1210,12 @@ qla2xxx_slave_configure(struct scsi_device *sdev) scsi_qla_host_t *vha = shost_priv(sdev->host); struct qla_hw_data *ha = vha->hw; struct fc_rport *rport = starget_to_rport(sdev->sdev_target); + struct req_que *req = ha->req_q_map[0]; if (sdev->tagged_supported) - scsi_activate_tcq(sdev, ha->req->max_q_depth); + scsi_activate_tcq(sdev, req->max_q_depth); else - scsi_deactivate_tcq(sdev, ha->req->max_q_depth); + scsi_deactivate_tcq(sdev, req->max_q_depth); rport->dev_loss_tmo = ha->port_down_retry_count; @@ -1471,6 +1561,7 @@ static int qla2x00_iospace_config(struct qla_hw_data *ha) { resource_size_t pio; + uint16_t msix; if (pci_request_selected_regions(ha->pdev, ha->bars, QLA2XXX_DRIVER_NAME)) { @@ -1523,6 +1614,29 @@ skip_pio: goto iospace_error_exit; } + /* Determine queue resources */ + ha->max_queues = 1; + if (ql2xmaxqueues > 1) { + ha->mqiobase = ioremap(pci_resource_start(ha->pdev, 3), + pci_resource_len(ha->pdev, 3)); + if (ha->mqiobase) { + /* Read MSIX vector size of the board */ + pci_read_config_word(ha->pdev, QLA_PCI_MSIX_CONTROL, + &msix); + ha->msix_count = msix; + /* Max queues are bounded by available msix vectors */ + /* queue 0 uses two msix vectors */ + if (ha->msix_count - 1 < ql2xmaxqueues) + ha->max_queues = ha->msix_count - 1; + else if (ql2xmaxqueues > QLA_MQ_SIZE) + ha->max_queues = QLA_MQ_SIZE; + else + ha->max_queues = ql2xmaxqueues; + qla_printk(KERN_INFO, ha, + "MSI-X vector count: %d\n", msix); + } + } + ha->msix_count = ha->max_queues + 1; return (0); iospace_error_exit: @@ -1568,6 +1682,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) struct scsi_host_template *sht; int bars, max_id, mem_only = 0; uint16_t req_length = 0, rsp_length = 0; + struct req_que *req = NULL; + struct rsp_que *rsp = NULL; bars = pci_select_bars(pdev, IORESOURCE_MEM | IORESOURCE_IO); sht = &qla2x00_driver_template; @@ -1655,6 +1771,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->init_cb_size = sizeof(struct mid_init_cb_24xx); ha->gid_list_info_size = 8; ha->optrom_size = OPTROM_SIZE_24XX; + ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA24XX; ha->isp_ops = &qla24xx_isp_ops; } else if (IS_QLA25XX(ha)) { ha->mbx_count = MAILBOX_REGISTER_COUNT; @@ -1664,6 +1781,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->init_cb_size = sizeof(struct mid_init_cb_24xx); ha->gid_list_info_size = 8; ha->optrom_size = OPTROM_SIZE_25XX; + ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX; ha->isp_ops = &qla25xx_isp_ops; } @@ -1674,7 +1792,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) set_bit(0, (unsigned long *) ha->vp_idx_map); - ret = qla2x00_mem_alloc(ha, req_length, rsp_length); + ret = qla2x00_mem_alloc(ha, req_length, rsp_length, &req, &rsp); if (!ret) { qla_printk(KERN_WARNING, ha, "[ERROR] Failed to allocate memory for adapter\n"); @@ -1682,9 +1800,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) goto probe_hw_failed; } - ha->req->max_q_depth = MAX_Q_DEPTH; + req->max_q_depth = MAX_Q_DEPTH; if (ql2xmaxqdepth != 0 && ql2xmaxqdepth <= 0xffffU) - ha->req->max_q_depth = ql2xmaxqdepth; + req->max_q_depth = ql2xmaxqdepth; + base_vha = qla2x00_create_host(sht, ha); if (!base_vha) { @@ -1700,13 +1819,13 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) qla2x00_config_dma_addressing(base_vha); host = base_vha->host; - host->can_queue = ha->req->length + 128; - if (IS_QLA2XXX_MIDTYPE(ha)) { + base_vha->req_ques[0] = req->id; + host->can_queue = req->length + 128; + if (IS_QLA2XXX_MIDTYPE(ha)) base_vha->mgmt_svr_loop_id = 10 + base_vha->vp_idx; - } else { + else base_vha->mgmt_svr_loop_id = MANAGEMENT_SERVER + base_vha->vp_idx; - } if (IS_QLA2100(ha)) host->sg_tablesize = 32; host->max_id = max_id; @@ -1718,6 +1837,21 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) host->max_lun = MAX_LUNS; host->transportt = qla2xxx_transport_template; + /* Set up the irqs */ + ret = qla2x00_request_irqs(ha, rsp); + if (ret) + goto probe_failed; + + /* Alloc arrays of request and response ring ptrs */ + if (!qla2x00_alloc_queues(ha)) { + qla_printk(KERN_WARNING, ha, + "[ERROR] Failed to allocate memory for queue" + " pointers\n"); + goto probe_failed; + } + ha->rsp_q_map[0] = rsp; + ha->req_q_map[0] = req; + if (qla2x00_initialize_adapter(base_vha)) { qla_printk(KERN_WARNING, ha, "Failed to initialize adapter\n"); @@ -1730,11 +1864,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) goto probe_failed; } - /* Set up the irqs */ - ret = qla2x00_request_irqs(ha); - if (ret) - goto probe_failed; - /* * Startup the kernel thread for this host adapter */ @@ -1786,6 +1915,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) return 0; probe_failed: + qla2x00_free_que(ha, req, rsp); qla2x00_free_device(base_vha); scsi_host_put(base_vha->host); @@ -1836,6 +1966,9 @@ qla2x00_remove_one(struct pci_dev *pdev) if (ha->iobase) iounmap(ha->iobase); + if (ha->mqiobase) + iounmap(ha->mqiobase); + pci_release_selected_regions(ha->pdev, ha->bars); kfree(ha); ha = NULL; @@ -1884,6 +2017,8 @@ qla2x00_free_device(scsi_qla_host_t *vha) qla2x00_free_irqs(vha); qla2x00_mem_free(ha); + + qla2x00_free_queues(ha); } static inline void @@ -1998,11 +2133,10 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *vha, int defer) * !0 = failure. */ static int -qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len) +qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, + struct req_que **req, struct rsp_que **rsp) { char name[16]; - struct req_que *req = NULL; - struct rsp_que *rsp = NULL; ha->init_cb_size = sizeof(init_cb_t); if (IS_QLA2XXX_MIDTYPE(ha)) @@ -2055,52 +2189,67 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len) } /* Allocate memory for request ring */ - req = kzalloc(sizeof(struct req_que), GFP_KERNEL); - if (!req) { + *req = kzalloc(sizeof(struct req_que), GFP_KERNEL); + if (!*req) { DEBUG(printk("Unable to allocate memory for req\n")); goto fail_req; } - ha->req = req; - req->length = req_len; - req->ring = dma_alloc_coherent(&ha->pdev->dev, - (req->length + 1) * sizeof(request_t), - &req->dma, GFP_KERNEL); - if (!req->ring) { + (*req)->length = req_len; + (*req)->ring = dma_alloc_coherent(&ha->pdev->dev, + ((*req)->length + 1) * sizeof(request_t), + &(*req)->dma, GFP_KERNEL); + if (!(*req)->ring) { DEBUG(printk("Unable to allocate memory for req_ring\n")); goto fail_req_ring; } /* Allocate memory for response ring */ - rsp = kzalloc(sizeof(struct rsp_que), GFP_KERNEL); - if (!rsp) { - DEBUG(printk("Unable to allocate memory for rsp\n")); + *rsp = kzalloc(sizeof(struct rsp_que), GFP_KERNEL); + if (!*rsp) { + qla_printk(KERN_WARNING, ha, + "Unable to allocate memory for rsp\n"); goto fail_rsp; } - ha->rsp = rsp; - rsp->hw = ha; - rsp->length = rsp_len; - - rsp->ring = dma_alloc_coherent(&ha->pdev->dev, - (rsp->length + 1) * sizeof(response_t), - &rsp->dma, GFP_KERNEL); - if (!rsp->ring) { - DEBUG(printk("Unable to allocate memory for rsp_ring\n")); + (*rsp)->hw = ha; + (*rsp)->length = rsp_len; + (*rsp)->ring = dma_alloc_coherent(&ha->pdev->dev, + ((*rsp)->length + 1) * sizeof(response_t), + &(*rsp)->dma, GFP_KERNEL); + if (!(*rsp)->ring) { + qla_printk(KERN_WARNING, ha, + "Unable to allocate memory for rsp_ring\n"); goto fail_rsp_ring; } + (*req)->rsp = *rsp; + (*rsp)->req = *req; + /* Allocate memory for NVRAM data for vports */ + if (ha->nvram_npiv_size) { + ha->npiv_info = kzalloc(sizeof(struct qla_npiv_entry) * + ha->nvram_npiv_size, GFP_KERNEL); + if (!ha->npiv_info) { + qla_printk(KERN_WARNING, ha, + "Unable to allocate memory for npiv info\n"); + goto fail_npiv_info; + } + } else + ha->npiv_info = NULL; INIT_LIST_HEAD(&ha->vp_list); return 1; +fail_npiv_info: + dma_free_coherent(&ha->pdev->dev, ((*rsp)->length + 1) * + sizeof(response_t), (*rsp)->ring, (*rsp)->dma); + (*rsp)->ring = NULL; + (*rsp)->dma = 0; fail_rsp_ring: - kfree(rsp); - ha->rsp = NULL; + kfree(*rsp); fail_rsp: - dma_free_coherent(&ha->pdev->dev, (req->length + 1) * - sizeof(request_t), req->ring, req->dma); - req->ring = NULL; - req->dma = 0; + dma_free_coherent(&ha->pdev->dev, ((*req)->length + 1) * + sizeof(request_t), (*req)->ring, (*req)->dma); + (*req)->ring = NULL; + (*req)->dma = 0; fail_req_ring: - kfree(req); - ha->req = NULL; + kfree(*req); fail_req: dma_free_coherent(&ha->pdev->dev, sizeof(struct ct_sns_pkt), ha->ct_sns, ha->ct_sns_dma); @@ -2144,9 +2293,6 @@ fail: static void qla2x00_mem_free(struct qla_hw_data *ha) { - struct req_que *req = ha->req; - struct rsp_que *rsp = ha->rsp; - if (ha->srb_mempool) mempool_destroy(ha->srb_mempool); @@ -2189,6 +2335,7 @@ qla2x00_mem_free(struct qla_hw_data *ha) ha->init_cb, ha->init_cb_dma); vfree(ha->optrom_buffer); kfree(ha->nvram); + kfree(ha->npiv_info); ha->srb_mempool = NULL; ha->eft = NULL; @@ -2210,26 +2357,6 @@ qla2x00_mem_free(struct qla_hw_data *ha) ha->fw_dump = NULL; ha->fw_dumped = 0; ha->fw_dump_reading = 0; - - if (rsp) { - if (rsp->ring) - dma_free_coherent(&ha->pdev->dev, - (rsp->length + 1) * sizeof(response_t), - rsp->ring, rsp->dma); - - kfree(rsp); - rsp = NULL; - } - - if (req) { - if (req->ring) - dma_free_coherent(&ha->pdev->dev, - (req->length + 1) * sizeof(request_t), - req->ring, req->dma); - - kfree(req); - req = NULL; - } } struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht, @@ -2613,9 +2740,8 @@ qla2x00_sp_free_dma(srb_t *sp) } void -qla2x00_sp_compl(scsi_qla_host_t *vha, srb_t *sp) +qla2x00_sp_compl(struct qla_hw_data *ha, srb_t *sp) { - struct qla_hw_data *ha = vha->hw; struct scsi_cmnd *cmd = sp->cmd; qla2x00_sp_free_dma(sp); @@ -2643,7 +2769,7 @@ qla2x00_timer(scsi_qla_host_t *vha) srb_t *sp; int t; struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req; + struct req_que *req; /* * Ports - Port down timer. * @@ -2693,6 +2819,7 @@ qla2x00_timer(scsi_qla_host_t *vha) if (!vha->vp_idx) { spin_lock_irqsave(&ha->hardware_lock, cpu_flags); + req = ha->req_q_map[0]; for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) { diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 6d6c02129a5..c538ee1b1a3 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -547,7 +547,7 @@ qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start) uint16_t cnt, chksum, *wptr; struct qla_flt_location *fltl; struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req; + struct req_que *req = ha->req_q_map[0]; /* * FLT-location structure resides after the last PCI region. @@ -624,7 +624,7 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr) struct qla_flt_header *flt; struct qla_flt_region *region; struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req; + struct req_que *req = ha->req_q_map[0]; ha->flt_region_flt = flt_addr; wptr = (uint16_t *)req->ring; @@ -730,7 +730,7 @@ qla2xxx_get_fdt_info(scsi_qla_host_t *vha) uint8_t man_id, flash_id; uint16_t mid, fid; struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req; + struct req_que *req = ha->req_q_map[0]; wptr = (uint16_t *)req->ring; fdt = (struct qla_fdt_layout *)req->ring; @@ -833,6 +833,7 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha) void *data; uint16_t *wptr; uint16_t cnt, chksum; + int i; struct qla_npiv_header hdr; struct qla_npiv_entry *entry; struct qla_hw_data *ha = vha->hw; @@ -876,7 +877,7 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha) entry = data + sizeof(struct qla_npiv_header); cnt = le16_to_cpu(hdr.entries); - for ( ; cnt; cnt--, entry++) { + for (i = 0; cnt; cnt--, entry++, i++) { uint16_t flags; struct fc_vport_identifiers vid; struct fc_vport *vport; @@ -894,19 +895,25 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha) vid.port_name = wwn_to_u64(entry->port_name); vid.node_name = wwn_to_u64(entry->node_name); + memcpy(&ha->npiv_info[i], entry, sizeof(struct qla_npiv_entry)); + DEBUG2(qla_printk(KERN_DEBUG, ha, "NPIV[%02x]: wwpn=%llx " - "wwnn=%llx vf_id=0x%x qos=0x%x.\n", cnt, vid.port_name, - vid.node_name, le16_to_cpu(entry->vf_id), - le16_to_cpu(entry->qos))); - - vport = fc_vport_create(vha->host, 0, &vid); - if (!vport) - qla_printk(KERN_INFO, ha, "NPIV-Config: Failed to " - "create vport [%02x]: wwpn=%llx wwnn=%llx.\n", cnt, - vid.port_name, vid.node_name); + "wwnn=%llx vf_id=0x%x Q_qos=0x%x F_qos=0x%x.\n", cnt, + vid.port_name, vid.node_name, le16_to_cpu(entry->vf_id), + entry->q_qos, entry->f_qos)); + + if (i < QLA_PRECONFIG_VPORTS) { + vport = fc_vport_create(vha->host, 0, &vid); + if (!vport) + qla_printk(KERN_INFO, ha, + "NPIV-Config: Failed to create vport [%02x]: " + "wwpn=%llx wwnn=%llx.\n", cnt, + vid.port_name, vid.node_name); + } } done: kfree(data); + ha->npiv_info = NULL; } static void diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 54b1100810b..be22f3a09f8 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,9 +7,9 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.02.02-k1" +#define QLA2XXX_VERSION "8.02.03-k1" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 2 -#define QLA_DRIVER_PATCH_VER 2 +#define QLA_DRIVER_PATCH_VER 3 #define QLA_DRIVER_BETA_VER 0 |