diff options
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_os.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 271 |
1 files changed, 187 insertions, 84 deletions
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 62ca1ddb0cc7..9c4699623410 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1043,6 +1043,34 @@ qla2x00_wait_for_hba_online(scsi_qla_host_t *vha) return (return_status); } +static inline int test_fcport_count(scsi_qla_host_t *vha) +{ + struct qla_hw_data *ha = vha->hw; + unsigned long flags; + int res; + + spin_lock_irqsave(&ha->tgt.sess_lock, flags); + ql_dbg(ql_dbg_init, vha, 0xffff, + "tgt %p, fcport_count=%d\n", + vha, vha->fcport_count); + res = (vha->fcport_count == 0); + spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); + + return res; +} + +/* + * qla2x00_wait_for_sess_deletion can only be called from remove_one. + * it has dependency on UNLOADING flag to stop device discovery + */ +static void +qla2x00_wait_for_sess_deletion(scsi_qla_host_t *vha) +{ + qla2x00_mark_all_devices_lost(vha, 0); + + wait_event(vha->fcport_waitQ, test_fcport_count(vha)); +} + /* * qla2x00_wait_for_hba_ready * Wait till the HBA is ready before doing driver unload @@ -2904,6 +2932,18 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) goto probe_init_failed; + base_vha->gnl.size = (ha->max_loop_id + 1) * + sizeof(struct get_name_list_extended); + base_vha->gnl.l = dma_alloc_coherent(&ha->pdev->dev, + base_vha->gnl.size, &base_vha->gnl.ldma, GFP_KERNEL); + INIT_LIST_HEAD(&base_vha->gnl.fcports); + + if (base_vha->gnl.l == NULL) { + ql_log(ql_log_fatal, base_vha, 0xffff, + "Alloc failed for name list.\n"); + goto probe_init_failed; + } + /* Alloc arrays of request and response ring ptrs */ if (!qla2x00_alloc_queues(ha, req, rsp)) { ql_log(ql_log_fatal, base_vha, 0x003d, @@ -3123,7 +3163,8 @@ skip_dpc: ql_dbg(ql_dbg_init, base_vha, 0x00f2, "Init done and hba is online.\n"); - if (qla_ini_mode_enabled(base_vha)) + if (qla_ini_mode_enabled(base_vha) || + qla_dual_mode_enabled(base_vha)) scsi_scan_host(host); else ql_dbg(ql_dbg_init, base_vha, 0x0122, @@ -3372,21 +3413,26 @@ qla2x00_remove_one(struct pci_dev *pdev) * resources. */ if (!atomic_read(&pdev->enable_cnt)) { + dma_free_coherent(&ha->pdev->dev, base_vha->gnl.size, + base_vha->gnl.l, base_vha->gnl.ldma); + scsi_host_put(base_vha->host); kfree(ha); pci_set_drvdata(pdev, NULL); return; } - qla2x00_wait_for_hba_ready(base_vha); - /* if UNLOAD flag is already set, then continue unload, + /* + * if UNLOAD flag is already set, then continue unload, * where it was set first. */ if (test_bit(UNLOADING, &base_vha->dpc_flags)) return; set_bit(UNLOADING, &base_vha->dpc_flags); + dma_free_coherent(&ha->pdev->dev, + base_vha->gnl.size, base_vha->gnl.l, base_vha->gnl.ldma); if (IS_QLAFX00(ha)) qlafx00_driver_shutdown(base_vha, 20); @@ -3535,10 +3581,14 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport, qla2xxx_wake_dpc(base_vha); } else { int now; - if (rport) + if (rport) { + ql_dbg(ql_dbg_disc, fcport->vha, 0xffff, + "%s %8phN. rport %p roles %x \n", + __func__, fcport->port_name, rport, + rport->roles); fc_remote_port_delete(rport); + } qlt_do_generation_tick(vha, &now); - qlt_fc_port_deleted(vha, fcport, now); } } @@ -3581,7 +3631,7 @@ void qla2x00_mark_device_lost(scsi_qla_host_t *vha, fc_port_t *fcport, fcport->login_retry = vha->hw->login_retry_count; ql_dbg(ql_dbg_disc, vha, 0x2067, - "Port login retry %8phN, id = 0x%04x retry cnt=%d.\n", + "Port login retry %8phN, lid 0x%04x retry cnt=%d.\n", fcport->port_name, fcport->loop_id, fcport->login_retry); } } @@ -3604,7 +3654,13 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *vha, int defer) { fc_port_t *fcport; + ql_dbg(ql_dbg_disc, vha, 0xffff, + "Mark all dev lost\n"); + list_for_each_entry(fcport, &vha->vp_fcports, list) { + fcport->scan_state = 0; + qlt_schedule_sess_for_deletion_lock(fcport); + if (vha->vp_idx != 0 && vha->vp_idx != fcport->vha->vp_idx) continue; @@ -4219,6 +4275,7 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht, spin_lock_init(&vha->work_lock); spin_lock_init(&vha->cmd_list_lock); + init_waitqueue_head(&vha->fcport_waitQ); sprintf(vha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, vha->host_no); ql_dbg(ql_dbg_init, vha, 0x0041, @@ -4232,7 +4289,7 @@ fail: return vha; } -static struct qla_work_evt * +struct qla_work_evt * qla2x00_alloc_work(struct scsi_qla_host *vha, enum qla_work_type type) { struct qla_work_evt *e; @@ -4254,7 +4311,7 @@ qla2x00_alloc_work(struct scsi_qla_host *vha, enum qla_work_type type) return e; } -static int +int qla2x00_post_work(struct scsi_qla_host *vha, struct qla_work_evt *e) { unsigned long flags; @@ -4315,7 +4372,6 @@ int qla2x00_post_async_##name##_work( \ } qla2x00_post_async_work(login, QLA_EVT_ASYNC_LOGIN); -qla2x00_post_async_work(login_done, QLA_EVT_ASYNC_LOGIN_DONE); qla2x00_post_async_work(logout, QLA_EVT_ASYNC_LOGOUT); qla2x00_post_async_work(logout_done, QLA_EVT_ASYNC_LOGOUT_DONE); qla2x00_post_async_work(adisc, QLA_EVT_ASYNC_ADISC); @@ -4368,6 +4424,67 @@ qlafx00_post_aenfx_work(struct scsi_qla_host *vha, uint32_t evtcode, return qla2x00_post_work(vha, e); } +int qla24xx_post_upd_fcport_work(struct scsi_qla_host *vha, fc_port_t *fcport) +{ + struct qla_work_evt *e; + + e = qla2x00_alloc_work(vha, QLA_EVT_UPD_FCPORT); + if (!e) + return QLA_FUNCTION_FAILED; + + e->u.fcport.fcport = fcport; + return qla2x00_post_work(vha, e); +} + +static +void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) +{ + unsigned long flags; + fc_port_t *fcport = NULL; + struct qlt_plogi_ack_t *pla = + (struct qlt_plogi_ack_t *)e->u.new_sess.pla; + + spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); + fcport = qla2x00_find_fcport_by_wwpn(vha, e->u.new_sess.port_name, 1); + if (fcport) { + fcport->d_id = e->u.new_sess.id; + if (pla) { + fcport->fw_login_state = DSC_LS_PLOGI_PEND; + qlt_plogi_ack_link(vha, pla, fcport, QLT_PLOGI_LINK_SAME_WWN); + /* we took an extra ref_count to prevent PLOGI ACK when + * fcport/sess has not been created. + */ + pla->ref_count--; + } + } else { + fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); + if (fcport) { + fcport->d_id = e->u.new_sess.id; + fcport->scan_state = QLA_FCPORT_FOUND; + fcport->flags |= FCF_FABRIC_DEVICE; + fcport->fw_login_state = DSC_LS_PLOGI_PEND; + + memcpy(fcport->port_name, e->u.new_sess.port_name, + WWN_SIZE); + list_add_tail(&fcport->list, &vha->vp_fcports); + + if (pla) { + qlt_plogi_ack_link(vha, pla, fcport, + QLT_PLOGI_LINK_SAME_WWN); + pla->ref_count--; + } + } + } + spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); + + if (fcport) { + if (pla) + qlt_plogi_ack_unref(vha, pla); + else + qla24xx_async_gnl(vha, fcport); + } +} + void qla2x00_do_work(struct scsi_qla_host *vha) { @@ -4394,10 +4511,6 @@ qla2x00_do_work(struct scsi_qla_host *vha) qla2x00_async_login(vha, e->u.logio.fcport, e->u.logio.data); break; - case QLA_EVT_ASYNC_LOGIN_DONE: - qla2x00_async_login_done(vha, e->u.logio.fcport, - e->u.logio.data); - break; case QLA_EVT_ASYNC_LOGOUT: qla2x00_async_logout(vha, e->u.logio.fcport); break; @@ -4419,6 +4532,34 @@ qla2x00_do_work(struct scsi_qla_host *vha) case QLA_EVT_AENFX: qlafx00_process_aen(vha, e); break; + case QLA_EVT_GIDPN: + qla24xx_async_gidpn(vha, e->u.fcport.fcport); + break; + case QLA_EVT_GPNID: + qla24xx_async_gpnid(vha, &e->u.gpnid.id); + break; + case QLA_EVT_GPNID_DONE: + qla24xx_async_gpnid_done(vha, e->u.iosb.sp); + break; + case QLA_EVT_NEW_SESS: + qla24xx_create_new_sess(vha, e); + break; + case QLA_EVT_GPDB: + qla24xx_async_gpdb(vha, e->u.fcport.fcport, + e->u.fcport.opt); + break; + case QLA_EVT_GPSC: + qla24xx_async_gpsc(vha, e->u.fcport.fcport); + break; + case QLA_EVT_UPD_FCPORT: + qla2x00_update_fcport(vha, e->u.fcport.fcport); + break; + case QLA_EVT_GNL: + qla24xx_async_gnl(vha, e->u.fcport.fcport); + break; + case QLA_EVT_NACK: + qla24xx_do_nack_work(vha, e); + break; } if (e->flags & QLA_EVT_FLAG_FREE) kfree(e); @@ -4435,9 +4576,7 @@ void qla2x00_relogin(struct scsi_qla_host *vha) { fc_port_t *fcport; int status; - uint16_t next_loopid = 0; - struct qla_hw_data *ha = vha->hw; - uint16_t data[2]; + struct event_arg ea; list_for_each_entry(fcport, &vha->vp_fcports, list) { /* @@ -4448,77 +4587,38 @@ void qla2x00_relogin(struct scsi_qla_host *vha) fcport->login_retry && !(fcport->flags & FCF_ASYNC_SENT)) { fcport->login_retry--; if (fcport->flags & FCF_FABRIC_DEVICE) { - if (fcport->flags & FCF_FCP2_DEVICE) - 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); - - if (fcport->loop_id == FC_NO_LOOP_ID) { - fcport->loop_id = next_loopid = - ha->min_external_loopid; - status = qla2x00_find_new_loop_id( - vha, fcport); - if (status != QLA_SUCCESS) { - /* Ran out of IDs to use */ - break; - } - } - - if (IS_ALOGIO_CAPABLE(ha)) { - fcport->flags |= FCF_ASYNC_SENT; - data[0] = 0; - data[1] = QLA_LOGIO_LOGIN_RETRIED; - status = qla2x00_post_async_login_work( - vha, fcport, data); - if (status == QLA_SUCCESS) - continue; - /* Attempt a retry. */ - status = 1; - } else { - status = qla2x00_fabric_login(vha, - fcport, &next_loopid); - if (status == QLA_SUCCESS) { - int status2; - uint8_t opts; - - opts = 0; - if (fcport->flags & - FCF_FCP2_DEVICE) - opts |= BIT_1; - status2 = - qla2x00_get_port_database( - vha, fcport, opts); - if (status2 != QLA_SUCCESS) - status = 1; - } - } - } else + ql_dbg(ql_dbg_disc, fcport->vha, 0xffff, + "%s %8phC DS %d LS %d\n", __func__, + fcport->port_name, fcport->disc_state, + fcport->fw_login_state); + memset(&ea, 0, sizeof(ea)); + ea.event = FCME_RELOGIN; + ea.fcport = fcport; + qla2x00_fcport_event_handler(vha, &ea); + } else { status = qla2x00_local_device_login(vha, fcport); + if (status == QLA_SUCCESS) { + fcport->old_loop_id = fcport->loop_id; + ql_dbg(ql_dbg_disc, vha, 0x2003, + "Port login OK: logged in ID 0x%x.\n", + fcport->loop_id); + qla2x00_update_fcport(vha, fcport); + } else if (status == 1) { + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + /* retry the login again */ + ql_dbg(ql_dbg_disc, vha, 0x2007, + "Retrying %d login again loop_id 0x%x.\n", + fcport->login_retry, + fcport->loop_id); + } else { + fcport->login_retry = 0; + } - if (status == QLA_SUCCESS) { - fcport->old_loop_id = fcport->loop_id; - - ql_dbg(ql_dbg_disc, vha, 0x2003, - "Port login OK: logged in ID 0x%x.\n", - fcport->loop_id); - - qla2x00_update_fcport(vha, fcport); - - } else if (status == 1) { - set_bit(RELOGIN_NEEDED, &vha->dpc_flags); - /* retry the login again */ - ql_dbg(ql_dbg_disc, vha, 0x2007, - "Retrying %d login again loop_id 0x%x.\n", - fcport->login_retry, fcport->loop_id); - } else { - fcport->login_retry = 0; + if (fcport->login_retry == 0 && + status != QLA_SUCCESS) + qla2x00_clear_loop_id(fcport); } - - if (fcport->login_retry == 0 && status != QLA_SUCCESS) - qla2x00_clear_loop_id(fcport); } if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) break; @@ -5182,7 +5282,8 @@ qla2x00_disable_board_on_pci_error(struct work_struct *work) struct pci_dev *pdev = ha->pdev; scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); - /* if UNLOAD flag is already set, then continue unload, + /* + * if UNLOAD flag is already set, then continue unload, * where it was set first. */ if (test_bit(UNLOADING, &base_vha->dpc_flags)) @@ -5191,6 +5292,8 @@ qla2x00_disable_board_on_pci_error(struct work_struct *work) ql_log(ql_log_warn, base_vha, 0x015b, "Disabling adapter.\n"); + qla2x00_wait_for_sess_deletion(base_vha); + set_bit(UNLOADING, &base_vha->dpc_flags); qla2x00_delete_all_vps(ha, base_vha); |