MODULE_PARM_DESC(ql2xmaxqdepth,
"Maximum queue depth to report for target devices.");
+int ql2xqfulltracking = 1;
+module_param(ql2xqfulltracking, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ql2xqfulltracking,
+ "Controls whether the driver tracks queue full status "
+ "returns and dynamically adjusts a scsi device's queue "
+ "depth. Default is 1, perform tracking. Set to 0 to "
+ "disable dynamic tracking and adjustment of queue depth.");
+
int ql2xqfullrampup = 120;
module_param(ql2xqfullrampup, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(ql2xqfullrampup,
"Enables MQ settings "
"Default is 1 for single queue. Set it to number \
of queues in MQ mode.");
+
+int ql2xmultique_tag;
+module_param(ql2xmultique_tag, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xmultique_tag,
+ "Enables CPU affinity settings for the driver "
+ "Default is 0 for no affinity of request and response IO. "
+ "Set it to 1 to turn on the cpu affinity.");
+
+int ql2xfwloadbin;
+module_param(ql2xfwloadbin, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xfwloadbin,
+ "Option to specify location from which to load ISP firmware:\n"
+ " 2 -- load firmware via the request_firmware() (hotplug)\n"
+ " interface.\n"
+ " 1 -- load firmware from flash.\n"
+ " 0 -- use default semantics.\n");
+
/*
* SCSI host template entry points
*/
/* -------------------------------------------------------------------------- */
static int qla2x00_alloc_queues(struct qla_hw_data *ha)
{
- ha->req_q_map = kzalloc(sizeof(struct req_que *) * ha->max_queues,
+ ha->req_q_map = kzalloc(sizeof(struct req_que *) * ha->max_req_queues,
GFP_KERNEL);
if (!ha->req_q_map) {
qla_printk(KERN_WARNING, ha,
goto fail_req_map;
}
- ha->rsp_q_map = kzalloc(sizeof(struct rsp_que *) * ha->max_queues,
+ ha->rsp_q_map = kzalloc(sizeof(struct rsp_que *) * ha->max_rsp_queues,
GFP_KERNEL);
if (!ha->rsp_q_map) {
qla_printk(KERN_WARNING, ha,
return -ENOMEM;
}
-static void qla2x00_free_que(struct qla_hw_data *ha, struct req_que *req,
- struct rsp_que *rsp)
+static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req)
{
- 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 = NULL;
}
+static void qla2x00_free_rsp_que(struct qla_hw_data *ha, 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;
+}
+
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];
+ for (cnt = 0; cnt < ha->max_req_queues; cnt++) {
req = ha->req_q_map[cnt];
- qla2x00_free_que(ha, req, rsp);
+ qla2x00_free_req_que(ha, req);
+ }
+ kfree(ha->req_q_map);
+ ha->req_q_map = NULL;
+
+ for (cnt = 0; cnt < ha->max_rsp_queues; cnt++) {
+ rsp = ha->rsp_q_map[cnt];
+ qla2x00_free_rsp_que(ha, rsp);
}
kfree(ha->rsp_q_map);
ha->rsp_q_map = NULL;
+}
- kfree(ha->req_q_map);
- ha->req_q_map = NULL;
+static int qla25xx_setup_mode(struct scsi_qla_host *vha)
+{
+ uint16_t options = 0;
+ int ques, req, ret;
+ struct qla_hw_data *ha = vha->hw;
+
+ if (ql2xmultique_tag) {
+ /* CPU affinity mode */
+ ha->wq = create_workqueue("qla2xxx_wq");
+ /* create a request queue for IO */
+ options |= BIT_7;
+ req = qla25xx_create_req_que(ha, options, 0, 0, -1,
+ QLA_DEFAULT_QUE_QOS);
+ if (!req) {
+ qla_printk(KERN_WARNING, ha,
+ "Can't create request queue\n");
+ goto fail;
+ }
+ vha->req = ha->req_q_map[req];
+ options |= BIT_1;
+ for (ques = 1; ques < ha->max_rsp_queues; ques++) {
+ ret = qla25xx_create_rsp_que(ha, options, 0, 0, req);
+ if (!ret) {
+ qla_printk(KERN_WARNING, ha,
+ "Response Queue create failed\n");
+ goto fail2;
+ }
+ }
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "CPU affinity mode enabled, no. of response"
+ " queues:%d, no. of request queues:%d\n",
+ ha->max_rsp_queues, ha->max_req_queues));
+ }
+ return 0;
+fail2:
+ qla25xx_delete_queues(vha);
+fail:
+ ha->mqenable = 0;
+ return 1;
}
static char *
sp->fcport = fcport;
sp->cmd = cmd;
- sp->que = ha->req_q_map[0];
sp->flags = 0;
CMD_SP(cmd) = (void *)sp;
cmd->scsi_done = done;
int rval;
if (unlikely(pci_channel_offline(ha->pdev))) {
- cmd->result = DID_REQUEUE << 16;
+ if (ha->pdev->error_state == pci_channel_io_frozen)
+ cmd->result = DID_REQUEUE << 16;
+ else
+ cmd->result = DID_NO_CONNECT << 16;
goto qc24_fail_command;
}
void
qla2x00_abort_fcport_cmds(fc_port_t *fcport)
{
- int cnt, que, id;
+ int cnt;
unsigned long flags;
srb_t *sp;
scsi_qla_host_t *vha = fcport->vha;
struct req_que *req;
spin_lock_irqsave(&ha->hardware_lock, flags);
- for (que = 0; que < QLA_MAX_HOST_QUES; que++) {
- id = vha->req_ques[que];
- req = ha->req_q_map[id];
- if (!req)
+ req = vha->req;
+ for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
+ sp = req->outstanding_cmds[cnt];
+ if (!sp)
+ continue;
+ if (sp->fcport != fcport)
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, req)) {
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ if (ha->isp_ops->abort_command(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)
DEBUG2(qla_printk(KERN_WARNING, ha,
- "Abort failed -- %lx\n",
+ "Abort failed while waiting -- %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);
}
unsigned long flags;
int wait = 0;
struct qla_hw_data *ha = vha->hw;
- struct req_que *req;
+ struct req_que *req = vha->req;
srb_t *spt;
qla2x00_block_error_handler(cmd);
spt = (srb_t *) CMD_SP(cmd);
if (!spt)
return SUCCESS;
- req = spt->que;
/* Check active list for command command. */
spin_lock_irqsave(&ha->hardware_lock, flags);
" pid=%ld.\n", __func__, vha->host_no, sp, serial));
spin_unlock_irqrestore(&ha->hardware_lock, flags);
- if (ha->isp_ops->abort_command(vha, sp, req)) {
+ if (ha->isp_ops->abort_command(sp)) {
DEBUG2(printk("%s(%ld): abort_command "
"mbx failed.\n", __func__, vha->host_no));
ret = FAILED;
return status;
spin_lock_irqsave(&ha->hardware_lock, flags);
- req = sp->que;
+ req = vha->req;
for (cnt = 1; status == QLA_SUCCESS &&
cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
sp = req->outstanding_cmds[cnt];
static int
__qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type,
- struct scsi_cmnd *cmd, int (*do_reset)(struct fc_port *, unsigned int))
+ struct scsi_cmnd *cmd, int (*do_reset)(struct fc_port *, unsigned int, int))
{
scsi_qla_host_t *vha = shost_priv(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
if (qla2x00_wait_for_loop_ready(vha) != QLA_SUCCESS)
goto eh_reset_failed;
err = 2;
- if (do_reset(fcport, cmd->device->lun) != QLA_SUCCESS)
+ if (do_reset(fcport, cmd->device->lun, cmd->request->cpu + 1)
+ != QLA_SUCCESS)
goto eh_reset_failed;
err = 3;
if (qla2x00_eh_wait_for_pending_commands(vha, cmd->device->id,
if (qla2x00_vp_abort_isp(vha))
goto eh_host_reset_lock;
} else {
+ if (ha->wq)
+ flush_workqueue(ha->wq);
+
set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
if (qla2x00_abort_isp(base_vha)) {
clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
struct fc_port *fcport;
struct qla_hw_data *ha = vha->hw;
- if (ha->flags.enable_lip_full_login && !vha->vp_idx) {
+ if (ha->flags.enable_lip_full_login && !vha->vp_idx &&
+ !IS_QLA81XX(ha)) {
ret = qla2x00_full_login_lip(vha);
if (ret != QLA_SUCCESS) {
DEBUG2_3(printk("%s(%ld): failed: "
if (fcport->port_type != FCT_TARGET)
continue;
- ret = ha->isp_ops->target_reset(fcport, 0);
+ ret = ha->isp_ops->target_reset(fcport, 0, 0);
if (ret != QLA_SUCCESS) {
DEBUG2_3(printk("%s(%ld): bus_reset failed: "
"target_reset=%d d_id=%x.\n", __func__,
struct req_que *req;
spin_lock_irqsave(&ha->hardware_lock, flags);
- for (que = 0; que < ha->max_queues; que++) {
+ for (que = 0; que < ha->max_req_queues; que++) {
req = ha->req_q_map[que];
if (!req)
continue;
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[vha->req_ques[0]];
+ struct req_que *req = vha->req;
if (sdev->tagged_supported)
scsi_activate_tcq(sdev, req->max_q_depth);
/* Assume a 32bit DMA mask. */
ha->flags.enable_64bit_addressing = 0;
- if (!dma_set_mask(&ha->pdev->dev, DMA_64BIT_MASK)) {
+ if (!dma_set_mask(&ha->pdev->dev, DMA_BIT_MASK(64))) {
/* Any upper-dword bits set? */
if (MSD(dma_get_required_mask(&ha->pdev->dev)) &&
- !pci_set_consistent_dma_mask(ha->pdev, DMA_64BIT_MASK)) {
+ !pci_set_consistent_dma_mask(ha->pdev, DMA_BIT_MASK(64))) {
/* Ok, a 64bit DMA mask is applicable. */
ha->flags.enable_64bit_addressing = 1;
ha->isp_ops->calc_req_entries = qla2x00_calc_iocbs_64;
}
}
- dma_set_mask(&ha->pdev->dev, DMA_32BIT_MASK);
- pci_set_consistent_dma_mask(ha->pdev, DMA_32BIT_MASK);
+ dma_set_mask(&ha->pdev->dev, DMA_BIT_MASK(32));
+ pci_set_consistent_dma_mask(ha->pdev, DMA_BIT_MASK(32));
}
static void
.build_iocbs = NULL,
.prep_ms_iocb = qla24xx_prep_ms_iocb,
.prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb,
- .read_nvram = qla25xx_read_nvram_data,
- .write_nvram = qla25xx_write_nvram_data,
+ .read_nvram = NULL,
+ .write_nvram = NULL,
.fw_dump = qla81xx_fw_dump,
.beacon_on = qla24xx_beacon_on,
.beacon_off = qla24xx_beacon_off,
ha->fw_srisc_address = RISC_START_ADDRESS_2400;
break;
}
+
+ /* Get adapter physical port no from interrupt pin register. */
+ pci_read_config_byte(ha->pdev, PCI_INTERRUPT_PIN, &ha->port_no);
+ if (ha->port_no & 1)
+ ha->flags.port0 = 1;
+ else
+ ha->flags.port0 = 0;
}
static int
{
resource_size_t pio;
uint16_t msix;
+ int cpus;
if (pci_request_selected_regions(ha->pdev, ha->bars,
QLA2XXX_DRIVER_NAME)) {
}
/* Determine queue resources */
- ha->max_queues = 1;
- if (ql2xmaxqueues <= 1 || (!IS_QLA25XX(ha) && !IS_QLA81XX(ha)))
+ ha->max_req_queues = ha->max_rsp_queues = 1;
+ if ((ql2xmaxqueues <= 1 || ql2xmultique_tag < 1) &&
+ (!IS_QLA25XX(ha) && !IS_QLA81XX(ha)))
goto mqiobase_exit;
ha->mqiobase = ioremap(pci_resource_start(ha->pdev, 3),
pci_resource_len(ha->pdev, 3));
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;
+ if (ql2xmultique_tag) {
+ cpus = num_online_cpus();
+ ha->max_rsp_queues = (ha->msix_count - 1 - cpus) ?
+ (cpus + 1) : (ha->msix_count - 1);
+ ha->max_req_queues = 2;
+ } else if (ql2xmaxqueues > 1) {
+ ha->max_req_queues = ql2xmaxqueues > QLA_MQ_SIZE ?
+ QLA_MQ_SIZE : ql2xmaxqueues;
+ DEBUG2(qla_printk(KERN_INFO, ha, "QoS mode set, max no"
+ " of request queues:%d\n", ha->max_req_queues));
+ }
qla_printk(KERN_INFO, ha,
"MSI-X vector count: %d\n", msix);
- }
+ } else
+ qla_printk(KERN_INFO, ha, "BAR 3 not enabled\n");
mqiobase_exit:
- ha->msix_count = ha->max_queues + 1;
+ ha->msix_count = ha->max_rsp_queues + 1;
return (0);
iospace_error_exit:
ret = -ENOMEM;
qla2x00_mem_free(ha);
- qla2x00_free_que(ha, req, rsp);
+ qla2x00_free_req_que(ha, req);
+ qla2x00_free_rsp_que(ha, rsp);
goto probe_hw_failed;
}
pci_set_drvdata(pdev, base_vha);
host = base_vha->host;
- base_vha->req_ques[0] = req->id;
+ base_vha->req = req;
host->can_queue = req->length + 128;
if (IS_QLA2XXX_MIDTYPE(ha))
base_vha->mgmt_svr_loop_id = 10 + base_vha->vp_idx;
}
ha->rsp_q_map[0] = rsp;
ha->req_q_map[0] = req;
-
+ rsp->req = req;
+ req->rsp = rsp;
+ set_bit(0, ha->req_qid_map);
+ set_bit(0, ha->rsp_qid_map);
/* FWI2-capable only. */
req->req_q_in = &ha->iobase->isp24.req_q_in;
req->req_q_out = &ha->iobase->isp24.req_q_out;
goto probe_failed;
}
+ if (ha->mqenable)
+ if (qla25xx_setup_mode(base_vha))
+ qla_printk(KERN_WARNING, ha,
+ "Can't create queues, falling back to single"
+ " queue mode\n");
+
/*
* Startup the kernel thread for this host adapter
*/
return 0;
probe_init_failed:
- qla2x00_free_que(ha, req, rsp);
- ha->max_queues = 0;
+ qla2x00_free_req_que(ha, req);
+ qla2x00_free_rsp_que(ha, rsp);
+ ha->max_req_queues = ha->max_rsp_queues = 0;
probe_failed:
if (base_vha->timer_active)
base_vha->flags.online = 0;
+ /* Flush the work queue and remove it */
+ if (ha->wq) {
+ flush_workqueue(ha->wq);
+ destroy_workqueue(ha->wq);
+ ha->wq = NULL;
+ }
+
/* Kill the kernel thread for this host */
if (ha->dpc_thread) {
struct task_struct *t = ha->dpc_thread;
{
struct qla_hw_data *ha = vha->hw;
+ qla25xx_delete_queues(vha);
+
if (ha->flags.fce_enabled)
qla2x00_disable_fce_trace(vha, NULL, NULL);
static pci_ers_result_t
qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
{
+ scsi_qla_host_t *base_vha = pci_get_drvdata(pdev);
+
switch (state) {
case pci_channel_io_normal:
return PCI_ERS_RESULT_CAN_RECOVER;
pci_disable_device(pdev);
return PCI_ERS_RESULT_NEED_RESET;
case pci_channel_io_perm_failure:
- qla2x00_remove_one(pdev);
+ qla2x00_abort_all_cmds(base_vha, DID_NO_CONNECT << 16);
return PCI_ERS_RESULT_DISCONNECT;
}
return PCI_ERS_RESULT_NEED_RESET;