From aa6f5ffbdba45aa8e19e5048648fc6c7b25376d3 Mon Sep 17 00:00:00 2001 From: merge Date: Thu, 22 Jan 2009 13:55:32 +0000 Subject: MERGE-via-pending-tracking-hist-MERGE-via-stable-tracking-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040-1232632141 pending-tracking-hist top was MERGE-via-stable-tracking-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040-1232632141 / fdf777a63bcb59e0dfd78bfe2c6242e01f6d4eb9 ... parent commitmessage: From: merge MERGE-via-stable-tracking-hist-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040 stable-tracking-hist top was MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040 / 90463bfd2d5a3c8b52f6e6d71024a00e052b0ced ... parent commitmessage: From: merge MERGE-via-mokopatches-tracking-hist-fix-stray-endmenu-patch mokopatches-tracking-hist top was fix-stray-endmenu-patch / 3630e0be570de8057e7f8d2fe501ed353cdf34e6 ... parent commitmessage: From: Andy Green fix-stray-endmenu.patch Signed-off-by: Andy Green --- drivers/scsi/qla2xxx/qla_os.c | 1594 ++++++++++++++++++++++++----------------- 1 file changed, 952 insertions(+), 642 deletions(-) (limited to 'drivers/scsi/qla2xxx/qla_os.c') diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 21dd182ad51..cf32653fe01 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 */ @@ -183,42 +188,108 @@ struct scsi_transport_template *qla2xxx_transport_vport_template = NULL; */ __inline__ void -qla2x00_start_timer(scsi_qla_host_t *ha, void *func, unsigned long interval) +qla2x00_start_timer(scsi_qla_host_t *vha, void *func, unsigned long interval) { - init_timer(&ha->timer); - ha->timer.expires = jiffies + interval * HZ; - ha->timer.data = (unsigned long)ha; - ha->timer.function = (void (*)(unsigned long))func; - add_timer(&ha->timer); - ha->timer_active = 1; + init_timer(&vha->timer); + vha->timer.expires = jiffies + interval * HZ; + vha->timer.data = (unsigned long)vha; + vha->timer.function = (void (*)(unsigned long))func; + add_timer(&vha->timer); + vha->timer_active = 1; } static inline void -qla2x00_restart_timer(scsi_qla_host_t *ha, unsigned long interval) +qla2x00_restart_timer(scsi_qla_host_t *vha, unsigned long interval) { - mod_timer(&ha->timer, jiffies + interval * HZ); + mod_timer(&vha->timer, jiffies + interval * HZ); } static __inline__ void -qla2x00_stop_timer(scsi_qla_host_t *ha) +qla2x00_stop_timer(scsi_qla_host_t *vha) { - del_timer_sync(&ha->timer); - ha->timer_active = 0; + del_timer_sync(&vha->timer); + vha->timer_active = 0; } static int qla2x00_do_dpc(void *data); static void qla2x00_rst_aen(scsi_qla_host_t *); -static int qla2x00_mem_alloc(scsi_qla_host_t *); -static void qla2x00_mem_free(scsi_qla_host_t *ha); -static void qla2x00_sp_free_dma(scsi_qla_host_t *, srb_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 *ha, char *str) +qla2x00_pci_info_str(struct scsi_qla_host *vha, char *str) { + struct qla_hw_data *ha = vha->hw; static char *pci_bus_modes[] = { "33", "66", "100", "133", }; @@ -240,9 +311,10 @@ qla2x00_pci_info_str(struct scsi_qla_host *ha, char *str) } static char * -qla24xx_pci_info_str(struct scsi_qla_host *ha, char *str) +qla24xx_pci_info_str(struct scsi_qla_host *vha, char *str) { static char *pci_bus_modes[] = { "33", "66", "100", "133", }; + struct qla_hw_data *ha = vha->hw; uint32_t pci_bus; int pcie_reg; @@ -290,9 +362,10 @@ qla24xx_pci_info_str(struct scsi_qla_host *ha, char *str) } static char * -qla2x00_fw_version_str(struct scsi_qla_host *ha, char *str) +qla2x00_fw_version_str(struct scsi_qla_host *vha, char *str) { char un_str[10]; + struct qla_hw_data *ha = vha->hw; sprintf(str, "%d.%02d.%02d ", ha->fw_major_version, ha->fw_minor_version, @@ -328,44 +401,29 @@ qla2x00_fw_version_str(struct scsi_qla_host *ha, char *str) } static char * -qla24xx_fw_version_str(struct scsi_qla_host *ha, char *str) +qla24xx_fw_version_str(struct scsi_qla_host *vha, char *str) { - sprintf(str, "%d.%02d.%02d ", ha->fw_major_version, - ha->fw_minor_version, - ha->fw_subminor_version); + struct qla_hw_data *ha = vha->hw; - if (ha->fw_attributes & BIT_0) - strcat(str, "[Class 2] "); - if (ha->fw_attributes & BIT_1) - strcat(str, "[IP] "); - if (ha->fw_attributes & BIT_2) - strcat(str, "[Multi-ID] "); - if (ha->fw_attributes & BIT_3) - strcat(str, "[SB-2] "); - if (ha->fw_attributes & BIT_4) - strcat(str, "[T10 CRC] "); - if (ha->fw_attributes & BIT_5) - strcat(str, "[VI] "); - if (ha->fw_attributes & BIT_10) - strcat(str, "[84XX] "); - if (ha->fw_attributes & BIT_13) - strcat(str, "[Experimental]"); + sprintf(str, "%d.%02d.%02d (%x)", ha->fw_major_version, + ha->fw_minor_version, ha->fw_subminor_version, ha->fw_attributes); return str; } static inline srb_t * -qla2x00_get_new_sp(scsi_qla_host_t *ha, fc_port_t *fcport, +qla2x00_get_new_sp(scsi_qla_host_t *vha, fc_port_t *fcport, struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) { srb_t *sp; + struct qla_hw_data *ha = vha->hw; sp = mempool_alloc(ha->srb_mempool, GFP_ATOMIC); if (!sp) return sp; - sp->ha = ha; 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; @@ -376,9 +434,10 @@ qla2x00_get_new_sp(scsi_qla_host_t *ha, fc_port_t *fcport, static int qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) { - scsi_qla_host_t *ha = shost_priv(cmd->device->host); + scsi_qla_host_t *vha = shost_priv(cmd->device->host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device)); + struct qla_hw_data *ha = vha->hw; srb_t *sp; int rval; @@ -399,33 +458,33 @@ qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) if (atomic_read(&fcport->state) != FCS_ONLINE) { if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD || - atomic_read(&ha->loop_state) == LOOP_DEAD) { + atomic_read(&vha->loop_state) == LOOP_DEAD) { cmd->result = DID_NO_CONNECT << 16; goto qc_fail_command; } goto qc_target_busy; } - spin_unlock_irq(ha->host->host_lock); + spin_unlock_irq(vha->host->host_lock); - sp = qla2x00_get_new_sp(ha, fcport, cmd, done); + sp = qla2x00_get_new_sp(vha, fcport, cmd, done); if (!sp) goto qc_host_busy_lock; - rval = qla2x00_start_scsi(sp); + rval = ha->isp_ops->start_scsi(sp); if (rval != QLA_SUCCESS) goto qc_host_busy_free_sp; - spin_lock_irq(ha->host->host_lock); + spin_lock_irq(vha->host->host_lock); return 0; qc_host_busy_free_sp: - qla2x00_sp_free_dma(ha, sp); + qla2x00_sp_free_dma(sp); mempool_free(sp, ha->srb_mempool); qc_host_busy_lock: - spin_lock_irq(ha->host->host_lock); + spin_lock_irq(vha->host->host_lock); return SCSI_MLQUEUE_HOST_BUSY; qc_target_busy: @@ -441,14 +500,15 @@ qc_fail_command: static int qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) { - scsi_qla_host_t *ha = shost_priv(cmd->device->host); + scsi_qla_host_t *vha = shost_priv(cmd->device->host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device)); + struct qla_hw_data *ha = vha->hw; + struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); srb_t *sp; int rval; - scsi_qla_host_t *pha = to_qla_parent(ha); - if (unlikely(pci_channel_offline(pha->pdev))) { + if (unlikely(pci_channel_offline(ha->pdev))) { cmd->result = DID_REQUEUE << 16; goto qc24_fail_command; } @@ -465,33 +525,33 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) if (atomic_read(&fcport->state) != FCS_ONLINE) { if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD || - atomic_read(&pha->loop_state) == LOOP_DEAD) { + atomic_read(&base_vha->loop_state) == LOOP_DEAD) { cmd->result = DID_NO_CONNECT << 16; goto qc24_fail_command; } goto qc24_target_busy; } - spin_unlock_irq(ha->host->host_lock); + spin_unlock_irq(vha->host->host_lock); - sp = qla2x00_get_new_sp(pha, fcport, cmd, done); + sp = qla2x00_get_new_sp(base_vha, fcport, cmd, done); if (!sp) goto qc24_host_busy_lock; - rval = qla24xx_start_scsi(sp); + rval = ha->isp_ops->start_scsi(sp); if (rval != QLA_SUCCESS) goto qc24_host_busy_free_sp; - spin_lock_irq(ha->host->host_lock); + spin_lock_irq(vha->host->host_lock); return 0; qc24_host_busy_free_sp: - qla2x00_sp_free_dma(pha, sp); - mempool_free(sp, pha->srb_mempool); + qla2x00_sp_free_dma(sp); + mempool_free(sp, ha->srb_mempool); qc24_host_busy_lock: - spin_lock_irq(ha->host->host_lock); + spin_lock_irq(vha->host->host_lock); return SCSI_MLQUEUE_HOST_BUSY; qc24_target_busy: @@ -510,17 +570,14 @@ qc24_fail_command: * max time. * * Input: - * ha = actual ha whose done queue will contain the command - * returned by firmware. * cmd = Scsi Command to wait on. - * flag = Abort/Reset(Bus or Device Reset) * * Return: * Not Found : 0 * Found : 1 */ static int -qla2x00_eh_wait_on_command(scsi_qla_host_t *ha, struct scsi_cmnd *cmd) +qla2x00_eh_wait_on_command(struct scsi_cmnd *cmd) { #define ABORT_POLLING_PERIOD 1000 #define ABORT_WAIT_ITER ((10 * 1000) / (ABORT_POLLING_PERIOD)) @@ -557,21 +614,22 @@ qla2x00_eh_wait_on_command(scsi_qla_host_t *ha, struct scsi_cmnd *cmd) * Failed (Adapter is offline/disabled) : 1 */ int -qla2x00_wait_for_hba_online(scsi_qla_host_t *ha) +qla2x00_wait_for_hba_online(scsi_qla_host_t *vha) { int return_status; unsigned long wait_online; - scsi_qla_host_t *pha = to_qla_parent(ha); + struct qla_hw_data *ha = vha->hw; + scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); wait_online = jiffies + (MAX_LOOP_TIMEOUT * HZ); - while (((test_bit(ISP_ABORT_NEEDED, &pha->dpc_flags)) || - test_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags) || - test_bit(ISP_ABORT_RETRY, &pha->dpc_flags) || - pha->dpc_active) && time_before(jiffies, wait_online)) { + while (((test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags)) || + test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags) || + test_bit(ISP_ABORT_RETRY, &base_vha->dpc_flags) || + ha->dpc_active) && time_before(jiffies, wait_online)) { msleep(1000); } - if (pha->flags.online) + if (base_vha->flags.online) return_status = QLA_SUCCESS; else return_status = QLA_FUNCTION_FAILED; @@ -596,19 +654,20 @@ qla2x00_wait_for_hba_online(scsi_qla_host_t *ha) * Failed (LOOP_NOT_READY) : 1 */ static inline int -qla2x00_wait_for_loop_ready(scsi_qla_host_t *ha) +qla2x00_wait_for_loop_ready(scsi_qla_host_t *vha) { int return_status = QLA_SUCCESS; unsigned long loop_timeout ; - scsi_qla_host_t *pha = to_qla_parent(ha); + struct qla_hw_data *ha = vha->hw; + scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); /* wait for 5 min at the max for loop to be ready */ loop_timeout = jiffies + (MAX_LOOP_TIMEOUT * HZ); - while ((!atomic_read(&pha->loop_down_timer) && - atomic_read(&pha->loop_state) == LOOP_DOWN) || - atomic_read(&pha->loop_state) != LOOP_READY) { - if (atomic_read(&pha->loop_state) == LOOP_DEAD) { + while ((!atomic_read(&base_vha->loop_down_timer) && + atomic_read(&base_vha->loop_state) == LOOP_DOWN) || + atomic_read(&base_vha->loop_state) != LOOP_READY) { + if (atomic_read(&base_vha->loop_state) == LOOP_DEAD) { return_status = QLA_FUNCTION_FAILED; break; } @@ -624,35 +683,42 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *ha) 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 *ha = fcport->ha; - scsi_qla_host_t *pha = to_qla_parent(ha); + scsi_qla_host_t *vha = fcport->vha; + struct qla_hw_data *ha = vha->hw; + struct req_que *req; - spin_lock_irqsave(&pha->hardware_lock, flags); - for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { - sp = pha->outstanding_cmds[cnt]; - if (!sp) - continue; - if (sp->fcport != fcport) + 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) 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(&pha->hardware_lock, flags); - if (ha->isp_ops->abort_command(ha, sp)) { - DEBUG2(qla_printk(KERN_WARNING, ha, - "Abort failed -- %lx\n", sp->cmd->serial_number)); - } else { - if (qla2x00_eh_wait_on_command(ha, 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(&pha->hardware_lock, flags); } - spin_unlock_irqrestore(&pha->hardware_lock, flags); + spin_unlock_irqrestore(&ha->hardware_lock, flags); } static void @@ -690,14 +756,16 @@ qla2x00_block_error_handler(struct scsi_cmnd *cmnd) static int qla2xxx_eh_abort(struct scsi_cmnd *cmd) { - scsi_qla_host_t *ha = shost_priv(cmd->device->host); + scsi_qla_host_t *vha = shost_priv(cmd->device->host); srb_t *sp; int ret, i; unsigned int id, lun; unsigned long serial; unsigned long flags; int wait = 0; - scsi_qla_host_t *pha = to_qla_parent(ha); + struct qla_hw_data *ha = vha->hw; + struct req_que *req; + srb_t *spt; qla2x00_block_error_handler(cmd); @@ -709,11 +777,15 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) id = cmd->device->id; lun = cmd->device->lun; serial = cmd->serial_number; + spt = (srb_t *) CMD_SP(cmd); + if (!spt) + return SUCCESS; + req = spt->que; /* Check active list for command command. */ - spin_lock_irqsave(&pha->hardware_lock, flags); + spin_lock_irqsave(&ha->hardware_lock, flags); for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) { - sp = pha->outstanding_cmds[i]; + sp = req->outstanding_cmds[i]; if (sp == NULL) continue; @@ -721,37 +793,36 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) if (sp->cmd != cmd) continue; - DEBUG2(printk("%s(%ld): aborting sp %p from RISC. pid=%ld.\n", - __func__, ha->host_no, sp, serial)); + DEBUG2(printk("%s(%ld): aborting sp %p from RISC." + " pid=%ld.\n", __func__, vha->host_no, sp, serial)); - spin_unlock_irqrestore(&pha->hardware_lock, flags); - if (ha->isp_ops->abort_command(ha, sp)) { + 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__, ha->host_no)); + "mbx failed.\n", __func__, vha->host_no)); } else { DEBUG3(printk("%s(%ld): abort_command " - "mbx success.\n", __func__, ha->host_no)); + "mbx success.\n", __func__, vha->host_no)); wait = 1; } - spin_lock_irqsave(&pha->hardware_lock, flags); - + spin_lock_irqsave(&ha->hardware_lock, flags); break; } - spin_unlock_irqrestore(&pha->hardware_lock, flags); + spin_unlock_irqrestore(&ha->hardware_lock, flags); /* Wait for the command to be returned. */ if (wait) { - if (qla2x00_eh_wait_on_command(ha, cmd) != QLA_SUCCESS) { + if (qla2x00_eh_wait_on_command(cmd) != QLA_SUCCESS) { qla_printk(KERN_ERR, ha, "scsi(%ld:%d:%d): Abort handler timed out -- %lx " - "%x.\n", ha->host_no, id, lun, serial, ret); + "%x.\n", vha->host_no, id, lun, serial, ret); ret = FAILED; } } qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): Abort command issued -- %d %lx %x.\n", - ha->host_no, id, lun, wait, serial, ret); + vha->host_no, id, lun, wait, serial, ret); return ret; } @@ -763,23 +834,27 @@ enum nexus_wait_type { }; static int -qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha, unsigned int t, - unsigned int l, enum nexus_wait_type type) +qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *vha, unsigned int t, + unsigned int l, srb_t *sp, enum nexus_wait_type type) { int cnt, match, status; - srb_t *sp; unsigned long flags; - scsi_qla_host_t *pha = to_qla_parent(ha); + struct qla_hw_data *ha = vha->hw; + struct req_que *req; status = QLA_SUCCESS; - spin_lock_irqsave(&pha->hardware_lock, flags); - for (cnt = 1; status == QLA_SUCCESS && cnt < MAX_OUTSTANDING_COMMANDS; - cnt++) { - sp = pha->outstanding_cmds[cnt]; + if (!sp) + return status; + + spin_lock_irqsave(&ha->hardware_lock, flags); + req = sp->que; + for (cnt = 1; status == QLA_SUCCESS && + cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { + sp = req->outstanding_cmds[cnt]; if (!sp) continue; - if (ha->vp_idx != sp->fcport->ha->vp_idx) + if (vha->vp_idx != sp->fcport->vha->vp_idx) continue; match = 0; switch (type) { @@ -791,17 +866,17 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha, unsigned int t, break; case WAIT_LUN: match = (sp->cmd->device->id == t && - sp->cmd->device->lun == l); + sp->cmd->device->lun == l); break; } if (!match) continue; - spin_unlock_irqrestore(&pha->hardware_lock, flags); - status = qla2x00_eh_wait_on_command(ha, sp->cmd); - spin_lock_irqsave(&pha->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(&pha->hardware_lock, flags); + spin_unlock_irqrestore(&ha->hardware_lock, flags); return status; } @@ -817,7 +892,7 @@ 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)) { - scsi_qla_host_t *ha = shost_priv(cmd->device->host); + scsi_qla_host_t *vha = shost_priv(cmd->device->host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; int err; @@ -826,31 +901,31 @@ __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type, if (!fcport) return FAILED; - qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): %s RESET ISSUED.\n", - ha->host_no, cmd->device->id, cmd->device->lun, name); + qla_printk(KERN_INFO, vha->hw, "scsi(%ld:%d:%d): %s RESET ISSUED.\n", + vha->host_no, cmd->device->id, cmd->device->lun, name); err = 0; - if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS) + if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) goto eh_reset_failed; err = 1; - if (qla2x00_wait_for_loop_ready(ha) != QLA_SUCCESS) + if (qla2x00_wait_for_loop_ready(vha) != QLA_SUCCESS) goto eh_reset_failed; err = 2; if (do_reset(fcport, cmd->device->lun) != QLA_SUCCESS) goto eh_reset_failed; err = 3; - if (qla2x00_eh_wait_for_pending_commands(ha, cmd->device->id, - cmd->device->lun, type) != QLA_SUCCESS) + if (qla2x00_eh_wait_for_pending_commands(vha, cmd->device->id, + cmd->device->lun, (srb_t *) CMD_SP(cmd), type) != QLA_SUCCESS) goto eh_reset_failed; - qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): %s RESET SUCCEEDED.\n", - ha->host_no, cmd->device->id, cmd->device->lun, name); + qla_printk(KERN_INFO, vha->hw, "scsi(%ld:%d:%d): %s RESET SUCCEEDED.\n", + vha->host_no, cmd->device->id, cmd->device->lun, name); return SUCCESS; eh_reset_failed: - qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): %s RESET FAILED: %s.\n", - ha->host_no, cmd->device->id, cmd->device->lun, name, + qla_printk(KERN_INFO, vha->hw, "scsi(%ld:%d:%d): %s RESET FAILED: %s.\n" + , vha->host_no, cmd->device->id, cmd->device->lun, name, reset_errors[err]); return FAILED; } @@ -858,7 +933,8 @@ __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type, static int qla2xxx_eh_device_reset(struct scsi_cmnd *cmd) { - scsi_qla_host_t *ha = shost_priv(cmd->device->host); + scsi_qla_host_t *vha = shost_priv(cmd->device->host); + struct qla_hw_data *ha = vha->hw; return __qla2xxx_eh_generic_reset("DEVICE", WAIT_LUN, cmd, ha->isp_ops->lun_reset); @@ -867,7 +943,8 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd) static int qla2xxx_eh_target_reset(struct scsi_cmnd *cmd) { - scsi_qla_host_t *ha = shost_priv(cmd->device->host); + scsi_qla_host_t *vha = shost_priv(cmd->device->host); + struct qla_hw_data *ha = vha->hw; return __qla2xxx_eh_generic_reset("TARGET", WAIT_TARGET, cmd, ha->isp_ops->target_reset); @@ -891,12 +968,12 @@ qla2xxx_eh_target_reset(struct scsi_cmnd *cmd) static int qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd) { - scsi_qla_host_t *ha = shost_priv(cmd->device->host); - scsi_qla_host_t *pha = to_qla_parent(ha); + scsi_qla_host_t *vha = shost_priv(cmd->device->host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; int ret = FAILED; unsigned int id, lun; unsigned long serial; + srb_t *sp = (srb_t *) CMD_SP(cmd); qla2x00_block_error_handler(cmd); @@ -907,28 +984,28 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd) if (!fcport) return ret; - qla_printk(KERN_INFO, ha, - "scsi(%ld:%d:%d): LOOP RESET ISSUED.\n", ha->host_no, id, lun); + qla_printk(KERN_INFO, vha->hw, + "scsi(%ld:%d:%d): BUS RESET ISSUED.\n", vha->host_no, id, lun); - if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS) { + if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) { DEBUG2(printk("%s failed:board disabled\n",__func__)); goto eh_bus_reset_done; } - if (qla2x00_wait_for_loop_ready(ha) == QLA_SUCCESS) { - if (qla2x00_loop_reset(ha) == QLA_SUCCESS) + if (qla2x00_wait_for_loop_ready(vha) == QLA_SUCCESS) { + if (qla2x00_loop_reset(vha) == QLA_SUCCESS) ret = SUCCESS; } if (ret == FAILED) goto eh_bus_reset_done; /* Flush outstanding commands. */ - if (qla2x00_eh_wait_for_pending_commands(pha, 0, 0, WAIT_HOST) != + if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, sp, WAIT_HOST) != QLA_SUCCESS) ret = FAILED; eh_bus_reset_done: - qla_printk(KERN_INFO, ha, "%s: reset %s\n", __func__, + qla_printk(KERN_INFO, vha->hw, "%s: reset %s\n", __func__, (ret == FAILED) ? "failed" : "succeded"); return ret; @@ -952,12 +1029,14 @@ eh_bus_reset_done: static int qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) { - scsi_qla_host_t *ha = shost_priv(cmd->device->host); + scsi_qla_host_t *vha = shost_priv(cmd->device->host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; + struct qla_hw_data *ha = vha->hw; int ret = FAILED; unsigned int id, lun; unsigned long serial; - scsi_qla_host_t *pha = to_qla_parent(ha); + srb_t *sp = (srb_t *) CMD_SP(cmd); + scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); qla2x00_block_error_handler(cmd); @@ -969,9 +1048,9 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) return ret; qla_printk(KERN_INFO, ha, - "scsi(%ld:%d:%d): ADAPTER RESET ISSUED.\n", ha->host_no, id, lun); + "scsi(%ld:%d:%d): ADAPTER RESET ISSUED.\n", vha->host_no, id, lun); - if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS) + if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) goto eh_host_reset_lock; /* @@ -982,26 +1061,28 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) * devices as lost kicking of the port_down_timer * while dpc is stuck for the mailbox to complete. */ - qla2x00_wait_for_loop_ready(ha); - set_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags); - if (qla2x00_abort_isp(pha)) { - clear_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags); - /* failed. schedule dpc to try */ - set_bit(ISP_ABORT_NEEDED, &pha->dpc_flags); - - if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS) + qla2x00_wait_for_loop_ready(vha); + if (vha != base_vha) { + if (qla2x00_vp_abort_isp(vha)) goto eh_host_reset_lock; + } else { + set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); + if (qla2x00_abort_isp(base_vha)) { + clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); + /* failed. schedule dpc to try */ + set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags); + + if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) + goto eh_host_reset_lock; + } + clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); } - clear_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags); - /* Waiting for our command in done_queue to be returned to OS.*/ - if (qla2x00_eh_wait_for_pending_commands(pha, 0, 0, WAIT_HOST) == - QLA_SUCCESS) + /* Waiting for command to be returned to OS.*/ + if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, sp, WAIT_HOST) == + QLA_SUCCESS) ret = SUCCESS; - if (ha->parent) - qla2x00_vp_abort_isp(ha); - eh_host_reset_lock: qla_printk(KERN_INFO, ha, "%s: reset %s\n", __func__, (ret == FAILED) ? "failed" : "succeded"); @@ -1020,35 +1101,36 @@ eh_host_reset_lock: * 0 = success */ int -qla2x00_loop_reset(scsi_qla_host_t *ha) +qla2x00_loop_reset(scsi_qla_host_t *vha) { int ret; struct fc_port *fcport; + struct qla_hw_data *ha = vha->hw; - if (ha->flags.enable_lip_full_login) { - ret = qla2x00_full_login_lip(ha); + if (ha->flags.enable_lip_full_login && !vha->vp_idx) { + ret = qla2x00_full_login_lip(vha); if (ret != QLA_SUCCESS) { - DEBUG2_3(printk("%s(%ld): bus_reset failed: " - "full_login_lip=%d.\n", __func__, ha->host_no, + DEBUG2_3(printk("%s(%ld): failed: " + "full_login_lip=%d.\n", __func__, vha->host_no, ret)); } - atomic_set(&ha->loop_state, LOOP_DOWN); - atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME); - qla2x00_mark_all_devices_lost(ha, 0); - qla2x00_wait_for_loop_ready(ha); + atomic_set(&vha->loop_state, LOOP_DOWN); + atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); + qla2x00_mark_all_devices_lost(vha, 0); + qla2x00_wait_for_loop_ready(vha); } - if (ha->flags.enable_lip_reset) { - ret = qla2x00_lip_reset(ha); + if (ha->flags.enable_lip_reset && !vha->vp_idx) { + ret = qla2x00_lip_reset(vha); if (ret != QLA_SUCCESS) { - DEBUG2_3(printk("%s(%ld): bus_reset failed: " - "lip_reset=%d.\n", __func__, ha->host_no, ret)); - } - qla2x00_wait_for_loop_ready(ha); + DEBUG2_3(printk("%s(%ld): failed: " + "lip_reset=%d.\n", __func__, vha->host_no, ret)); + } else + qla2x00_wait_for_loop_ready(vha); } if (ha->flags.enable_target_reset) { - list_for_each_entry(fcport, &ha->fcports, list) { + list_for_each_entry(fcport, &vha->vp_fcports, list) { if (fcport->port_type != FCT_TARGET) continue; @@ -1056,31 +1138,37 @@ qla2x00_loop_reset(scsi_qla_host_t *ha) if (ret != QLA_SUCCESS) { DEBUG2_3(printk("%s(%ld): bus_reset failed: " "target_reset=%d d_id=%x.\n", __func__, - ha->host_no, ret, fcport->d_id.b24)); + vha->host_no, ret, fcport->d_id.b24)); } } } - /* Issue marker command only when we are going to start the I/O */ - ha->marker_needed = 1; + vha->marker_needed = 1; return QLA_SUCCESS; } void -qla2x00_abort_all_cmds(scsi_qla_host_t *ha, int res) +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; spin_lock_irqsave(&ha->hardware_lock, flags); - for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { - sp = ha->outstanding_cmds[cnt]; - if (sp) { - ha->outstanding_cmds[cnt] = NULL; - sp->cmd->result = res; - qla2x00_sp_compl(ha, sp); + for (que = 0; que < ha->max_queues; que++) { + req = ha->req_q_map[que]; + if (!req) + continue; + for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { + sp = req->outstanding_cmds[cnt]; + if (sp && sp->fcport->vha == vha) { + req->outstanding_cmds[cnt] = NULL; + sp->cmd->result = res; + qla2x00_sp_compl(ha, sp); + } } } spin_unlock_irqrestore(&ha->hardware_lock, flags); @@ -1102,13 +1190,15 @@ qla2xxx_slave_alloc(struct scsi_device *sdev) static int qla2xxx_slave_configure(struct scsi_device *sdev) { - scsi_qla_host_t *ha = shost_priv(sdev->host); + 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]]; if (sdev->tagged_supported) - scsi_activate_tcq(sdev, ha->max_q_depth); + scsi_activate_tcq(sdev, req->max_q_depth); else - scsi_deactivate_tcq(sdev, ha->max_q_depth); + scsi_deactivate_tcq(sdev, req->max_q_depth); rport->dev_loss_tmo = ha->port_down_retry_count; @@ -1151,8 +1241,9 @@ qla2x00_change_queue_type(struct scsi_device *sdev, int tag_type) * supported addressing method. */ static void -qla2x00_config_dma_addressing(scsi_qla_host_t *ha) +qla2x00_config_dma_addressing(scsi_qla_host_t *vha) { + struct qla_hw_data *ha = vha->hw; /* Assume a 32bit DMA mask. */ ha->flags.enable_64bit_addressing = 0; @@ -1173,7 +1264,7 @@ qla2x00_config_dma_addressing(scsi_qla_host_t *ha) } static void -qla2x00_enable_intrs(scsi_qla_host_t *ha) +qla2x00_enable_intrs(struct qla_hw_data *ha) { unsigned long flags = 0; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; @@ -1188,7 +1279,7 @@ qla2x00_enable_intrs(scsi_qla_host_t *ha) } static void -qla2x00_disable_intrs(scsi_qla_host_t *ha) +qla2x00_disable_intrs(struct qla_hw_data *ha) { unsigned long flags = 0; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; @@ -1202,7 +1293,7 @@ qla2x00_disable_intrs(scsi_qla_host_t *ha) } static void -qla24xx_enable_intrs(scsi_qla_host_t *ha) +qla24xx_enable_intrs(struct qla_hw_data *ha) { unsigned long flags = 0; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; @@ -1215,11 +1306,13 @@ qla24xx_enable_intrs(scsi_qla_host_t *ha) } static void -qla24xx_disable_intrs(scsi_qla_host_t *ha) +qla24xx_disable_intrs(struct qla_hw_data *ha) { unsigned long flags = 0; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + if (IS_NOPOLLING_TYPE(ha)) + return; spin_lock_irqsave(&ha->hardware_lock, flags); ha->interrupts_on = 0; WRT_REG_DWORD(®->ictrl, 0); @@ -1259,6 +1352,10 @@ static struct isp_operations qla2100_isp_ops = { .read_optrom = qla2x00_read_optrom_data, .write_optrom = qla2x00_write_optrom_data, .get_flash_version = qla2x00_get_flash_version, + .start_scsi = qla2x00_start_scsi, + .wrt_req_reg = NULL, + .wrt_rsp_reg = NULL, + .rd_req_reg = NULL, }; static struct isp_operations qla2300_isp_ops = { @@ -1293,6 +1390,10 @@ static struct isp_operations qla2300_isp_ops = { .read_optrom = qla2x00_read_optrom_data, .write_optrom = qla2x00_write_optrom_data, .get_flash_version = qla2x00_get_flash_version, + .start_scsi = qla2x00_start_scsi, + .wrt_req_reg = NULL, + .wrt_rsp_reg = NULL, + .rd_req_reg = NULL, }; static struct isp_operations qla24xx_isp_ops = { @@ -1327,6 +1428,10 @@ static struct isp_operations qla24xx_isp_ops = { .read_optrom = qla24xx_read_optrom_data, .write_optrom = qla24xx_write_optrom_data, .get_flash_version = qla24xx_get_flash_version, + .start_scsi = qla24xx_start_scsi, + .wrt_req_reg = qla24xx_wrt_req_reg, + .wrt_rsp_reg = qla24xx_wrt_rsp_reg, + .rd_req_reg = qla24xx_rd_req_reg, }; static struct isp_operations qla25xx_isp_ops = { @@ -1361,10 +1466,52 @@ static struct isp_operations qla25xx_isp_ops = { .read_optrom = qla25xx_read_optrom_data, .write_optrom = qla24xx_write_optrom_data, .get_flash_version = qla24xx_get_flash_version, + .start_scsi = qla24xx_start_scsi, + .wrt_req_reg = qla24xx_wrt_req_reg, + .wrt_rsp_reg = qla24xx_wrt_rsp_reg, + .rd_req_reg = qla24xx_rd_req_reg, +}; + +static struct isp_operations qla81xx_isp_ops = { + .pci_config = qla25xx_pci_config, + .reset_chip = qla24xx_reset_chip, + .chip_diag = qla24xx_chip_diag, + .config_rings = qla24xx_config_rings, + .reset_adapter = qla24xx_reset_adapter, + .nvram_config = qla81xx_nvram_config, + .update_fw_options = qla81xx_update_fw_options, + .load_risc = qla24xx_load_risc, + .pci_info_str = qla24xx_pci_info_str, + .fw_version_str = qla24xx_fw_version_str, + .intr_handler = qla24xx_intr_handler, + .enable_intrs = qla24xx_enable_intrs, + .disable_intrs = qla24xx_disable_intrs, + .abort_command = qla24xx_abort_command, + .target_reset = qla24xx_abort_target, + .lun_reset = qla24xx_lun_reset, + .fabric_login = qla24xx_login_fabric, + .fabric_logout = qla24xx_fabric_logout, + .calc_req_entries = NULL, + .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, + .fw_dump = qla81xx_fw_dump, + .beacon_on = qla24xx_beacon_on, + .beacon_off = qla24xx_beacon_off, + .beacon_blink = qla24xx_beacon_blink, + .read_optrom = qla25xx_read_optrom_data, + .write_optrom = qla24xx_write_optrom_data, + .get_flash_version = qla24xx_get_flash_version, + .start_scsi = qla24xx_start_scsi, + .wrt_req_reg = qla24xx_wrt_req_reg, + .wrt_rsp_reg = qla24xx_wrt_rsp_reg, + .rd_req_reg = qla24xx_rd_req_reg, }; static inline void -qla2x00_set_isp_flags(scsi_qla_host_t *ha) +qla2x00_set_isp_flags(struct qla_hw_data *ha) { ha->device_type = DT_EXTENDED_IDS; switch (ha->pdev->device) { @@ -1442,13 +1589,21 @@ qla2x00_set_isp_flags(scsi_qla_host_t *ha) ha->device_type |= DT_IIDMA; ha->fw_srisc_address = RISC_START_ADDRESS_2400; break; + case PCI_DEVICE_ID_QLOGIC_ISP8001: + ha->device_type |= DT_ISP8001; + ha->device_type |= DT_ZIO_SUPPORTED; + ha->device_type |= DT_FWI2; + ha->device_type |= DT_IIDMA; + ha->fw_srisc_address = RISC_START_ADDRESS_2400; + break; } } static int -qla2x00_iospace_config(scsi_qla_host_t *ha) +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)) { @@ -1501,6 +1656,30 @@ skip_pio: goto iospace_error_exit; } + /* Determine queue resources */ + ha->max_queues = 1; + if (ql2xmaxqueues <= 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)); + 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); + } + +mqiobase_exit: + ha->msix_count = ha->max_queues + 1; return (0); iospace_error_exit: @@ -1510,25 +1689,25 @@ iospace_error_exit: static void qla2xxx_scan_start(struct Scsi_Host *shost) { - scsi_qla_host_t *ha = shost_priv(shost); + scsi_qla_host_t *vha = shost_priv(shost); - set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); - set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags); - set_bit(RSCN_UPDATE, &ha->dpc_flags); - set_bit(NPIV_CONFIG_NEEDED, &ha->dpc_flags); + set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); + set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); + set_bit(RSCN_UPDATE, &vha->dpc_flags); + set_bit(NPIV_CONFIG_NEEDED, &vha->dpc_flags); } static int qla2xxx_scan_finished(struct Scsi_Host *shost, unsigned long time) { - scsi_qla_host_t *ha = shost_priv(shost); + scsi_qla_host_t *vha = shost_priv(shost); - if (!ha->host) + if (!vha->host) return 1; - if (time > ha->loop_reset_delay * HZ) + if (time > vha->hw->loop_reset_delay * HZ) return 1; - return atomic_read(&ha->loop_state) == LOOP_READY; + return atomic_read(&vha->loop_state) == LOOP_READY; } /* @@ -1539,11 +1718,15 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) { int ret = -ENODEV; struct Scsi_Host *host; - scsi_qla_host_t *ha; + scsi_qla_host_t *base_vha = NULL; + struct qla_hw_data *ha; char pci_info[30]; char fw_str[30]; struct scsi_host_template *sht; - int bars, mem_only = 0; + 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; @@ -1552,7 +1735,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8432 || pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5422 || pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5432 || - pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532) { + pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532 || + pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8001) { bars = pci_select_bars(pdev, IORESOURCE_MEM); sht = &qla24xx_driver_template; mem_only = 1; @@ -1569,33 +1753,24 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) /* This may fail but that's ok */ pci_enable_pcie_error_reporting(pdev); - host = scsi_host_alloc(sht, sizeof(scsi_qla_host_t)); - if (host == NULL) { - printk(KERN_WARNING - "qla2xxx: Couldn't allocate host from scsi layer!\n"); - goto probe_disable_device; + ha = kzalloc(sizeof(struct qla_hw_data), GFP_KERNEL); + if (!ha) { + DEBUG(printk("Unable to allocate memory for ha\n")); + goto probe_out; } + ha->pdev = pdev; /* Clear our data area */ - ha = shost_priv(host); - memset(ha, 0, sizeof(scsi_qla_host_t)); - - ha->pdev = pdev; - ha->host = host; - ha->host_no = host->host_no; - sprintf(ha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, ha->host_no); - ha->parent = NULL; ha->bars = bars; ha->mem_only = mem_only; spin_lock_init(&ha->hardware_lock); /* Set ISP-type information. */ qla2x00_set_isp_flags(ha); - /* Configure PCI I/O space */ ret = qla2x00_iospace_config(ha); if (ret) - goto probe_failed; + goto probe_hw_failed; qla_printk(KERN_INFO, ha, "Found an ISP%04X, irq %d, iobase 0x%p\n", pdev->device, pdev->irq, @@ -1603,95 +1778,170 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->prev_topology = 0; ha->init_cb_size = sizeof(init_cb_t); - ha->mgmt_svr_loop_id = MANAGEMENT_SERVER + ha->vp_idx; ha->link_data_rate = PORT_SPEED_UNKNOWN; ha->optrom_size = OPTROM_SIZE_2300; - ha->max_q_depth = MAX_Q_DEPTH; - if (ql2xmaxqdepth != 0 && ql2xmaxqdepth <= 0xffffU) - ha->max_q_depth = ql2xmaxqdepth; - /* Assign ISP specific operations. */ + max_id = MAX_TARGETS_2200; if (IS_QLA2100(ha)) { - host->max_id = MAX_TARGETS_2100; + max_id = MAX_TARGETS_2100; ha->mbx_count = MAILBOX_REGISTER_COUNT_2100; - ha->request_q_length = REQUEST_ENTRY_CNT_2100; - ha->response_q_length = RESPONSE_ENTRY_CNT_2100; - ha->last_loop_id = SNS_LAST_LOOP_ID_2100; - host->sg_tablesize = 32; + req_length = REQUEST_ENTRY_CNT_2100; + rsp_length = RESPONSE_ENTRY_CNT_2100; + ha->max_loop_id = SNS_LAST_LOOP_ID_2100; ha->gid_list_info_size = 4; + ha->flash_conf_off = ~0; + ha->flash_data_off = ~0; + ha->nvram_conf_off = ~0; + ha->nvram_data_off = ~0; ha->isp_ops = &qla2100_isp_ops; } else if (IS_QLA2200(ha)) { - host->max_id = MAX_TARGETS_2200; ha->mbx_count = MAILBOX_REGISTER_COUNT; - ha->request_q_length = REQUEST_ENTRY_CNT_2200; - ha->response_q_length = RESPONSE_ENTRY_CNT_2100; - ha->last_loop_id = SNS_LAST_LOOP_ID_2100; + req_length = REQUEST_ENTRY_CNT_2200; + rsp_length = RESPONSE_ENTRY_CNT_2100; + ha->max_loop_id = SNS_LAST_LOOP_ID_2100; ha->gid_list_info_size = 4; + ha->flash_conf_off = ~0; + ha->flash_data_off = ~0; + ha->nvram_conf_off = ~0; + ha->nvram_data_off = ~0; ha->isp_ops = &qla2100_isp_ops; } else if (IS_QLA23XX(ha)) { - host->max_id = MAX_TARGETS_2200; ha->mbx_count = MAILBOX_REGISTER_COUNT; - ha->request_q_length = REQUEST_ENTRY_CNT_2200; - ha->response_q_length = RESPONSE_ENTRY_CNT_2300; - ha->last_loop_id = SNS_LAST_LOOP_ID_2300; + req_length = REQUEST_ENTRY_CNT_2200; + rsp_length = RESPONSE_ENTRY_CNT_2300; + ha->max_loop_id = SNS_LAST_LOOP_ID_2300; ha->gid_list_info_size = 6; if (IS_QLA2322(ha) || IS_QLA6322(ha)) ha->optrom_size = OPTROM_SIZE_2322; + ha->flash_conf_off = ~0; + ha->flash_data_off = ~0; + ha->nvram_conf_off = ~0; + ha->nvram_data_off = ~0; ha->isp_ops = &qla2300_isp_ops; } else if (IS_QLA24XX_TYPE(ha)) { - host->max_id = MAX_TARGETS_2200; ha->mbx_count = MAILBOX_REGISTER_COUNT; - ha->request_q_length = REQUEST_ENTRY_CNT_24XX; - ha->response_q_length = RESPONSE_ENTRY_CNT_2300; - ha->last_loop_id = SNS_LAST_LOOP_ID_2300; + req_length = REQUEST_ENTRY_CNT_24XX; + rsp_length = RESPONSE_ENTRY_CNT_2300; + ha->max_loop_id = SNS_LAST_LOOP_ID_2300; ha->init_cb_size = sizeof(struct mid_init_cb_24xx); - ha->mgmt_svr_loop_id = 10 + ha->vp_idx; 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; + ha->flash_conf_off = FARX_ACCESS_FLASH_CONF; + ha->flash_data_off = FARX_ACCESS_FLASH_DATA; + ha->nvram_conf_off = FARX_ACCESS_NVRAM_CONF; + ha->nvram_data_off = FARX_ACCESS_NVRAM_DATA; } else if (IS_QLA25XX(ha)) { - host->max_id = MAX_TARGETS_2200; ha->mbx_count = MAILBOX_REGISTER_COUNT; - ha->request_q_length = REQUEST_ENTRY_CNT_24XX; - ha->response_q_length = RESPONSE_ENTRY_CNT_2300; - ha->last_loop_id = SNS_LAST_LOOP_ID_2300; + req_length = REQUEST_ENTRY_CNT_24XX; + rsp_length = RESPONSE_ENTRY_CNT_2300; + ha->max_loop_id = SNS_LAST_LOOP_ID_2300; ha->init_cb_size = sizeof(struct mid_init_cb_24xx); - ha->mgmt_svr_loop_id = 10 + ha->vp_idx; 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; + ha->flash_conf_off = FARX_ACCESS_FLASH_CONF; + ha->flash_data_off = FARX_ACCESS_FLASH_DATA; + ha->nvram_conf_off = FARX_ACCESS_NVRAM_CONF; + ha->nvram_data_off = FARX_ACCESS_NVRAM_DATA; + } else if (IS_QLA81XX(ha)) { + ha->mbx_count = MAILBOX_REGISTER_COUNT; + req_length = REQUEST_ENTRY_CNT_24XX; + rsp_length = RESPONSE_ENTRY_CNT_2300; + ha->max_loop_id = SNS_LAST_LOOP_ID_2300; + ha->init_cb_size = sizeof(struct mid_init_cb_81xx); + ha->gid_list_info_size = 8; + ha->optrom_size = OPTROM_SIZE_81XX; + ha->isp_ops = &qla81xx_isp_ops; + ha->flash_conf_off = FARX_ACCESS_FLASH_CONF_81XX; + ha->flash_data_off = FARX_ACCESS_FLASH_DATA_81XX; + ha->nvram_conf_off = ~0; + ha->nvram_data_off = ~0; } - host->can_queue = ha->request_q_length + 128; mutex_init(&ha->vport_lock); init_completion(&ha->mbx_cmd_comp); complete(&ha->mbx_cmd_comp); init_completion(&ha->mbx_intr_comp); - INIT_LIST_HEAD(&ha->list); - INIT_LIST_HEAD(&ha->fcports); - INIT_LIST_HEAD(&ha->vp_list); - INIT_LIST_HEAD(&ha->work_list); - set_bit(0, (unsigned long *) ha->vp_idx_map); - qla2x00_config_dma_addressing(ha); - if (qla2x00_mem_alloc(ha)) { + 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"); + goto probe_hw_failed; + } + + req->max_q_depth = MAX_Q_DEPTH; + if (ql2xmaxqdepth != 0 && ql2xmaxqdepth <= 0xffffU) + req->max_q_depth = ql2xmaxqdepth; + + + base_vha = qla2x00_create_host(sht, ha); + if (!base_vha) { + qla_printk(KERN_WARNING, ha, + "[ERROR] Failed to allocate memory for scsi_host\n"); + ret = -ENOMEM; + goto probe_hw_failed; + } + + pci_set_drvdata(pdev, base_vha); + + qla2x00_config_dma_addressing(base_vha); + + host = base_vha->host; + 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 + 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; + host->this_id = 255; + host->cmd_per_lun = 3; + host->unique_id = host->host_no; + host->max_cmd_len = MAX_CMDSZ; + host->max_channel = MAX_BUSES - 1; + 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 (ha->mqenable) { + ha->isp_ops->wrt_req_reg = qla25xx_wrt_req_reg; + ha->isp_ops->wrt_rsp_reg = qla25xx_wrt_rsp_reg; + ha->isp_ops->rd_req_reg = qla25xx_rd_req_reg; + } - if (qla2x00_initialize_adapter(ha)) { + if (qla2x00_initialize_adapter(base_vha)) { qla_printk(KERN_WARNING, ha, "Failed to initialize adapter\n"); DEBUG2(printk("scsi(%ld): Failed to initialize adapter - " "Adapter flags %x.\n", - ha->host_no, ha->device_flags)); + base_vha->host_no, base_vha->device_flags)); ret = -ENODEV; goto probe_failed; @@ -1701,7 +1951,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) * Startup the kernel thread for this host adapter */ ha->dpc_thread = kthread_create(qla2x00_do_dpc, ha, - "%s_dpc", ha->host_str); + "%s_dpc", base_vha->host_str); if (IS_ERR(ha->dpc_thread)) { qla_printk(KERN_WARNING, ha, "Unable to start DPC thread!\n"); @@ -1709,28 +1959,17 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) goto probe_failed; } - host->this_id = 255; - host->cmd_per_lun = 3; - host->unique_id = host->host_no; - host->max_cmd_len = MAX_CMDSZ; - host->max_channel = MAX_BUSES - 1; - host->max_lun = MAX_LUNS; - host->transportt = qla2xxx_transport_template; - - ret = qla2x00_request_irqs(ha); - if (ret) - goto probe_failed; + list_add_tail(&base_vha->list, &ha->vp_list); + base_vha->host->irq = ha->pdev->irq; /* Initialized the timer */ - qla2x00_start_timer(ha, qla2x00_timer, WATCH_INTERVAL); + qla2x00_start_timer(base_vha, qla2x00_timer, WATCH_INTERVAL); DEBUG2(printk("DEBUG: detect hba %ld at address = %p\n", - ha->host_no, ha)); - - pci_set_drvdata(pdev, ha); + base_vha->host_no, ha)); - ha->flags.init_done = 1; - ha->flags.online = 1; + base_vha->flags.init_done = 1; + base_vha->flags.online = 1; ret = scsi_add_host(host, &pdev->dev); if (ret) @@ -1740,76 +1979,97 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) scsi_scan_host(host); - qla2x00_alloc_sysfs_attr(ha); + qla2x00_alloc_sysfs_attr(base_vha); - qla2x00_init_host_attr(ha); + qla2x00_init_host_attr(base_vha); - qla2x00_dfs_setup(ha); + qla2x00_dfs_setup(base_vha); qla_printk(KERN_INFO, ha, "\n" " QLogic Fibre Channel HBA Driver: %s\n" " QLogic %s - %s\n" " ISP%04X: %s @ %s hdma%c, host#=%ld, fw=%s\n", qla2x00_version_str, ha->model_number, - ha->model_desc ? ha->model_desc: "", pdev->device, - ha->isp_ops->pci_info_str(ha, pci_info), pci_name(pdev), - ha->flags.enable_64bit_addressing ? '+': '-', ha->host_no, - ha->isp_ops->fw_version_str(ha, fw_str)); + ha->model_desc ? ha->model_desc : "", pdev->device, + ha->isp_ops->pci_info_str(base_vha, pci_info), pci_name(pdev), + ha->flags.enable_64bit_addressing ? '+' : '-', base_vha->host_no, + ha->isp_ops->fw_version_str(base_vha, fw_str)); return 0; probe_failed: - qla2x00_free_device(ha); + qla2x00_free_device(base_vha); - scsi_host_put(host); + scsi_host_put(base_vha->host); -probe_disable_device: - pci_disable_device(pdev); +probe_hw_failed: + if (ha->iobase) + iounmap(ha->iobase); + + pci_release_selected_regions(ha->pdev, ha->bars); + kfree(ha); + ha = NULL; probe_out: + pci_disable_device(pdev); return ret; } static void qla2x00_remove_one(struct pci_dev *pdev) { - scsi_qla_host_t *ha, *vha, *temp; + scsi_qla_host_t *base_vha, *vha, *temp; + struct qla_hw_data *ha; - ha = pci_get_drvdata(pdev); + base_vha = pci_get_drvdata(pdev); + ha = base_vha->hw; - list_for_each_entry_safe(vha, temp, &ha->vp_list, vp_list) - fc_vport_terminate(vha->fc_vport); + list_for_each_entry_safe(vha, temp, &ha->vp_list, list) { + if (vha && vha->fc_vport) + fc_vport_terminate(vha->fc_vport); + } - set_bit(UNLOADING, &ha->dpc_flags); + set_bit(UNLOADING, &base_vha->dpc_flags); - qla2x00_dfs_remove(ha); + qla2x00_dfs_remove(base_vha); - qla84xx_put_chip(ha); + qla84xx_put_chip(base_vha); - qla2x00_free_sysfs_attr(ha); + qla2x00_free_sysfs_attr(base_vha); - fc_remove_host(ha->host); + fc_remove_host(base_vha->host); - scsi_remove_host(ha->host); + scsi_remove_host(base_vha->host); - qla2x00_free_device(ha); + qla2x00_free_device(base_vha); - scsi_host_put(ha->host); + scsi_host_put(base_vha->host); + + if (ha->iobase) + iounmap(ha->iobase); + + if (ha->mqiobase) + iounmap(ha->mqiobase); + + pci_release_selected_regions(ha->pdev, ha->bars); + kfree(ha); + ha = NULL; pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); } static void -qla2x00_free_device(scsi_qla_host_t *ha) +qla2x00_free_device(scsi_qla_host_t *vha) { - qla2x00_abort_all_cmds(ha, DID_NO_CONNECT << 16); + struct qla_hw_data *ha = vha->hw; + qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16); /* Disable timer */ - if (ha->timer_active) - qla2x00_stop_timer(ha); + if (vha->timer_active) + qla2x00_stop_timer(vha); - ha->flags.online = 0; + vha->flags.online = 0; /* Kill the kernel thread for this host */ if (ha->dpc_thread) { @@ -1824,45 +2084,41 @@ qla2x00_free_device(scsi_qla_host_t *ha) } if (ha->flags.fce_enabled) - qla2x00_disable_fce_trace(ha, NULL, NULL); + qla2x00_disable_fce_trace(vha, NULL, NULL); if (ha->eft) - qla2x00_disable_eft_trace(ha); + qla2x00_disable_eft_trace(vha); /* Stop currently executing firmware. */ - qla2x00_try_to_stop_firmware(ha); + qla2x00_try_to_stop_firmware(vha); /* turn-off interrupts on the card */ if (ha->interrupts_on) ha->isp_ops->disable_intrs(ha); - qla2x00_mem_free(ha); + qla2x00_free_irqs(vha); - qla2x00_free_irqs(ha); + qla2x00_mem_free(ha); - /* release io space registers */ - if (ha->iobase) - iounmap(ha->iobase); - pci_release_selected_regions(ha->pdev, ha->bars); + qla2x00_free_queues(ha); } static inline void -qla2x00_schedule_rport_del(struct scsi_qla_host *ha, fc_port_t *fcport, +qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport, int defer) { struct fc_rport *rport; - scsi_qla_host_t *pha = to_qla_parent(ha); if (!fcport->rport) return; rport = fcport->rport; if (defer) { - spin_lock_irq(ha->host->host_lock); + spin_lock_irq(vha->host->host_lock); fcport->drport = rport; - spin_unlock_irq(ha->host->host_lock); - set_bit(FCPORT_UPDATE_NEEDED, &pha->dpc_flags); - qla2xxx_wake_dpc(pha); + spin_unlock_irq(vha->host->host_lock); + set_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags); + qla2xxx_wake_dpc(vha); } else fc_remote_port_delete(rport); } @@ -1876,13 +2132,14 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *ha, fc_port_t *fcport, * * Context: */ -void qla2x00_mark_device_lost(scsi_qla_host_t *ha, fc_port_t *fcport, +void qla2x00_mark_device_lost(scsi_qla_host_t *vha, fc_port_t *fcport, int do_login, int defer) { if (atomic_read(&fcport->state) == FCS_ONLINE && - ha->vp_idx == fcport->vp_idx) - qla2x00_schedule_rport_del(ha, fcport, defer); - + vha->vp_idx == fcport->vp_idx) { + atomic_set(&fcport->state, FCS_DEVICE_LOST); + qla2x00_schedule_rport_del(vha, fcport, defer); + } /* * We may need to retry the login, so don't change the state of the * port but do the retries. @@ -1894,13 +2151,13 @@ void qla2x00_mark_device_lost(scsi_qla_host_t *ha, fc_port_t *fcport, return; if (fcport->login_retry == 0) { - fcport->login_retry = ha->login_retry_count; - set_bit(RELOGIN_NEEDED, &ha->dpc_flags); + fcport->login_retry = vha->hw->login_retry_count; + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); DEBUG(printk("scsi(%ld): Port login retry: " "%02x%02x%02x%02x%02x%02x%02x%02x, " "id = 0x%04x retry cnt=%d\n", - ha->host_no, + vha->host_no, fcport->port_name[0], fcport->port_name[1], fcport->port_name[2], @@ -1928,13 +2185,12 @@ void qla2x00_mark_device_lost(scsi_qla_host_t *ha, fc_port_t *fcport, * Context: */ void -qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer) +qla2x00_mark_all_devices_lost(scsi_qla_host_t *vha, int defer) { fc_port_t *fcport; - scsi_qla_host_t *pha = to_qla_parent(ha); - list_for_each_entry(fcport, &pha->fcports, list) { - if (ha->vp_idx != fcport->vp_idx) + list_for_each_entry(fcport, &vha->vp_fcports, list) { + if (vha->vp_idx != fcport->vp_idx) continue; /* * No point in marking the device as lost, if the device is @@ -1942,9 +2198,11 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer) */ if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD) continue; - if (atomic_read(&fcport->state) == FCS_ONLINE) - qla2x00_schedule_rport_del(ha, fcport, defer); - atomic_set(&fcport->state, FCS_DEVICE_LOST); + if (atomic_read(&fcport->state) == FCS_ONLINE) { + atomic_set(&fcport->state, FCS_DEVICE_LOST); + qla2x00_schedule_rport_del(vha, fcport, defer); + } else + atomic_set(&fcport->state, FCS_DEVICE_LOST); } } @@ -1957,105 +2215,153 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer) * !0 = failure. */ static int -qla2x00_mem_alloc(scsi_qla_host_t *ha) +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]; - ha->request_ring = dma_alloc_coherent(&ha->pdev->dev, - (ha->request_q_length + 1) * sizeof(request_t), &ha->request_dma, - GFP_KERNEL); - if (!ha->request_ring) - goto fail; - - ha->response_ring = dma_alloc_coherent(&ha->pdev->dev, - (ha->response_q_length + 1) * sizeof(response_t), - &ha->response_dma, GFP_KERNEL); - if (!ha->response_ring) - goto fail_free_request_ring; - - ha->gid_list = dma_alloc_coherent(&ha->pdev->dev, GID_LIST_SIZE, - &ha->gid_list_dma, GFP_KERNEL); - if (!ha->gid_list) - goto fail_free_response_ring; + ha->init_cb_size = sizeof(init_cb_t); + if (IS_QLA2XXX_MIDTYPE(ha)) + ha->init_cb_size = sizeof(struct mid_init_cb_24xx); ha->init_cb = dma_alloc_coherent(&ha->pdev->dev, ha->init_cb_size, - &ha->init_cb_dma, GFP_KERNEL); + &ha->init_cb_dma, GFP_KERNEL); if (!ha->init_cb) - goto fail_free_gid_list; + goto fail; - snprintf(name, sizeof(name), "%s_%ld", QLA2XXX_DRIVER_NAME, - ha->host_no); - ha->s_dma_pool = dma_pool_create(name, &ha->pdev->dev, - DMA_POOL_SIZE, 8, 0); - if (!ha->s_dma_pool) + ha->gid_list = dma_alloc_coherent(&ha->pdev->dev, GID_LIST_SIZE, + &ha->gid_list_dma, GFP_KERNEL); + if (!ha->gid_list) goto fail_free_init_cb; ha->srb_mempool = mempool_create_slab_pool(SRB_MIN_REQ, srb_cachep); if (!ha->srb_mempool) - goto fail_free_s_dma_pool; + goto fail_free_gid_list; /* Get memory for cached NVRAM */ ha->nvram = kzalloc(MAX_NVRAM_SIZE, GFP_KERNEL); if (!ha->nvram) goto fail_free_srb_mempool; + snprintf(name, sizeof(name), "%s_%d", QLA2XXX_DRIVER_NAME, + ha->pdev->device); + ha->s_dma_pool = dma_pool_create(name, &ha->pdev->dev, + DMA_POOL_SIZE, 8, 0); + if (!ha->s_dma_pool) + goto fail_free_nvram; + /* Allocate memory for SNS commands */ if (IS_QLA2100(ha) || IS_QLA2200(ha)) { - /* Get consistent memory allocated for SNS commands */ + /* Get consistent memory allocated for SNS commands */ ha->sns_cmd = dma_alloc_coherent(&ha->pdev->dev, - sizeof(struct sns_cmd_pkt), &ha->sns_cmd_dma, GFP_KERNEL); + sizeof(struct sns_cmd_pkt), &ha->sns_cmd_dma, GFP_KERNEL); if (!ha->sns_cmd) - goto fail_free_nvram; + goto fail_dma_pool; } else { - /* Get consistent memory allocated for MS IOCB */ + /* Get consistent memory allocated for MS IOCB */ ha->ms_iocb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, - &ha->ms_iocb_dma); + &ha->ms_iocb_dma); if (!ha->ms_iocb) - goto fail_free_nvram; - - /* Get consistent memory allocated for CT SNS commands */ + goto fail_dma_pool; + /* Get consistent memory allocated for CT SNS commands */ ha->ct_sns = dma_alloc_coherent(&ha->pdev->dev, - sizeof(struct ct_sns_pkt), &ha->ct_sns_dma, GFP_KERNEL); + sizeof(struct ct_sns_pkt), &ha->ct_sns_dma, GFP_KERNEL); if (!ha->ct_sns) goto fail_free_ms_iocb; } - return 0; + /* Allocate memory for request ring */ + *req = kzalloc(sizeof(struct req_que), GFP_KERNEL); + if (!*req) { + DEBUG(printk("Unable to allocate memory for req\n")); + goto fail_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) { + 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) { + qla_printk(KERN_WARNING, ha, + "Unable to allocate memory for rsp\n"); + goto fail_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) { + 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); +fail_rsp: + 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); +fail_req: + dma_free_coherent(&ha->pdev->dev, sizeof(struct ct_sns_pkt), + ha->ct_sns, ha->ct_sns_dma); + ha->ct_sns = NULL; + ha->ct_sns_dma = 0; fail_free_ms_iocb: dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma); ha->ms_iocb = NULL; ha->ms_iocb_dma = 0; +fail_dma_pool: + dma_pool_destroy(ha->s_dma_pool); + ha->s_dma_pool = NULL; fail_free_nvram: kfree(ha->nvram); ha->nvram = NULL; fail_free_srb_mempool: mempool_destroy(ha->srb_mempool); ha->srb_mempool = NULL; -fail_free_s_dma_pool: - dma_pool_destroy(ha->s_dma_pool); - ha->s_dma_pool = NULL; -fail_free_init_cb: - dma_free_coherent(&ha->pdev->dev, ha->init_cb_size, ha->init_cb, - ha->init_cb_dma); - ha->init_cb = NULL; - ha->init_cb_dma = 0; fail_free_gid_list: dma_free_coherent(&ha->pdev->dev, GID_LIST_SIZE, ha->gid_list, - ha->gid_list_dma); + ha->gid_list_dma); ha->gid_list = NULL; ha->gid_list_dma = 0; -fail_free_response_ring: - dma_free_coherent(&ha->pdev->dev, (ha->response_q_length + 1) * - sizeof(response_t), ha->response_ring, ha->response_dma); - ha->response_ring = NULL; - ha->response_dma = 0; -fail_free_request_ring: - dma_free_coherent(&ha->pdev->dev, (ha->request_q_length + 1) * - sizeof(request_t), ha->request_ring, ha->request_dma); - ha->request_ring = NULL; - ha->request_dma = 0; +fail_free_init_cb: + dma_free_coherent(&ha->pdev->dev, ha->init_cb_size, ha->init_cb, + ha->init_cb_dma); + ha->init_cb = NULL; + ha->init_cb_dma = 0; fail: + DEBUG(printk("%s: Memory allocation failure\n", __func__)); return -ENOMEM; } @@ -2067,32 +2373,29 @@ fail: * ha = adapter block pointer. */ static void -qla2x00_mem_free(scsi_qla_host_t *ha) +qla2x00_mem_free(struct qla_hw_data *ha) { - struct list_head *fcpl, *fcptemp; - fc_port_t *fcport; - if (ha->srb_mempool) mempool_destroy(ha->srb_mempool); if (ha->fce) dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce, - ha->fce_dma); + ha->fce_dma); if (ha->fw_dump) { if (ha->eft) dma_free_coherent(&ha->pdev->dev, - ntohl(ha->fw_dump->eft_size), ha->eft, ha->eft_dma); + ntohl(ha->fw_dump->eft_size), ha->eft, ha->eft_dma); vfree(ha->fw_dump); } if (ha->sns_cmd) dma_free_coherent(&ha->pdev->dev, sizeof(struct sns_cmd_pkt), - ha->sns_cmd, ha->sns_cmd_dma); + ha->sns_cmd, ha->sns_cmd_dma); if (ha->ct_sns) dma_free_coherent(&ha->pdev->dev, sizeof(struct ct_sns_pkt), - ha->ct_sns, ha->ct_sns_dma); + ha->ct_sns, ha->ct_sns_dma); if (ha->sfp_data) dma_pool_free(ha->s_dma_pool, ha->sfp_data, ha->sfp_data_dma); @@ -2103,23 +2406,18 @@ qla2x00_mem_free(scsi_qla_host_t *ha) if (ha->s_dma_pool) dma_pool_destroy(ha->s_dma_pool); - if (ha->init_cb) - dma_free_coherent(&ha->pdev->dev, ha->init_cb_size, - ha->init_cb, ha->init_cb_dma); if (ha->gid_list) dma_free_coherent(&ha->pdev->dev, GID_LIST_SIZE, ha->gid_list, - ha->gid_list_dma); + ha->gid_list_dma); - if (ha->response_ring) - dma_free_coherent(&ha->pdev->dev, - (ha->response_q_length + 1) * sizeof(response_t), - ha->response_ring, ha->response_dma); - if (ha->request_ring) - dma_free_coherent(&ha->pdev->dev, - (ha->request_q_length + 1) * sizeof(request_t), - ha->request_ring, ha->request_dma); + if (ha->init_cb) + dma_free_coherent(&ha->pdev->dev, ha->init_cb_size, + 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; @@ -2138,30 +2436,45 @@ qla2x00_mem_free(scsi_qla_host_t *ha) ha->gid_list = NULL; ha->gid_list_dma = 0; - ha->response_ring = NULL; - ha->response_dma = 0; - ha->request_ring = NULL; - ha->request_dma = 0; + ha->fw_dump = NULL; + ha->fw_dumped = 0; + ha->fw_dump_reading = 0; +} - list_for_each_safe(fcpl, fcptemp, &ha->fcports) { - fcport = list_entry(fcpl, fc_port_t, list); +struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht, + struct qla_hw_data *ha) +{ + struct Scsi_Host *host; + struct scsi_qla_host *vha = NULL; - /* fc ports */ - list_del_init(&fcport->list); - kfree(fcport); + host = scsi_host_alloc(sht, sizeof(scsi_qla_host_t)); + if (host == NULL) { + printk(KERN_WARNING + "qla2xxx: Couldn't allocate host from scsi layer!\n"); + goto fail; } - INIT_LIST_HEAD(&ha->fcports); - ha->fw_dump = NULL; - ha->fw_dumped = 0; - ha->fw_dump_reading = 0; + /* Clear our data area */ + vha = shost_priv(host); + memset(vha, 0, sizeof(scsi_qla_host_t)); - vfree(ha->optrom_buffer); - kfree(ha->nvram); + vha->host = host; + vha->host_no = host->host_no; + vha->hw = ha; + + INIT_LIST_HEAD(&vha->vp_fcports); + INIT_LIST_HEAD(&vha->work_list); + INIT_LIST_HEAD(&vha->list); + + sprintf(vha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, vha->host_no); + return vha; + +fail: + return vha; } static struct qla_work_evt * -qla2x00_alloc_work(struct scsi_qla_host *ha, enum qla_work_type type, +qla2x00_alloc_work(struct scsi_qla_host *vha, enum qla_work_type type, int locked) { struct qla_work_evt *e; @@ -2178,79 +2491,117 @@ qla2x00_alloc_work(struct scsi_qla_host *ha, enum qla_work_type type, } static int -qla2x00_post_work(struct scsi_qla_host *ha, struct qla_work_evt *e, int locked) +qla2x00_post_work(struct scsi_qla_host *vha, struct qla_work_evt *e, int locked) { unsigned long uninitialized_var(flags); - scsi_qla_host_t *pha = to_qla_parent(ha); + struct qla_hw_data *ha = vha->hw; if (!locked) - spin_lock_irqsave(&pha->hardware_lock, flags); - list_add_tail(&e->list, &ha->work_list); - qla2xxx_wake_dpc(ha); + spin_lock_irqsave(&ha->hardware_lock, flags); + list_add_tail(&e->list, &vha->work_list); + qla2xxx_wake_dpc(vha); if (!locked) - spin_unlock_irqrestore(&pha->hardware_lock, flags); + spin_unlock_irqrestore(&ha->hardware_lock, flags); return QLA_SUCCESS; } int -qla2x00_post_aen_work(struct scsi_qla_host *ha, enum fc_host_event_code code, +qla2x00_post_aen_work(struct scsi_qla_host *vha, enum fc_host_event_code code, u32 data) { struct qla_work_evt *e; - e = qla2x00_alloc_work(ha, QLA_EVT_AEN, 1); + e = qla2x00_alloc_work(vha, QLA_EVT_AEN, 1); if (!e) return QLA_FUNCTION_FAILED; e->u.aen.code = code; e->u.aen.data = data; - return qla2x00_post_work(ha, e, 1); -} - -int -qla2x00_post_hwe_work(struct scsi_qla_host *ha, uint16_t code, uint16_t d1, - uint16_t d2, uint16_t d3) -{ - struct qla_work_evt *e; - - e = qla2x00_alloc_work(ha, QLA_EVT_HWE_LOG, 1); - if (!e) - return QLA_FUNCTION_FAILED; - - e->u.hwe.code = code; - e->u.hwe.d1 = d1; - e->u.hwe.d2 = d2; - e->u.hwe.d3 = d3; - return qla2x00_post_work(ha, e, 1); + return qla2x00_post_work(vha, e, 1); } static void -qla2x00_do_work(struct scsi_qla_host *ha) +qla2x00_do_work(struct scsi_qla_host *vha) { struct qla_work_evt *e; - scsi_qla_host_t *pha = to_qla_parent(ha); + struct qla_hw_data *ha = vha->hw; - spin_lock_irq(&pha->hardware_lock); - while (!list_empty(&ha->work_list)) { - e = list_entry(ha->work_list.next, struct qla_work_evt, list); + spin_lock_irq(&ha->hardware_lock); + while (!list_empty(&vha->work_list)) { + e = list_entry(vha->work_list.next, struct qla_work_evt, list); list_del_init(&e->list); - spin_unlock_irq(&pha->hardware_lock); + spin_unlock_irq(&ha->hardware_lock); switch (e->type) { case QLA_EVT_AEN: - fc_host_post_event(ha->host, fc_get_event_number(), + fc_host_post_event(vha->host, fc_get_event_number(), e->u.aen.code, e->u.aen.data); break; - case QLA_EVT_HWE_LOG: - qla2xxx_hw_event_log(ha, e->u.hwe.code, e->u.hwe.d1, - e->u.hwe.d2, e->u.hwe.d3); - break; } if (e->flags & QLA_EVT_FLAG_FREE) kfree(e); - spin_lock_irq(&pha->hardware_lock); + spin_lock_irq(&ha->hardware_lock); + } + spin_unlock_irq(&ha->hardware_lock); +} +/* Relogins all the fcports of a vport + * Context: dpc thread + */ +void qla2x00_relogin(struct scsi_qla_host *vha) +{ + fc_port_t *fcport; + uint8_t status; + uint16_t next_loopid = 0; + struct qla_hw_data *ha = vha->hw; + + list_for_each_entry(fcport, &vha->vp_fcports, list) { + /* + * If the port is not ONLINE then try to login + * to it if we haven't run out of retries. + */ + if (atomic_read(&fcport->state) != + FCS_ONLINE && fcport->login_retry) { + + if (fcport->flags & FCF_FABRIC_DEVICE) { + if (fcport->flags & FCF_TAPE_PRESENT) + ha->isp_ops->fabric_logout(vha, + fcport->loop_id, + fcport->d_id.b.domain, + fcport->d_id.b.area, + fcport->d_id.b.al_pa); + + status = qla2x00_fabric_login(vha, fcport, + &next_loopid); + } else + status = qla2x00_local_device_login(vha, + fcport); + + fcport->login_retry--; + if (status == QLA_SUCCESS) { + fcport->old_loop_id = fcport->loop_id; + + DEBUG(printk("scsi(%ld): port login OK: logged " + "in ID 0x%x\n", vha->host_no, fcport->loop_id)); + + qla2x00_update_fcport(vha, fcport); + + } else if (status == 1) { + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + /* retry the login again */ + DEBUG(printk("scsi(%ld): Retrying" + " %d login again loop_id 0x%x\n", + vha->host_no, fcport->login_retry, + fcport->loop_id)); + } else { + fcport->login_retry = 0; + } + + if (fcport->login_retry == 0 && status != QLA_SUCCESS) + fcport->loop_id = FC_NO_LOOP_ID; + } + if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) + break; } - spin_unlock_irq(&pha->hardware_lock); } /************************************************************************** @@ -2270,15 +2621,11 @@ static int qla2x00_do_dpc(void *data) { int rval; - scsi_qla_host_t *ha; - fc_port_t *fcport; - uint8_t status; - uint16_t next_loopid; - struct scsi_qla_host *vha; - int i; + scsi_qla_host_t *base_vha; + struct qla_hw_data *ha; - - ha = (scsi_qla_host_t *)data; + ha = (struct qla_hw_data *)data; + base_vha = pci_get_drvdata(ha->pdev); set_user_nice(current, -20); @@ -2292,10 +2639,10 @@ qla2x00_do_dpc(void *data) DEBUG3(printk("qla2x00: DPC handler waking up\n")); /* Initialization not yet finished. Don't do anything yet. */ - if (!ha->flags.init_done) + if (!base_vha->flags.init_done) continue; - DEBUG3(printk("scsi(%ld): DPC handler\n", ha->host_no)); + DEBUG3(printk("scsi(%ld): DPC handler\n", base_vha->host_no)); ha->dpc_active = 1; @@ -2304,149 +2651,98 @@ qla2x00_do_dpc(void *data) continue; } - qla2x00_do_work(ha); + qla2x00_do_work(base_vha); - if (test_and_clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) { + if (test_and_clear_bit(ISP_ABORT_NEEDED, + &base_vha->dpc_flags)) { DEBUG(printk("scsi(%ld): dpc: sched " "qla2x00_abort_isp ha = %p\n", - ha->host_no, ha)); + base_vha->host_no, ha)); if (!(test_and_set_bit(ABORT_ISP_ACTIVE, - &ha->dpc_flags))) { + &base_vha->dpc_flags))) { - if (qla2x00_abort_isp(ha)) { + if (qla2x00_abort_isp(base_vha)) { /* failed. retry later */ set_bit(ISP_ABORT_NEEDED, - &ha->dpc_flags); - } - clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); - } - - for_each_mapped_vp_idx(ha, i) { - list_for_each_entry(vha, &ha->vp_list, - vp_list) { - if (i == vha->vp_idx) { - set_bit(ISP_ABORT_NEEDED, - &vha->dpc_flags); - break; - } + &base_vha->dpc_flags); } + clear_bit(ABORT_ISP_ACTIVE, + &base_vha->dpc_flags); } DEBUG(printk("scsi(%ld): dpc: qla2x00_abort_isp end\n", - ha->host_no)); + base_vha->host_no)); } - if (test_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags)) { - qla2x00_update_fcports(ha); - clear_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags); + if (test_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags)) { + qla2x00_update_fcports(base_vha); + clear_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags); } - if (test_and_clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) && - (!(test_and_set_bit(RESET_ACTIVE, &ha->dpc_flags)))) { + if (test_and_clear_bit(RESET_MARKER_NEEDED, + &base_vha->dpc_flags) && + (!(test_and_set_bit(RESET_ACTIVE, &base_vha->dpc_flags)))) { DEBUG(printk("scsi(%ld): qla2x00_reset_marker()\n", - ha->host_no)); + base_vha->host_no)); - qla2x00_rst_aen(ha); - clear_bit(RESET_ACTIVE, &ha->dpc_flags); + qla2x00_rst_aen(base_vha); + clear_bit(RESET_ACTIVE, &base_vha->dpc_flags); } /* Retry each device up to login retry count */ - if ((test_and_clear_bit(RELOGIN_NEEDED, &ha->dpc_flags)) && - !test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) && - atomic_read(&ha->loop_state) != LOOP_DOWN) { + if ((test_and_clear_bit(RELOGIN_NEEDED, + &base_vha->dpc_flags)) && + !test_bit(LOOP_RESYNC_NEEDED, &base_vha->dpc_flags) && + atomic_read(&base_vha->loop_state) != LOOP_DOWN) { DEBUG(printk("scsi(%ld): qla2x00_port_login()\n", - ha->host_no)); - - next_loopid = 0; - list_for_each_entry(fcport, &ha->fcports, list) { - /* - * If the port is not ONLINE then try to login - * to it if we haven't run out of retries. - */ - if (atomic_read(&fcport->state) != FCS_ONLINE && - fcport->login_retry) { - - if (fcport->flags & FCF_FABRIC_DEVICE) { - if (fcport->flags & - FCF_TAPE_PRESENT) - ha->isp_ops->fabric_logout( - ha, fcport->loop_id, - fcport->d_id.b.domain, - fcport->d_id.b.area, - fcport->d_id.b.al_pa); - status = qla2x00_fabric_login( - ha, fcport, &next_loopid); - } else - status = - qla2x00_local_device_login( - ha, fcport); - - fcport->login_retry--; - if (status == QLA_SUCCESS) { - fcport->old_loop_id = fcport->loop_id; - - DEBUG(printk("scsi(%ld): port login OK: logged in ID 0x%x\n", - ha->host_no, fcport->loop_id)); - - qla2x00_update_fcport(ha, - fcport); - } else if (status == 1) { - set_bit(RELOGIN_NEEDED, &ha->dpc_flags); - /* retry the login again */ - DEBUG(printk("scsi(%ld): Retrying %d login again loop_id 0x%x\n", - ha->host_no, - fcport->login_retry, fcport->loop_id)); - } else { - fcport->login_retry = 0; - } - if (fcport->login_retry == 0 && status != QLA_SUCCESS) - fcport->loop_id = FC_NO_LOOP_ID; - } - if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) - break; - } + base_vha->host_no)); + qla2x00_relogin(base_vha); + DEBUG(printk("scsi(%ld): qla2x00_port_login - end\n", - ha->host_no)); + base_vha->host_no)); } - if (test_and_clear_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) { + if (test_and_clear_bit(LOOP_RESYNC_NEEDED, + &base_vha->dpc_flags)) { DEBUG(printk("scsi(%ld): qla2x00_loop_resync()\n", - ha->host_no)); + base_vha->host_no)); if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE, - &ha->dpc_flags))) { + &base_vha->dpc_flags))) { - rval = qla2x00_loop_resync(ha); + rval = qla2x00_loop_resync(base_vha); - clear_bit(LOOP_RESYNC_ACTIVE, &ha->dpc_flags); + clear_bit(LOOP_RESYNC_ACTIVE, + &base_vha->dpc_flags); } DEBUG(printk("scsi(%ld): qla2x00_loop_resync - end\n", - ha->host_no)); + base_vha->host_no)); } - if (test_bit(NPIV_CONFIG_NEEDED, &ha->dpc_flags) && - atomic_read(&ha->loop_state) == LOOP_READY) { - clear_bit(NPIV_CONFIG_NEEDED, &ha->dpc_flags); - qla2xxx_flash_npiv_conf(ha); + if (test_bit(NPIV_CONFIG_NEEDED, &base_vha->dpc_flags) && + atomic_read(&base_vha->loop_state) == LOOP_READY) { + clear_bit(NPIV_CONFIG_NEEDED, &base_vha->dpc_flags); + qla2xxx_flash_npiv_conf(base_vha); } if (!ha->interrupts_on) ha->isp_ops->enable_intrs(ha); - if (test_and_clear_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags)) - ha->isp_ops->beacon_blink(ha); + if (test_and_clear_bit(BEACON_BLINK_NEEDED, + &base_vha->dpc_flags)) + ha->isp_ops->beacon_blink(base_vha); - qla2x00_do_dpc_all_vps(ha); + qla2x00_do_dpc_all_vps(base_vha); ha->dpc_active = 0; } /* End of while(1) */ - DEBUG(printk("scsi(%ld): DPC handler exiting\n", ha->host_no)); + DEBUG(printk("scsi(%ld): DPC handler exiting\n", base_vha->host_no)); /* * Make sure that nobody tries to wake us up again. @@ -2457,11 +2753,12 @@ qla2x00_do_dpc(void *data) } void -qla2xxx_wake_dpc(scsi_qla_host_t *ha) +qla2xxx_wake_dpc(struct scsi_qla_host *vha) { + struct qla_hw_data *ha = vha->hw; struct task_struct *t = ha->dpc_thread; - if (!test_bit(UNLOADING, &ha->dpc_flags) && t) + if (!test_bit(UNLOADING, &vha->dpc_flags) && t) wake_up_process(t); } @@ -2473,26 +2770,26 @@ qla2xxx_wake_dpc(scsi_qla_host_t *ha) * ha = adapter block pointer. */ static void -qla2x00_rst_aen(scsi_qla_host_t *ha) +qla2x00_rst_aen(scsi_qla_host_t *vha) { - if (ha->flags.online && !ha->flags.reset_active && - !atomic_read(&ha->loop_down_timer) && - !(test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags))) { + if (vha->flags.online && !vha->flags.reset_active && + !atomic_read(&vha->loop_down_timer) && + !(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags))) { do { - clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); + clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags); /* * Issue marker command only when we are going to start * the I/O. */ - ha->marker_needed = 1; - } while (!atomic_read(&ha->loop_down_timer) && - (test_bit(RESET_MARKER_NEEDED, &ha->dpc_flags))); + vha->marker_needed = 1; + } while (!atomic_read(&vha->loop_down_timer) && + (test_bit(RESET_MARKER_NEEDED, &vha->dpc_flags))); } } static void -qla2x00_sp_free_dma(scsi_qla_host_t *ha, srb_t *sp) +qla2x00_sp_free_dma(srb_t *sp) { struct scsi_cmnd *cmd = sp->cmd; @@ -2504,11 +2801,11 @@ qla2x00_sp_free_dma(scsi_qla_host_t *ha, srb_t *sp) } void -qla2x00_sp_compl(scsi_qla_host_t *ha, srb_t *sp) +qla2x00_sp_compl(struct qla_hw_data *ha, srb_t *sp) { struct scsi_cmnd *cmd = sp->cmd; - qla2x00_sp_free_dma(ha, sp); + qla2x00_sp_free_dma(sp); mempool_free(sp, ha->srb_mempool); @@ -2524,7 +2821,7 @@ qla2x00_sp_compl(scsi_qla_host_t *ha, srb_t *sp) * Context: Interrupt ***************************************************************************/ void -qla2x00_timer(scsi_qla_host_t *ha) +qla2x00_timer(scsi_qla_host_t *vha) { unsigned long cpu_flags = 0; fc_port_t *fcport; @@ -2532,8 +2829,8 @@ qla2x00_timer(scsi_qla_host_t *ha) int index; srb_t *sp; int t; - scsi_qla_host_t *pha = to_qla_parent(ha); - + struct qla_hw_data *ha = vha->hw; + struct req_que *req; /* * Ports - Port down timer. * @@ -2542,7 +2839,7 @@ qla2x00_timer(scsi_qla_host_t *ha) * the port it marked DEAD. */ t = 0; - list_for_each_entry(fcport, &ha->fcports, list) { + list_for_each_entry(fcport, &vha->vp_fcports, list) { if (fcport->port_type != FCT_TARGET) continue; @@ -2556,7 +2853,7 @@ qla2x00_timer(scsi_qla_host_t *ha) DEBUG(printk("scsi(%ld): fcport-%d - port retry count: " "%d remaining\n", - ha->host_no, + vha->host_no, t, atomic_read(&fcport->port_down_timer))); } t++; @@ -2564,30 +2861,32 @@ qla2x00_timer(scsi_qla_host_t *ha) /* Loop down handler. */ - if (atomic_read(&ha->loop_down_timer) > 0 && - !(test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags)) && ha->flags.online) { + if (atomic_read(&vha->loop_down_timer) > 0 && + !(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) + && vha->flags.online) { - if (atomic_read(&ha->loop_down_timer) == - ha->loop_down_abort_time) { + if (atomic_read(&vha->loop_down_timer) == + vha->loop_down_abort_time) { DEBUG(printk("scsi(%ld): Loop Down - aborting the " "queues before time expire\n", - ha->host_no)); + vha->host_no)); - if (!IS_QLA2100(ha) && ha->link_down_timeout) - atomic_set(&ha->loop_state, LOOP_DEAD); + if (!IS_QLA2100(ha) && vha->link_down_timeout) + atomic_set(&vha->loop_state, LOOP_DEAD); /* Schedule an ISP abort to return any tape commands. */ /* NPIV - scan physical port only */ - if (!ha->parent) { + 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++) { fc_port_t *sfcp; - sp = ha->outstanding_cmds[index]; + sp = req->outstanding_cmds[index]; if (!sp) continue; sfcp = sp->fcport; @@ -2595,74 +2894,75 @@ qla2x00_timer(scsi_qla_host_t *ha) continue; set_bit(ISP_ABORT_NEEDED, - &ha->dpc_flags); + &vha->dpc_flags); break; } spin_unlock_irqrestore(&ha->hardware_lock, - cpu_flags); + cpu_flags); } - set_bit(ABORT_QUEUES_NEEDED, &ha->dpc_flags); + set_bit(ABORT_QUEUES_NEEDED, &vha->dpc_flags); start_dpc++; } /* if the loop has been down for 4 minutes, reinit adapter */ - if (atomic_dec_and_test(&ha->loop_down_timer) != 0) { + if (atomic_dec_and_test(&vha->loop_down_timer) != 0) { DEBUG(printk("scsi(%ld): Loop down exceed 4 mins - " "restarting queues.\n", - ha->host_no)); + vha->host_no)); - set_bit(RESTART_QUEUES_NEEDED, &ha->dpc_flags); + set_bit(RESTART_QUEUES_NEEDED, &vha->dpc_flags); start_dpc++; - if (!(ha->device_flags & DFLG_NO_CABLE) && - !ha->parent) { + if (!(vha->device_flags & DFLG_NO_CABLE) && + !vha->vp_idx) { DEBUG(printk("scsi(%ld): Loop down - " "aborting ISP.\n", - ha->host_no)); + vha->host_no)); qla_printk(KERN_WARNING, ha, "Loop down - aborting ISP.\n"); - set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); } } DEBUG3(printk("scsi(%ld): Loop Down - seconds remaining %d\n", - ha->host_no, - atomic_read(&ha->loop_down_timer))); + vha->host_no, + atomic_read(&vha->loop_down_timer))); } /* Check if beacon LED needs to be blinked */ if (ha->beacon_blink_led == 1) { - set_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags); + set_bit(BEACON_BLINK_NEEDED, &vha->dpc_flags); start_dpc++; } /* Process any deferred work. */ - if (!list_empty(&ha->work_list)) + if (!list_empty(&vha->work_list)) start_dpc++; /* Schedule the DPC routine if needed */ - if ((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) || - test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) || - test_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags) || + if ((test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || + test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags) || + test_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags) || start_dpc || - test_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) || - test_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags) || - test_bit(VP_DPC_NEEDED, &ha->dpc_flags) || - test_bit(RELOGIN_NEEDED, &ha->dpc_flags))) - qla2xxx_wake_dpc(pha); + test_bit(RESET_MARKER_NEEDED, &vha->dpc_flags) || + test_bit(BEACON_BLINK_NEEDED, &vha->dpc_flags) || + test_bit(VP_DPC_NEEDED, &vha->dpc_flags) || + test_bit(RELOGIN_NEEDED, &vha->dpc_flags))) + qla2xxx_wake_dpc(vha); - qla2x00_restart_timer(ha, WATCH_INTERVAL); + qla2x00_restart_timer(vha, WATCH_INTERVAL); } /* Firmware interface routines. */ -#define FW_BLOBS 6 +#define FW_BLOBS 7 #define FW_ISP21XX 0 #define FW_ISP22XX 1 #define FW_ISP2300 2 #define FW_ISP2322 3 #define FW_ISP24XX 4 #define FW_ISP25XX 5 +#define FW_ISP81XX 6 #define FW_FILE_ISP21XX "ql2100_fw.bin" #define FW_FILE_ISP22XX "ql2200_fw.bin" @@ -2670,6 +2970,7 @@ qla2x00_timer(scsi_qla_host_t *ha) #define FW_FILE_ISP2322 "ql2322_fw.bin" #define FW_FILE_ISP24XX "ql2400_fw.bin" #define FW_FILE_ISP25XX "ql2500_fw.bin" +#define FW_FILE_ISP81XX "ql8100_fw.bin" static DEFINE_MUTEX(qla_fw_lock); @@ -2680,11 +2981,13 @@ static struct fw_blob qla_fw_blobs[FW_BLOBS] = { { .name = FW_FILE_ISP2322, .segs = { 0x800, 0x1c000, 0x1e000, 0 }, }, { .name = FW_FILE_ISP24XX, }, { .name = FW_FILE_ISP25XX, }, + { .name = FW_FILE_ISP81XX, }, }; struct fw_blob * -qla2x00_request_firmware(scsi_qla_host_t *ha) +qla2x00_request_firmware(scsi_qla_host_t *vha) { + struct qla_hw_data *ha = vha->hw; struct fw_blob *blob; blob = NULL; @@ -2700,6 +3003,8 @@ qla2x00_request_firmware(scsi_qla_host_t *ha) blob = &qla_fw_blobs[FW_ISP24XX]; } else if (IS_QLA25XX(ha)) { blob = &qla_fw_blobs[FW_ISP25XX]; + } else if (IS_QLA81XX(ha)) { + blob = &qla_fw_blobs[FW_ISP81XX]; } mutex_lock(&qla_fw_lock); @@ -2708,7 +3013,7 @@ qla2x00_request_firmware(scsi_qla_host_t *ha) if (request_firmware(&blob->fw, blob->name, &ha->pdev->dev)) { DEBUG2(printk("scsi(%ld): Failed to load firmware image " - "(%s).\n", ha->host_no, blob->name)); + "(%s).\n", vha->host_no, blob->name)); blob->fw = NULL; blob = NULL; goto out; @@ -2753,7 +3058,8 @@ qla2xxx_pci_mmio_enabled(struct pci_dev *pdev) int risc_paused = 0; uint32_t stat; unsigned long flags; - scsi_qla_host_t *ha = pci_get_drvdata(pdev); + scsi_qla_host_t *base_vha = pci_get_drvdata(pdev); + struct qla_hw_data *ha = base_vha->hw; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24; @@ -2776,7 +3082,7 @@ qla2xxx_pci_mmio_enabled(struct pci_dev *pdev) if (risc_paused) { qla_printk(KERN_INFO, ha, "RISC paused -- mmio_enabled, " "Dumping firmware!\n"); - ha->isp_ops->fw_dump(ha, 0); + ha->isp_ops->fw_dump(base_vha, 0); return PCI_ERS_RESULT_NEED_RESET; } else @@ -2787,7 +3093,8 @@ static pci_ers_result_t qla2xxx_pci_slot_reset(struct pci_dev *pdev) { pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT; - scsi_qla_host_t *ha = pci_get_drvdata(pdev); + scsi_qla_host_t *base_vha = pci_get_drvdata(pdev); + struct qla_hw_data *ha = base_vha->hw; int rc; if (ha->mem_only) @@ -2803,13 +3110,13 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev) } pci_set_master(pdev); - if (ha->isp_ops->pci_config(ha)) + if (ha->isp_ops->pci_config(base_vha)) return ret; - set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); - if (qla2x00_abort_isp(ha)== QLA_SUCCESS) + set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); + if (qla2x00_abort_isp(base_vha) == QLA_SUCCESS) ret = PCI_ERS_RESULT_RECOVERED; - clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); + clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); return ret; } @@ -2817,10 +3124,11 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev) static void qla2xxx_pci_resume(struct pci_dev *pdev) { - scsi_qla_host_t *ha = pci_get_drvdata(pdev); + scsi_qla_host_t *base_vha = pci_get_drvdata(pdev); + struct qla_hw_data *ha = base_vha->hw; int ret; - ret = qla2x00_wait_for_hba_online(ha); + ret = qla2x00_wait_for_hba_online(base_vha); if (ret != QLA_SUCCESS) { qla_printk(KERN_ERR, ha, "the device failed to resume I/O " @@ -2850,6 +3158,7 @@ static struct pci_device_id qla2xxx_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5422) }, { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5432) }, { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2532) }, + { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8001) }, { 0 }, }; MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl); @@ -2938,3 +3247,4 @@ MODULE_FIRMWARE(FW_FILE_ISP2300); MODULE_FIRMWARE(FW_FILE_ISP2322); MODULE_FIRMWARE(FW_FILE_ISP24XX); MODULE_FIRMWARE(FW_FILE_ISP25XX); +MODULE_FIRMWARE(FW_FILE_ISP81XX); -- cgit v1.2.3