diff options
author | Anirban Chakraborty <anirban.chakraborty@qlogic.com> | 2008-12-09 16:45:39 -0800 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-12-29 11:24:33 -0600 |
commit | 73208dfd7ab19f379d73e8a0fbf30f92c203e5e8 (patch) | |
tree | f69be5e89817d17b066ece4dbe04e395339c0754 /drivers/scsi | |
parent | 85b4aa4926a50210b683ac89326e338e7d131211 (diff) |
[SCSI] qla2xxx: add support for multi-queue adapter
Following changes have been made.
1. qla_hw_data structure holds an array for request queue pointers,
and an array for response queue pointers.
2. The base request and response queues are created by default.
3. Additional request and response queues are created at the time of vport
creation. If queue resources are exhausted during vport creation, newly
created vports use the default queue.
4. Requests are sent to the request queue that the vport was assigned
in the beginning.
5. Responses are completed on the response queue with which the request queue
is associated with.
[fixup memcpy argument reversal spotted by davej@redhat.com]
Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi')
-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 |