summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/qla2xxx/qla_target.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_target.c')
-rw-r--r--drivers/scsi/qla2xxx/qla_target.c542
1 files changed, 374 insertions, 168 deletions
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 8c811b251d42..39828207bc1d 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -141,6 +141,8 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *,
struct abts_recv_from_24xx *);
static void qlt_send_busy(struct qla_qpair *, struct atio_from_isp *,
uint16_t);
+static int qlt_check_reserve_free_req(struct qla_qpair *qpair, uint32_t);
+static inline uint32_t qlt_make_handle(struct qla_qpair *);
/*
* Global Variables
@@ -541,7 +543,6 @@ void qlt_response_pkt_all_vps(struct scsi_qla_host *vha,
qlt_response_pkt(host, rsp, pkt);
break;
}
-
default:
qlt_response_pkt(vha, rsp, pkt);
break;
@@ -600,14 +601,9 @@ void qla2x00_async_nack_sp_done(void *s, int res)
sp->fcport->login_succ = 1;
vha->fcport_count++;
-
- ql_dbg(ql_dbg_disc, vha, 0x20f3,
- "%s %d %8phC post upd_fcport fcp_cnt %d\n",
- __func__, __LINE__,
- sp->fcport->port_name,
- vha->fcport_count);
- sp->fcport->disc_state = DSC_UPD_FCPORT;
- qla24xx_post_upd_fcport_work(vha, sp->fcport);
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
+ qla24xx_sched_upd_fcport(sp->fcport);
+ spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
} else {
sp->fcport->login_retry = 0;
sp->fcport->disc_state = DSC_LOGIN_COMPLETE;
@@ -1230,11 +1226,12 @@ void qlt_schedule_sess_for_deletion(struct fc_port *sess)
{
struct qla_tgt *tgt = sess->tgt;
unsigned long flags;
+ u16 sec;
- if (sess->disc_state == DSC_DELETE_PEND)
+ switch (sess->disc_state) {
+ case DSC_DELETE_PEND:
return;
-
- if (sess->disc_state == DSC_DELETED) {
+ case DSC_DELETED:
if (tgt && tgt->tgt_stop && (tgt->sess_count == 0))
wake_up_all(&tgt->waitQ);
if (sess->vha->fcport_count == 0)
@@ -1243,11 +1240,26 @@ void qlt_schedule_sess_for_deletion(struct fc_port *sess)
if (!sess->plogi_link[QLT_PLOGI_LINK_SAME_WWN] &&
!sess->plogi_link[QLT_PLOGI_LINK_CONFLICT])
return;
+ break;
+ case DSC_UPD_FCPORT:
+ /*
+ * This port is not done reporting to upper layer.
+ * let it finish
+ */
+ sess->next_disc_state = DSC_DELETE_PEND;
+ sec = jiffies_to_msecs(jiffies -
+ sess->jiffies_at_registration)/1000;
+ if (sess->sec_since_registration < sec && sec && !(sec % 5)) {
+ sess->sec_since_registration = sec;
+ ql_dbg(ql_dbg_disc, sess->vha, 0xffff,
+ "%s %8phC : Slow Rport registration(%d Sec)\n",
+ __func__, sess->port_name, sec);
+ }
+ return;
+ default:
+ break;
}
- if (sess->deleted == QLA_SESS_DELETED)
- sess->logout_on_delete = 0;
-
spin_lock_irqsave(&sess->vha->work_lock, flags);
if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
spin_unlock_irqrestore(&sess->vha->work_lock, flags);
@@ -1261,7 +1273,8 @@ void qlt_schedule_sess_for_deletion(struct fc_port *sess)
qla24xx_chk_fcp_state(sess);
ql_dbg(ql_dbg_tgt, sess->vha, 0xe001,
- "Scheduling sess %p for deletion\n", sess);
+ "Scheduling sess %p for deletion %8phC\n",
+ sess, sess->port_name);
INIT_WORK(&sess->del_work, qla24xx_delete_sess_fn);
WARN_ON(!queue_work(sess->vha->hw->wq, &sess->del_work));
@@ -1479,27 +1492,14 @@ int qlt_stop_phase1(struct qla_tgt *tgt)
struct qla_hw_data *ha = tgt->ha;
unsigned long flags;
+ mutex_lock(&ha->optrom_mutex);
mutex_lock(&qla_tgt_mutex);
- if (!vha->fc_vport) {
- struct Scsi_Host *sh = vha->host;
- struct fc_host_attrs *fc_host = shost_to_fc_host(sh);
- bool npiv_vports;
-
- spin_lock_irqsave(sh->host_lock, flags);
- npiv_vports = (fc_host->npiv_vports_inuse);
- spin_unlock_irqrestore(sh->host_lock, flags);
-
- if (npiv_vports) {
- mutex_unlock(&qla_tgt_mutex);
- ql_dbg(ql_dbg_tgt_mgt, vha, 0xf021,
- "NPIV is in use. Can not stop target\n");
- return -EPERM;
- }
- }
+
if (tgt->tgt_stop || tgt->tgt_stopped) {
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04e,
"Already in tgt->tgt_stop or tgt_stopped state\n");
mutex_unlock(&qla_tgt_mutex);
+ mutex_unlock(&ha->optrom_mutex);
return -EPERM;
}
@@ -1537,6 +1537,8 @@ int qlt_stop_phase1(struct qla_tgt *tgt)
/* Wait for sessions to clear out (just in case) */
wait_event_timeout(tgt->waitQ, test_tgt_sess_count(tgt), 10*HZ);
+ mutex_unlock(&ha->optrom_mutex);
+
return 0;
}
EXPORT_SYMBOL(qlt_stop_phase1);
@@ -1566,6 +1568,15 @@ void qlt_stop_phase2(struct qla_tgt *tgt)
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00c, "Stop of tgt %p finished\n",
tgt);
+
+ switch (vha->qlini_mode) {
+ case QLA2XXX_INI_MODE_EXCLUSIVE:
+ vha->flags.online = 1;
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ break;
+ default:
+ break;
+ }
}
EXPORT_SYMBOL(qlt_stop_phase2);
@@ -1715,6 +1726,94 @@ static void qlt_send_notify_ack(struct qla_qpair *qpair,
qla2x00_start_iocbs(vha, qpair->req);
}
+static int qlt_build_abts_resp_iocb(struct qla_tgt_mgmt_cmd *mcmd)
+{
+ struct scsi_qla_host *vha = mcmd->vha;
+ struct qla_hw_data *ha = vha->hw;
+ struct abts_resp_to_24xx *resp;
+ uint32_t f_ctl, h;
+ uint8_t *p;
+ int rc;
+ struct abts_recv_from_24xx *abts = &mcmd->orig_iocb.abts;
+ struct qla_qpair *qpair = mcmd->qpair;
+
+ ql_dbg(ql_dbg_tgt, vha, 0xe006,
+ "Sending task mgmt ABTS response (ha=%p, status=%x)\n",
+ ha, mcmd->fc_tm_rsp);
+
+ rc = qlt_check_reserve_free_req(qpair, 1);
+ if (rc) {
+ ql_dbg(ql_dbg_tgt, vha, 0xe04a,
+ "qla_target(%d): %s failed: unable to allocate request packet\n",
+ vha->vp_idx, __func__);
+ return -EAGAIN;
+ }
+
+ resp = (struct abts_resp_to_24xx *)qpair->req->ring_ptr;
+ memset(resp, 0, sizeof(*resp));
+
+ h = qlt_make_handle(qpair);
+ if (unlikely(h == QLA_TGT_NULL_HANDLE)) {
+ /*
+ * CTIO type 7 from the firmware doesn't provide a way to
+ * know the initiator's LOOP ID, hence we can't find
+ * the session and, so, the command.
+ */
+ return -EAGAIN;
+ } else {
+ qpair->req->outstanding_cmds[h] = (srb_t *)mcmd;
+ }
+
+ resp->handle = MAKE_HANDLE(qpair->req->id, h);
+ resp->entry_type = ABTS_RESP_24XX;
+ resp->entry_count = 1;
+ resp->nport_handle = abts->nport_handle;
+ resp->vp_index = vha->vp_idx;
+ resp->sof_type = abts->sof_type;
+ resp->exchange_address = abts->exchange_address;
+ resp->fcp_hdr_le = abts->fcp_hdr_le;
+ f_ctl = cpu_to_le32(F_CTL_EXCH_CONTEXT_RESP |
+ F_CTL_LAST_SEQ | F_CTL_END_SEQ |
+ F_CTL_SEQ_INITIATIVE);
+ p = (uint8_t *)&f_ctl;
+ resp->fcp_hdr_le.f_ctl[0] = *p++;
+ resp->fcp_hdr_le.f_ctl[1] = *p++;
+ resp->fcp_hdr_le.f_ctl[2] = *p;
+
+ resp->fcp_hdr_le.d_id[0] = abts->fcp_hdr_le.s_id[0];
+ resp->fcp_hdr_le.d_id[1] = abts->fcp_hdr_le.s_id[1];
+ resp->fcp_hdr_le.d_id[2] = abts->fcp_hdr_le.s_id[2];
+ resp->fcp_hdr_le.s_id[0] = abts->fcp_hdr_le.d_id[0];
+ resp->fcp_hdr_le.s_id[1] = abts->fcp_hdr_le.d_id[1];
+ resp->fcp_hdr_le.s_id[2] = abts->fcp_hdr_le.d_id[2];
+
+ resp->exchange_addr_to_abort = abts->exchange_addr_to_abort;
+ if (mcmd->fc_tm_rsp == FCP_TMF_CMPL) {
+ resp->fcp_hdr_le.r_ctl = R_CTL_BASIC_LINK_SERV | R_CTL_B_ACC;
+ resp->payload.ba_acct.seq_id_valid = SEQ_ID_INVALID;
+ resp->payload.ba_acct.low_seq_cnt = 0x0000;
+ resp->payload.ba_acct.high_seq_cnt = 0xFFFF;
+ resp->payload.ba_acct.ox_id = abts->fcp_hdr_le.ox_id;
+ resp->payload.ba_acct.rx_id = abts->fcp_hdr_le.rx_id;
+ } else {
+ resp->fcp_hdr_le.r_ctl = R_CTL_BASIC_LINK_SERV | R_CTL_B_RJT;
+ resp->payload.ba_rjt.reason_code =
+ BA_RJT_REASON_CODE_UNABLE_TO_PERFORM;
+ /* Other bytes are zero */
+ }
+
+ vha->vha_tgt.qla_tgt->abts_resp_expected++;
+
+ /* Memory Barrier */
+ wmb();
+ if (qpair->reqq_start_iocbs)
+ qpair->reqq_start_iocbs(qpair);
+ else
+ qla2x00_start_iocbs(vha, qpair->req);
+
+ return rc;
+}
+
/*
* ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire
*/
@@ -1742,6 +1841,7 @@ static void qlt_24xx_send_abts_resp(struct qla_qpair *qpair,
}
resp->entry_type = ABTS_RESP_24XX;
+ resp->handle = QLA_TGT_SKIP_HANDLE;
resp->entry_count = 1;
resp->nport_handle = abts->nport_handle;
resp->vp_index = vha->vp_idx;
@@ -1799,15 +1899,13 @@ static void qlt_24xx_send_abts_resp(struct qla_qpair *qpair,
* ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire
*/
static void qlt_24xx_retry_term_exchange(struct scsi_qla_host *vha,
- struct abts_resp_from_24xx_fw *entry)
+ struct qla_qpair *qpair, response_t *pkt, struct qla_tgt_mgmt_cmd *mcmd)
{
struct ctio7_to_24xx *ctio;
+ u16 tmp;
+ struct abts_recv_from_24xx *entry;
- ql_dbg(ql_dbg_tgt, vha, 0xe007,
- "Sending retry TERM EXCH CTIO7 (ha=%p)\n", vha->hw);
-
- ctio = (struct ctio7_to_24xx *)qla2x00_alloc_iocbs_ready(
- vha->hw->base_qpair, NULL);
+ ctio = (struct ctio7_to_24xx *)qla2x00_alloc_iocbs_ready(qpair, NULL);
if (ctio == NULL) {
ql_dbg(ql_dbg_tgt, vha, 0xe04b,
"qla_target(%d): %s failed: unable to allocate "
@@ -1815,6 +1913,13 @@ static void qlt_24xx_retry_term_exchange(struct scsi_qla_host *vha,
return;
}
+ if (mcmd)
+ /* abts from remote port */
+ entry = &mcmd->orig_iocb.abts;
+ else
+ /* abts from this driver. */
+ entry = (struct abts_recv_from_24xx *)pkt;
+
/*
* We've got on entrance firmware's response on by us generated
* ABTS response. So, in it ID fields are reversed.
@@ -1826,56 +1931,48 @@ static void qlt_24xx_retry_term_exchange(struct scsi_qla_host *vha,
ctio->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK;
ctio->timeout = cpu_to_le16(QLA_TGT_TIMEOUT);
ctio->vp_index = vha->vp_idx;
- ctio->initiator_id[0] = entry->fcp_hdr_le.d_id[0];
- ctio->initiator_id[1] = entry->fcp_hdr_le.d_id[1];
- ctio->initiator_id[2] = entry->fcp_hdr_le.d_id[2];
ctio->exchange_addr = entry->exchange_addr_to_abort;
- ctio->u.status1.flags = cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_1 |
- CTIO7_FLAGS_TERMINATE);
- ctio->u.status1.ox_id = cpu_to_le16(entry->fcp_hdr_le.ox_id);
+ tmp = (CTIO7_FLAGS_STATUS_MODE_1 | CTIO7_FLAGS_TERMINATE);
- /* Memory Barrier */
- wmb();
- qla2x00_start_iocbs(vha, vha->req);
+ if (mcmd) {
+ ctio->initiator_id[0] = entry->fcp_hdr_le.s_id[0];
+ ctio->initiator_id[1] = entry->fcp_hdr_le.s_id[1];
+ ctio->initiator_id[2] = entry->fcp_hdr_le.s_id[2];
- qlt_24xx_send_abts_resp(vha->hw->base_qpair,
- (struct abts_recv_from_24xx *)entry,
- FCP_TMF_CMPL, true);
-}
-
-static int abort_cmd_for_tag(struct scsi_qla_host *vha, uint32_t tag)
-{
- struct qla_tgt_sess_op *op;
- struct qla_tgt_cmd *cmd;
- unsigned long flags;
+ if (mcmd->flags & QLA24XX_MGMT_ABORT_IO_ATTR_VALID)
+ tmp |= (mcmd->abort_io_attr << 9);
+ else if (qpair->retry_term_cnt & 1)
+ tmp |= (0x4 << 9);
+ } else {
+ ctio->initiator_id[0] = entry->fcp_hdr_le.d_id[0];
+ ctio->initiator_id[1] = entry->fcp_hdr_le.d_id[1];
+ ctio->initiator_id[2] = entry->fcp_hdr_le.d_id[2];
- spin_lock_irqsave(&vha->cmd_list_lock, flags);
- list_for_each_entry(op, &vha->qla_sess_op_cmd_list, cmd_list) {
- if (tag == op->atio.u.isp24.exchange_addr) {
- op->aborted = true;
- spin_unlock_irqrestore(&vha->cmd_list_lock, flags);
- return 1;
- }
+ if (qpair->retry_term_cnt & 1)
+ tmp |= (0x4 << 9);
}
+ ctio->u.status1.flags = cpu_to_le16(tmp);
+ ctio->u.status1.ox_id = entry->fcp_hdr_le.ox_id;
- list_for_each_entry(op, &vha->unknown_atio_list, cmd_list) {
- if (tag == op->atio.u.isp24.exchange_addr) {
- op->aborted = true;
- spin_unlock_irqrestore(&vha->cmd_list_lock, flags);
- return 1;
- }
- }
+ ql_dbg(ql_dbg_tgt, vha, 0xe007,
+ "Sending retry TERM EXCH CTIO7 flags %04xh oxid %04xh attr valid %x\n",
+ le16_to_cpu(ctio->u.status1.flags),
+ le16_to_cpu(ctio->u.status1.ox_id),
+ (mcmd && mcmd->flags & QLA24XX_MGMT_ABORT_IO_ATTR_VALID) ? 1 : 0);
- list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) {
- if (tag == cmd->atio.u.isp24.exchange_addr) {
- cmd->aborted = 1;
- spin_unlock_irqrestore(&vha->cmd_list_lock, flags);
- return 1;
- }
- }
- spin_unlock_irqrestore(&vha->cmd_list_lock, flags);
+ /* Memory Barrier */
+ wmb();
+ if (qpair->reqq_start_iocbs)
+ qpair->reqq_start_iocbs(qpair);
+ else
+ qla2x00_start_iocbs(vha, qpair->req);
+
+ if (mcmd)
+ qlt_build_abts_resp_iocb(mcmd);
+ else
+ qlt_24xx_send_abts_resp(qpair,
+ (struct abts_recv_from_24xx *)entry, FCP_TMF_CMPL, true);
- return 0;
}
/* drop cmds for the given lun
@@ -1970,9 +2067,8 @@ static void qlt_do_tmr_work(struct work_struct *work)
spin_lock_irqsave(mcmd->qpair->qp_lock_ptr, flags);
switch (mcmd->tmr_func) {
case QLA_TGT_ABTS:
- qlt_24xx_send_abts_resp(mcmd->qpair,
- &mcmd->orig_iocb.abts,
- FCP_TMF_REJECTED, false);
+ mcmd->fc_tm_rsp = FCP_TMF_REJECTED;
+ qlt_build_abts_resp_iocb(mcmd);
break;
case QLA_TGT_LUN_RESET:
case QLA_TGT_CLEAR_TS:
@@ -2007,12 +2103,6 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha,
struct qla_tgt_mgmt_cmd *mcmd;
struct qla_qpair_hint *h = &vha->vha_tgt.qla_tgt->qphints[0];
- if (abort_cmd_for_tag(vha, abts->exchange_addr_to_abort)) {
- /* send TASK_ABORT response immediately */
- qlt_24xx_send_abts_resp(ha->base_qpair, abts, FCP_TMF_CMPL, false);
- return 0;
- }
-
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00f,
"qla_target(%d): task abort (tag=%d)\n",
vha->vp_idx, abts->exchange_addr_to_abort);
@@ -2025,7 +2115,7 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha,
return -ENOMEM;
}
memset(mcmd, 0, sizeof(*mcmd));
-
+ mcmd->cmd_type = TYPE_TGT_TMCMD;
mcmd->sess = sess;
memcpy(&mcmd->orig_iocb.abts, abts, sizeof(mcmd->orig_iocb.abts));
mcmd->reset_count = ha->base_qpair->chip_reset;
@@ -2047,6 +2137,8 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha,
if (abort_cmd && abort_cmd->qpair) {
mcmd->qpair = abort_cmd->qpair;
mcmd->se_cmd.cpuid = abort_cmd->se_cmd.cpuid;
+ mcmd->abort_io_attr = abort_cmd->atio.u.isp24.attr;
+ mcmd->flags = QLA24XX_MGMT_ABORT_IO_ATTR_VALID;
}
}
@@ -2264,6 +2356,7 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd)
struct qla_hw_data *ha = vha->hw;
unsigned long flags;
struct qla_qpair *qpair = mcmd->qpair;
+ bool free_mcmd = true;
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf013,
"TM response mcmd (%p) status %#x state %#x",
@@ -2302,10 +2395,10 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd)
&mcmd->orig_iocb.imm_ntfy, 0, 0, 0, 0, 0, 0);
}
} else {
- if (mcmd->orig_iocb.atio.u.raw.entry_type == ABTS_RECV_24XX)
- qlt_24xx_send_abts_resp(qpair, &mcmd->orig_iocb.abts,
- mcmd->fc_tm_rsp, false);
- else
+ if (mcmd->orig_iocb.atio.u.raw.entry_type == ABTS_RECV_24XX) {
+ qlt_build_abts_resp_iocb(mcmd);
+ free_mcmd = false;
+ } else
qlt_24xx_send_task_mgmt_ctio(qpair, mcmd,
mcmd->fc_tm_rsp);
}
@@ -2317,7 +2410,9 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd)
* descriptor after TFO->queue_tm_rsp() -> tcm_qla2xxx_queue_tm_rsp() ->
* qlt_xmit_tm_rsp() returns here..
*/
- ha->tgt.tgt_ops->free_mcmd(mcmd);
+ if (free_mcmd)
+ ha->tgt.tgt_ops->free_mcmd(mcmd);
+
spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
}
EXPORT_SYMBOL(qlt_xmit_tm_rsp);
@@ -2330,7 +2425,7 @@ static int qlt_pci_map_calc_cnt(struct qla_tgt_prm *prm)
BUG_ON(cmd->sg_cnt == 0);
prm->sg = (struct scatterlist *)cmd->sg;
- prm->seg_cnt = pci_map_sg(cmd->qpair->pdev, cmd->sg,
+ prm->seg_cnt = dma_map_sg(&cmd->qpair->pdev->dev, cmd->sg,
cmd->sg_cnt, cmd->dma_data_direction);
if (unlikely(prm->seg_cnt == 0))
goto out_err;
@@ -2357,7 +2452,7 @@ static int qlt_pci_map_calc_cnt(struct qla_tgt_prm *prm)
if (cmd->prot_sg_cnt) {
prm->prot_sg = cmd->prot_sg;
- prm->prot_seg_cnt = pci_map_sg(cmd->qpair->pdev,
+ prm->prot_seg_cnt = dma_map_sg(&cmd->qpair->pdev->dev,
cmd->prot_sg, cmd->prot_sg_cnt,
cmd->dma_data_direction);
if (unlikely(prm->prot_seg_cnt == 0))
@@ -2392,12 +2487,12 @@ static void qlt_unmap_sg(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd)
qpair = cmd->qpair;
- pci_unmap_sg(qpair->pdev, cmd->sg, cmd->sg_cnt,
+ dma_unmap_sg(&qpair->pdev->dev, cmd->sg, cmd->sg_cnt,
cmd->dma_data_direction);
cmd->sg_mapped = 0;
if (cmd->prot_sg_cnt)
- pci_unmap_sg(qpair->pdev, cmd->prot_sg, cmd->prot_sg_cnt,
+ dma_unmap_sg(&qpair->pdev->dev, cmd->prot_sg, cmd->prot_sg_cnt,
cmd->dma_data_direction);
if (!cmd->ctx)
@@ -3289,7 +3384,10 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
cmd->state = QLA_TGT_STATE_PROCESSED; /* Mid-level is done processing */
+ spin_lock(&cmd->cmd_lock);
cmd->cmd_sent_to_fw = 1;
+ spin_unlock(&cmd->cmd_lock);
+ cmd->ctio_flags = le16_to_cpu(pkt->u.status0.flags);
/* Memory Barrier */
wmb();
@@ -3367,7 +3465,10 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd)
qlt_load_data_segments(&prm);
cmd->state = QLA_TGT_STATE_NEED_DATA;
+ spin_lock(&cmd->cmd_lock);
cmd->cmd_sent_to_fw = 1;
+ spin_unlock(&cmd->cmd_lock);
+ cmd->ctio_flags = le16_to_cpu(pkt->u.status0.flags);
/* Memory Barrier */
wmb();
@@ -3825,10 +3926,10 @@ static int qlt_term_ctio_exchange(struct qla_qpair *qpair, void *ctio,
/* ha->hardware_lock supposed to be held on entry */
-static struct qla_tgt_cmd *qlt_ctio_to_cmd(struct scsi_qla_host *vha,
+static void *qlt_ctio_to_cmd(struct scsi_qla_host *vha,
struct rsp_que *rsp, uint32_t handle, void *ctio)
{
- struct qla_tgt_cmd *cmd = NULL;
+ void *cmd = NULL;
struct req_que *req;
int qid = GET_QID(handle);
uint32_t h = handle & ~QLA_TGT_HANDLE_MASK;
@@ -3857,7 +3958,7 @@ static struct qla_tgt_cmd *qlt_ctio_to_cmd(struct scsi_qla_host *vha,
return NULL;
}
- cmd = (struct qla_tgt_cmd *)req->outstanding_cmds[h];
+ cmd = (void *) req->outstanding_cmds[h];
if (unlikely(cmd == NULL)) {
ql_dbg(ql_dbg_async, vha, 0xe053,
"qla_target(%d): Suspicious: unable to find the command with handle %x req->id %d rsp->id %d\n",
@@ -3930,7 +4031,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha,
return;
}
- cmd = qlt_ctio_to_cmd(vha, rsp, handle, ctio);
+ cmd = (struct qla_tgt_cmd *)qlt_ctio_to_cmd(vha, rsp, handle, ctio);
if (cmd == NULL)
return;
@@ -3941,12 +4042,20 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha,
if (unlikely(status != CTIO_SUCCESS)) {
switch (status & 0xFFFF) {
+ case CTIO_INVALID_RX_ID:
+ if (printk_ratelimit())
+ dev_info(&vha->hw->pdev->dev,
+ "qla_target(%d): CTIO with INVALID_RX_ID ATIO attr %x CTIO Flags %x|%x\n",
+ vha->vp_idx, cmd->atio.u.isp24.attr,
+ ((cmd->ctio_flags >> 9) & 0xf),
+ cmd->ctio_flags);
+
+ break;
case CTIO_LIP_RESET:
case CTIO_TARGET_RESET:
case CTIO_ABORTED:
/* driver request abort via Terminate exchange */
case CTIO_TIMEOUT:
- case CTIO_INVALID_RX_ID:
/* They are OK */
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf058,
"qla_target(%d): CTIO with "
@@ -3973,7 +4082,6 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha,
* Session is already logged out, but we need
* to notify initiator, who's not aware of this
*/
- cmd->sess->logout_on_delete = 0;
cmd->sess->send_els_logo = 1;
ql_dbg(ql_dbg_disc, vha, 0x20f8,
"%s %d %8phC post del sess\n",
@@ -4711,6 +4819,12 @@ static int qlt_handle_login(struct scsi_qla_host *vha,
sess = qlt_find_sess_invalidate_other(vha, wwn,
port_id, loop_id, &conflict_sess);
spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
+ } else {
+ ql_dbg(ql_dbg_disc, vha, 0xffff,
+ "%s %d Term INOT due to WWN=0 lid=%d, NportID %06X ",
+ __func__, __LINE__, loop_id, port_id.b24);
+ qlt_send_term_imm_notif(vha, iocb, 1);
+ goto out;
}
if (IS_SW_RESV_ADDR(port_id)) {
@@ -4752,6 +4866,32 @@ static int qlt_handle_login(struct scsi_qla_host *vha,
goto out;
}
+ if (sess->disc_state == DSC_UPD_FCPORT) {
+ u16 sec;
+
+ /*
+ * Remote port registration is still going on from
+ * previous login. Allow it to finish before we
+ * accept the new login.
+ */
+ sess->next_disc_state = DSC_DELETE_PEND;
+ sec = jiffies_to_msecs(jiffies -
+ sess->jiffies_at_registration) / 1000;
+ if (sess->sec_since_registration < sec && sec &&
+ !(sec % 5)) {
+ sess->sec_since_registration = sec;
+ ql_dbg(ql_dbg_disc, vha, 0xffff,
+ "%s %8phC - Slow Rport registration (%d Sec)\n",
+ __func__, sess->port_name, sec);
+ }
+
+ if (!conflict_sess)
+ kmem_cache_free(qla_tgt_plogi_cachep, pla);
+
+ qlt_send_term_imm_notif(vha, iocb, 1);
+ goto out;
+ }
+
qlt_plogi_ack_link(vha, pla, sess, QLT_PLOGI_LINK_SAME_WWN);
sess->d_id = port_id;
sess->login_gen++;
@@ -4910,6 +5050,7 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
if (sess != NULL) {
bool delete = false;
+ int sec;
spin_lock_irqsave(&tgt->ha->tgt.sess_lock, flags);
switch (sess->fw_login_state) {
case DSC_LS_PLOGI_PEND:
@@ -4922,9 +5063,24 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
}
switch (sess->disc_state) {
+ case DSC_UPD_FCPORT:
+ spin_unlock_irqrestore(&tgt->ha->tgt.sess_lock,
+ flags);
+
+ sec = jiffies_to_msecs(jiffies -
+ sess->jiffies_at_registration)/1000;
+ if (sess->sec_since_registration < sec && sec &&
+ !(sec % 5)) {
+ sess->sec_since_registration = sec;
+ ql_dbg(ql_dbg_disc, sess->vha, 0xffff,
+ "%s %8phC : Slow Rport registration(%d Sec)\n",
+ __func__, sess->port_name, sec);
+ }
+ qlt_send_term_imm_notif(vha, iocb, 1);
+ return 0;
+
case DSC_LOGIN_PEND:
case DSC_GPDB:
- case DSC_UPD_FCPORT:
case DSC_LOGIN_COMPLETE:
case DSC_ADISC:
delete = false;
@@ -5608,6 +5764,101 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
tgt->atio_irq_cmd_count--;
}
+/*
+ * qpair lock is assume to be held
+ * rc = 0 : send terminate & abts respond
+ * rc != 0: do not send term & abts respond
+ */
+static int qlt_chk_unresolv_exchg(struct scsi_qla_host *vha,
+ struct qla_qpair *qpair, struct abts_resp_from_24xx_fw *entry)
+{
+ struct qla_hw_data *ha = vha->hw;
+ int rc = 0;
+
+ /*
+ * Detect unresolved exchange. If the same ABTS is unable
+ * to terminate an existing command and the same ABTS loops
+ * between FW & Driver, then force FW dump. Under 1 jiff,
+ * we should see multiple loops.
+ */
+ if (qpair->retry_term_exchg_addr == entry->exchange_addr_to_abort &&
+ qpair->retry_term_jiff == jiffies) {
+ /* found existing exchange */
+ qpair->retry_term_cnt++;
+ if (qpair->retry_term_cnt >= 5) {
+ rc = EIO;
+ qpair->retry_term_cnt = 0;
+ ql_log(ql_log_warn, vha, 0xffff,
+ "Unable to send ABTS Respond. Dumping firmware.\n");
+ ql_dump_buffer(ql_dbg_tgt_mgt + ql_dbg_buffer,
+ vha, 0xffff, (uint8_t *)entry, sizeof(*entry));
+
+ if (qpair == ha->base_qpair)
+ ha->isp_ops->fw_dump(vha, 1);
+ else
+ ha->isp_ops->fw_dump(vha, 0);
+
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ }
+ } else if (qpair->retry_term_jiff != jiffies) {
+ qpair->retry_term_exchg_addr = entry->exchange_addr_to_abort;
+ qpair->retry_term_cnt = 0;
+ qpair->retry_term_jiff = jiffies;
+ }
+
+ return rc;
+}
+
+
+static void qlt_handle_abts_completion(struct scsi_qla_host *vha,
+ struct rsp_que *rsp, response_t *pkt)
+{
+ struct abts_resp_from_24xx_fw *entry =
+ (struct abts_resp_from_24xx_fw *)pkt;
+ u32 h = pkt->handle & ~QLA_TGT_HANDLE_MASK;
+ struct qla_tgt_mgmt_cmd *mcmd;
+ struct qla_hw_data *ha = vha->hw;
+
+ mcmd = (struct qla_tgt_mgmt_cmd *)qlt_ctio_to_cmd(vha, rsp,
+ pkt->handle, pkt);
+ if (mcmd == NULL && h != QLA_TGT_SKIP_HANDLE) {
+ ql_dbg(ql_dbg_async, vha, 0xe064,
+ "qla_target(%d): ABTS Comp without mcmd\n",
+ vha->vp_idx);
+ return;
+ }
+
+ if (mcmd)
+ vha = mcmd->vha;
+ vha->vha_tgt.qla_tgt->abts_resp_expected--;
+
+ ql_dbg(ql_dbg_tgt, vha, 0xe038,
+ "ABTS_RESP_24XX: compl_status %x\n",
+ entry->compl_status);
+
+ if (le16_to_cpu(entry->compl_status) != ABTS_RESP_COMPL_SUCCESS) {
+ if ((entry->error_subcode1 == 0x1E) &&
+ (entry->error_subcode2 == 0)) {
+ if (qlt_chk_unresolv_exchg(vha, rsp->qpair, entry)) {
+ ha->tgt.tgt_ops->free_mcmd(mcmd);
+ return;
+ }
+ qlt_24xx_retry_term_exchange(vha, rsp->qpair,
+ pkt, mcmd);
+ } else {
+ ql_dbg(ql_dbg_tgt, vha, 0xe063,
+ "qla_target(%d): ABTS_RESP_24XX failed %x (subcode %x:%x)",
+ vha->vp_idx, entry->compl_status,
+ entry->error_subcode1,
+ entry->error_subcode2);
+ ha->tgt.tgt_ops->free_mcmd(mcmd);
+ }
+ } else {
+ ha->tgt.tgt_ops->free_mcmd(mcmd);
+ }
+}
+
/* ha->hardware_lock supposed to be held on entry */
/* called via callback from qla2xxx */
static void qlt_response_pkt(struct scsi_qla_host *vha,
@@ -5740,41 +5991,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha,
case ABTS_RESP_24XX:
if (tgt->abts_resp_expected > 0) {
- struct abts_resp_from_24xx_fw *entry =
- (struct abts_resp_from_24xx_fw *)pkt;
- ql_dbg(ql_dbg_tgt, vha, 0xe038,
- "ABTS_RESP_24XX: compl_status %x\n",
- entry->compl_status);
- tgt->abts_resp_expected--;
- if (le16_to_cpu(entry->compl_status) !=
- ABTS_RESP_COMPL_SUCCESS) {
- if ((entry->error_subcode1 == 0x1E) &&
- (entry->error_subcode2 == 0)) {
- /*
- * We've got a race here: aborted
- * exchange not terminated, i.e.
- * response for the aborted command was
- * sent between the abort request was
- * received and processed.
- * Unfortunately, the firmware has a
- * silly requirement that all aborted
- * exchanges must be explicitely
- * terminated, otherwise it refuses to
- * send responses for the abort
- * requests. So, we have to
- * (re)terminate the exchange and retry
- * the abort response.
- */
- qlt_24xx_retry_term_exchange(vha,
- entry);
- } else
- ql_dbg(ql_dbg_tgt, vha, 0xe063,
- "qla_target(%d): ABTS_RESP_24XX "
- "failed %x (subcode %x:%x)",
- vha->vp_idx, entry->compl_status,
- entry->error_subcode1,
- entry->error_subcode2);
- }
+ qlt_handle_abts_completion(vha, rsp, pkt);
} else {
ql_dbg(ql_dbg_tgt, vha, 0xe064,
"qla_target(%d): Unexpected ABTS_RESP_24XX "
@@ -5964,10 +6181,7 @@ static fc_port_t *qlt_get_port_database(struct scsi_qla_host *vha,
case MODE_DUAL:
if (newfcport) {
if (!IS_IIDMA_CAPABLE(vha->hw) || !vha->hw->flags.gpsc_supported) {
- ql_dbg(ql_dbg_disc, vha, 0x20fe,
- "%s %d %8phC post upd_fcport fcp_cnt %d\n",
- __func__, __LINE__, fcport->port_name, vha->fcport_count);
- qla24xx_post_upd_fcport_work(vha, fcport);
+ qla24xx_sched_upd_fcport(fcport);
} else {
ql_dbg(ql_dbg_disc, vha, 0x20ff,
"%s %d %8phC post gpsc fcp_cnt %d\n",
@@ -6413,6 +6627,9 @@ int qlt_lport_register(void *target_lport_ptr, u64 phys_wwpn,
if (!(host->hostt->supported_mode & MODE_TARGET))
continue;
+ if (vha->qlini_mode == QLA2XXX_INI_MODE_ENABLED)
+ continue;
+
spin_lock_irqsave(&ha->hardware_lock, flags);
if ((!npiv_wwpn || !npiv_wwnn) && host->active_mode & MODE_TARGET) {
pr_debug("MODE_TARGET already active on qla2xxx(%d)\n",
@@ -6475,15 +6692,15 @@ void qlt_lport_deregister(struct scsi_qla_host *vha)
EXPORT_SYMBOL(qlt_lport_deregister);
/* Must be called under HW lock */
-static void qlt_set_mode(struct scsi_qla_host *vha)
+void qlt_set_mode(struct scsi_qla_host *vha)
{
- switch (ql2x_ini_mode) {
+ switch (vha->qlini_mode) {
case QLA2XXX_INI_MODE_DISABLED:
case QLA2XXX_INI_MODE_EXCLUSIVE:
vha->host->active_mode = MODE_TARGET;
break;
case QLA2XXX_INI_MODE_ENABLED:
- vha->host->active_mode = MODE_UNKNOWN;
+ vha->host->active_mode = MODE_INITIATOR;
break;
case QLA2XXX_INI_MODE_DUAL:
vha->host->active_mode = MODE_DUAL;
@@ -6496,7 +6713,7 @@ static void qlt_set_mode(struct scsi_qla_host *vha)
/* Must be called under HW lock */
static void qlt_clear_mode(struct scsi_qla_host *vha)
{
- switch (ql2x_ini_mode) {
+ switch (vha->qlini_mode) {
case QLA2XXX_INI_MODE_DISABLED:
vha->host->active_mode = MODE_UNKNOWN;
break;
@@ -6532,12 +6749,17 @@ qlt_enable_vha(struct scsi_qla_host *vha)
dump_stack();
return;
}
+ if (vha->qlini_mode == QLA2XXX_INI_MODE_ENABLED)
+ return;
spin_lock_irqsave(&ha->hardware_lock, flags);
tgt->tgt_stopped = 0;
qlt_set_mode(vha);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ mutex_lock(&ha->optrom_mutex);
+ ql_dbg(ql_dbg_tgt_mgt, vha, 0xf021,
+ "%s.\n", __func__);
if (vha->vp_idx) {
qla24xx_disable_vp(vha);
qla24xx_enable_vp(vha);
@@ -6546,6 +6768,7 @@ qlt_enable_vha(struct scsi_qla_host *vha)
qla2xxx_wake_dpc(base_vha);
qla2x00_wait_for_hba_online(base_vha);
}
+ mutex_unlock(&ha->optrom_mutex);
}
EXPORT_SYMBOL(qlt_enable_vha);
@@ -6767,7 +6990,7 @@ qlt_24xx_config_nvram_stage1(struct scsi_qla_host *vha, struct nvram_24xx *nv)
if (qla_tgt_mode_enabled(vha))
nv->exchange_count = cpu_to_le16(0xFFFF);
else /* dual */
- nv->exchange_count = cpu_to_le16(ql2xexchoffld);
+ nv->exchange_count = cpu_to_le16(vha->ql2xexchoffld);
/* Enable target mode */
nv->firmware_options_1 |= cpu_to_le32(BIT_4);
@@ -6846,14 +7069,6 @@ qlt_24xx_config_nvram_stage2(struct scsi_qla_host *vha,
memcpy(icb->node_name, ha->tgt.tgt_node_name, WWN_SIZE);
icb->firmware_options_1 |= cpu_to_le32(BIT_14);
}
-
- /* disable ZIO at start time. */
- if (!vha->flags.init_done) {
- uint32_t tmp;
- tmp = le32_to_cpu(icb->firmware_options_2);
- tmp &= ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
- icb->firmware_options_2 = cpu_to_le32(tmp);
- }
}
void
@@ -6881,7 +7096,7 @@ qlt_81xx_config_nvram_stage1(struct scsi_qla_host *vha, struct nvram_81xx *nv)
if (qla_tgt_mode_enabled(vha))
nv->exchange_count = cpu_to_le16(0xFFFF);
else /* dual */
- nv->exchange_count = cpu_to_le16(ql2xexchoffld);
+ nv->exchange_count = cpu_to_le16(vha->ql2xexchoffld);
/* Enable target mode */
nv->firmware_options_1 |= cpu_to_le32(BIT_4);
@@ -6957,15 +7172,6 @@ qlt_81xx_config_nvram_stage2(struct scsi_qla_host *vha,
memcpy(icb->node_name, ha->tgt.tgt_node_name, WWN_SIZE);
icb->firmware_options_1 |= cpu_to_le32(BIT_14);
}
-
- /* disable ZIO at start time. */
- if (!vha->flags.init_done) {
- uint32_t tmp;
- tmp = le32_to_cpu(icb->firmware_options_2);
- tmp &= ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
- icb->firmware_options_2 = cpu_to_le32(tmp);
- }
-
}
void