diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-04 15:15:15 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-04 15:15:15 -0700 |
commit | 03da30986793385af57eeca3296253c887b742e6 (patch) | |
tree | 9c46dbe51c9d0856990649dd917ab45474b7be87 /drivers/scsi/qla2xxx/qla_os.c | |
parent | 6ba74014c1ab0e37af7de6f64b4eccbbae3cb9e7 (diff) | |
parent | 339f4f4eab80caa6cf0d39fb057ad6ddb84ba91e (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (276 commits)
[SCSI] zfcp: Trigger logging in the FCP channel on qdio error conditions
[SCSI] zfcp: Introduce experimental support for DIF/DIX
[SCSI] zfcp: Enable data division support for FCP devices
[SCSI] zfcp: Prevent access on uninitialized memory.
[SCSI] zfcp: Post events through FC transport class
[SCSI] zfcp: Cleanup QDIO attachment and improve processing.
[SCSI] zfcp: Cleanup function parameters for sbal value.
[SCSI] zfcp: Use correct width for timer_interval field
[SCSI] zfcp: Remove SCSI device when removing unit
[SCSI] zfcp: Use memdup_user and kstrdup
[SCSI] zfcp: Fix retry after failed "open port" erp action
[SCSI] zfcp: Fail erp after timeout
[SCSI] zfcp: Use forced_reopen in terminate_rport_io callback
[SCSI] zfcp: Register SCSI devices after successful fc_remote_port_add
[SCSI] zfcp: Do not try "forced close" when port is already closed
[SCSI] zfcp: Do not unblock rport from REOPEN_PORT_FORCED
[SCSI] sd: add support for runtime PM
[SCSI] implement runtime Power Management
[SCSI] convert to the new PM framework
[SCSI] Unify SAM_ and SAM_STAT_ macros
...
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_os.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 109 |
1 files changed, 67 insertions, 42 deletions
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index be1a8fcbb1f..ff2172da7c1 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2008 QLogic Corporation + * Copyright (c) 2003-2010 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -140,7 +140,7 @@ MODULE_PARM_DESC(ql2xetsenable, "Enables firmware ETS burst." "Default is 0 - skip ETS enablement."); -int ql2xdbwr; +int ql2xdbwr = 1; module_param(ql2xdbwr, int, S_IRUGO|S_IRUSR); MODULE_PARM_DESC(ql2xdbwr, "Option to specify scheme for request queue posting\n" @@ -517,6 +517,7 @@ qla2x00_get_new_sp(scsi_qla_host_t *vha, fc_port_t *fcport, if (!sp) return sp; + atomic_set(&sp->ref_count, 1); sp->fcport = fcport; sp->cmd = cmd; sp->flags = 0; @@ -700,7 +701,7 @@ qla2x00_wait_for_hba_online(scsi_qla_host_t *vha) * Success (Adapter is online/no flash ops) : 0 * Failed (Adapter is offline/disabled/flash ops in progress) : 1 */ -int +static int qla2x00_wait_for_reset_ready(scsi_qla_host_t *vha) { int return_status; @@ -797,6 +798,12 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *vha) return (return_status); } +static void +sp_get(struct srb *sp) +{ + atomic_inc(&sp->ref_count); +} + /************************************************************************** * qla2xxx_eh_abort * @@ -825,6 +832,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) struct qla_hw_data *ha = vha->hw; struct req_que *req = vha->req; srb_t *spt; + int got_ref = 0; fc_block_scsi_eh(cmd); @@ -856,6 +864,10 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) DEBUG2(printk("%s(%ld): aborting sp %p from RISC." " pid=%ld.\n", __func__, vha->host_no, sp, serial)); + /* Get a reference to the sp and drop the lock.*/ + sp_get(sp); + got_ref++; + spin_unlock_irqrestore(&ha->hardware_lock, flags); if (ha->isp_ops->abort_command(sp)) { DEBUG2(printk("%s(%ld): abort_command " @@ -881,6 +893,9 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) } } + if (got_ref) + qla2x00_sp_compl(ha, sp); + qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): Abort command issued -- %d %lx %x.\n", vha->host_no, id, lun, wait, serial, ret); @@ -888,24 +903,17 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) return ret; } -enum nexus_wait_type { - WAIT_HOST = 0, - WAIT_TARGET, - WAIT_LUN, -}; - -static int +int 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) + unsigned int l, enum nexus_wait_type type) { int cnt, match, status; unsigned long flags; struct qla_hw_data *ha = vha->hw; struct req_que *req; + srb_t *sp; status = QLA_SUCCESS; - if (!sp) - return status; spin_lock_irqsave(&ha->hardware_lock, flags); req = vha->req; @@ -943,24 +951,6 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *vha, unsigned int t, return status; } -void qla82xx_wait_for_pending_commands(scsi_qla_host_t *vha) -{ - int cnt; - srb_t *sp; - struct req_que *req = vha->req; - - DEBUG2(qla_printk(KERN_INFO, vha->hw, - "Waiting for pending commands\n")); - for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { - sp = req->outstanding_cmds[cnt]; - if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, - sp, WAIT_HOST) == QLA_SUCCESS) { - DEBUG2(qla_printk(KERN_INFO, vha->hw, - "Done wait for pending commands\n")); - } - } -} - static char *reset_errors[] = { "HBA not online", "HBA not ready", @@ -996,7 +986,7 @@ __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type, goto eh_reset_failed; err = 3; if (qla2x00_eh_wait_for_pending_commands(vha, cmd->device->id, - cmd->device->lun, (srb_t *) CMD_SP(cmd), type) != QLA_SUCCESS) + cmd->device->lun, type) != QLA_SUCCESS) goto eh_reset_failed; qla_printk(KERN_INFO, vha->hw, "scsi(%ld:%d:%d): %s RESET SUCCEEDED.\n", @@ -1004,7 +994,7 @@ __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type, return SUCCESS; - eh_reset_failed: +eh_reset_failed: 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]); @@ -1054,7 +1044,6 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd) int ret = FAILED; unsigned int id, lun; unsigned long serial; - srb_t *sp = (srb_t *) CMD_SP(cmd); fc_block_scsi_eh(cmd); @@ -1081,7 +1070,7 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd) goto eh_bus_reset_done; /* Flush outstanding commands. */ - if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, sp, WAIT_HOST) != + if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, WAIT_HOST) != QLA_SUCCESS) ret = FAILED; @@ -1116,7 +1105,6 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) int ret = FAILED; unsigned int id, lun; unsigned long serial; - srb_t *sp = (srb_t *) CMD_SP(cmd); scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); fc_block_scsi_eh(cmd); @@ -1171,7 +1159,7 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) } /* Waiting for command to be returned to OS.*/ - if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, sp, WAIT_HOST) == + if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, WAIT_HOST) == QLA_SUCCESS) ret = SUCCESS; @@ -1662,7 +1650,7 @@ static struct isp_operations qla81xx_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, + .start_scsi = qla24xx_dif_start_scsi, .abort_isp = qla2x00_abort_isp, }; @@ -2113,6 +2101,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) init_completion(&ha->mbx_cmd_comp); complete(&ha->mbx_cmd_comp); init_completion(&ha->mbx_intr_comp); + init_completion(&ha->dcbx_comp); set_bit(0, (unsigned long *) ha->vp_idx_map); @@ -2158,7 +2147,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) host->this_id = 255; host->cmd_per_lun = 3; host->unique_id = host->host_no; - host->max_cmd_len = MAX_CMDSZ; + if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif) + host->max_cmd_len = 32; + else + host->max_cmd_len = MAX_CMDSZ; host->max_channel = MAX_BUSES - 1; host->max_lun = MAX_LUNS; host->transportt = qla2xxx_transport_template; @@ -2258,7 +2250,7 @@ skip_dpc: DEBUG2(printk("DEBUG: detect hba %ld at address = %p\n", base_vha->host_no, ha)); - if (IS_QLA25XX(ha) && ql2xenabledif) { + if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif) { if (ha->fw_attributes & BIT_4) { base_vha->flags.difdix_supported = 1; DEBUG18(qla_printk(KERN_INFO, ha, @@ -2266,8 +2258,10 @@ skip_dpc: " protection.\n")); scsi_host_set_prot(host, SHOST_DIF_TYPE1_PROTECTION + | SHOST_DIF_TYPE2_PROTECTION | SHOST_DIF_TYPE3_PROTECTION | SHOST_DIX_TYPE1_PROTECTION + | SHOST_DIX_TYPE2_PROTECTION | SHOST_DIX_TYPE3_PROTECTION); scsi_host_set_guard(host, SHOST_DIX_GUARD_CRC); } else @@ -2402,6 +2396,10 @@ qla2x00_remove_one(struct pci_dev *pdev) scsi_host_put(base_vha->host); if (IS_QLA82XX(ha)) { + qla82xx_idc_lock(ha); + qla82xx_clear_drv_active(ha); + qla82xx_idc_unlock(ha); + iounmap((device_reg_t __iomem *)ha->nx_pcibase); if (!ql2xdbwr) iounmap((device_reg_t __iomem *)ha->nxdb_wr_ptr); @@ -2467,11 +2465,24 @@ qla2x00_free_device(scsi_qla_host_t *vha) qla2x00_free_irqs(vha); + qla2x00_free_fcports(vha); + qla2x00_mem_free(ha); qla2x00_free_queues(ha); } +void qla2x00_free_fcports(struct scsi_qla_host *vha) +{ + fc_port_t *fcport, *tfcport; + + list_for_each_entry_safe(fcport, tfcport, &vha->vp_fcports, list) { + list_del(&fcport->list); + kfree(fcport); + fcport = NULL; + } +} + static inline void qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport, int defer) @@ -3463,8 +3474,8 @@ qla2x00_sp_free_dma(srb_t *sp) CMD_SP(cmd) = NULL; } -void -qla2x00_sp_compl(struct qla_hw_data *ha, srb_t *sp) +static void +qla2x00_sp_final_compl(struct qla_hw_data *ha, srb_t *sp) { struct scsi_cmnd *cmd = sp->cmd; @@ -3485,6 +3496,20 @@ qla2x00_sp_compl(struct qla_hw_data *ha, srb_t *sp) cmd->scsi_done(cmd); } +void +qla2x00_sp_compl(struct qla_hw_data *ha, srb_t *sp) +{ + if (atomic_read(&sp->ref_count) == 0) { + DEBUG2(qla_printk(KERN_WARNING, ha, + "SP reference-count to ZERO -- sp=%p\n", sp)); + DEBUG2(BUG()); + return; + } + if (!atomic_dec_and_test(&sp->ref_count)) + return; + qla2x00_sp_final_compl(ha, sp); +} + /************************************************************************** * qla2x00_timer * |