Commit 5ffc266e authored by James Smart's avatar James Smart Committed by James Bottomley

[SCSI] lpfc 8.3.6 : FC Protocol Fixes

FC protocol fixes.
 - Fix send sequence logic to handle multi SGL IOCBs.
 - Fix FDISC completion always setting VPORT state to failed.
 - Ported the fix on reporting of max_vpi to uppper layer.
 - Fix incorrect number of Vports allowed to be created.
 - Fixed Dead FCoE port after creating vports.
 - Added handling of ELS request for Reinstate Recovery Qualifier (RRQ)
 - Handle unsolicited CT exchange initiator receiving CT exchange ABTS
 - Migrate LUN queue depth ramp up code to scsi mid-layer.
 - Made ABTS WQE go to the same WQ as the WQE to be aborted.
 - Fix Vport does not rediscover after FCF goes away.
 - Fixed lpfc_unreg_vfi failure after devloss timeout.
 - Fixed RPI bit leak.
 - Fix hbq pointer corruption during target discovery.
Signed-off-by: default avatarJames Smart <james.smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent c868595d
......@@ -202,6 +202,7 @@ struct lpfc_stats {
uint32_t elsRcvLIRR;
uint32_t elsRcvRPS;
uint32_t elsRcvRPL;
uint32_t elsRcvRRQ;
uint32_t elsXmitFLOGI;
uint32_t elsXmitFDISC;
uint32_t elsXmitPLOGI;
......
......@@ -105,8 +105,6 @@ struct lpfc_nodelist {
struct lpfc_vport *vport;
struct lpfc_work_evt els_retry_evt;
struct lpfc_work_evt dev_loss_evt;
unsigned long last_ramp_up_time; /* jiffy of last ramp up */
unsigned long last_q_full_time; /* jiffy of last queue full */
struct kref kref;
atomic_t cmd_pending;
uint32_t cmd_qdepth;
......
......@@ -4520,6 +4520,29 @@ lpfc_els_rcv_lirr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
return 0;
}
/**
* lpfc_els_rcv_rrq - Process an unsolicited rrq iocb
* @vport: pointer to a host virtual N_Port data structure.
* @cmdiocb: pointer to lpfc command iocb data structure.
* @ndlp: pointer to a node-list data structure.
*
* This routine processes a Reinstate Recovery Qualifier (RRQ) IOCB
* received as an ELS unsolicited event. A request to RRQ shall only
* be accepted if the Originator Nx_Port N_Port_ID or the Responder
* Nx_Port N_Port_ID of the target Exchange is the same as the
* N_Port_ID of the Nx_Port that makes the request. If the RRQ is
* not accepted, an LS_RJT with reason code "Unable to perform
* command request" and reason code explanation "Invalid Originator
* S_ID" shall be returned. For now, we just unconditionally accept
* RRQ from the target.
**/
static void
lpfc_els_rcv_rrq(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
struct lpfc_nodelist *ndlp)
{
lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
}
/**
* lpfc_els_rsp_rps_acc - Completion callbk func for MBX_READ_LNK_STAT mbox cmd
* @phba: pointer to lpfc hba data structure.
......@@ -5636,6 +5659,16 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
if (newnode)
lpfc_nlp_put(ndlp);
break;
case ELS_CMD_RRQ:
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
"RCV RRQ: did:x%x/ste:x%x flg:x%x",
did, vport->port_state, ndlp->nlp_flag);
phba->fc_stat.elsRcvRRQ++;
lpfc_els_rcv_rrq(vport, elsiocb, ndlp);
if (newnode)
lpfc_nlp_put(ndlp);
break;
default:
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
"RCV ELS cmd: cmd:x%x did:x%x/ste:x%x",
......@@ -6042,11 +6075,6 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
irsp->ulpStatus, irsp->un.ulpWord[4]);
goto fdisc_failed;
}
if (vport->fc_vport->vport_state == FC_VPORT_INITIALIZING)
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
lpfc_nlp_put(ndlp);
/* giving up on FDISC. Cancel discovery timer */
lpfc_can_disctmo(vport);
spin_lock_irq(shost->host_lock);
vport->fc_flag |= FC_FABRIC;
if (vport->phba->fc_topology == TOPOLOGY_LOOP)
......@@ -6125,6 +6153,7 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
int did = ndlp->nlp_DID;
int rc;
vport->port_state = LPFC_FDISC;
cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did,
ELS_CMD_FDISC);
......@@ -6190,7 +6219,6 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
return 1;
}
lpfc_vport_set_state(vport, FC_VPORT_INITIALIZING);
vport->port_state = LPFC_FDISC;
return 0;
}
......
......@@ -3538,7 +3538,7 @@ typedef struct _IOCB { /* IOCB structure */
ASYNCSTAT_FIELDS asyncstat; /* async_status iocb */
QUE_XRI64_CX_FIELDS quexri64cx; /* que_xri64_cx fields */
struct rcv_seq64 rcvseq64; /* RCV_SEQ64 and RCV_CONT64 */
struct sli4_bls_acc bls_acc; /* UNSOL ABTS BLS_ACC params */
uint32_t ulpWord[IOCB_WORD_SZ - 2]; /* generic 6 'words' */
} un;
union {
......
......@@ -194,6 +194,26 @@ struct lpfc_sli4_flags {
#define lpfc_fip_flag_WORD word0
};
struct sli4_bls_acc {
uint32_t word0_rsvd; /* Word0 must be reserved */
uint32_t word1;
#define lpfc_abts_orig_SHIFT 0
#define lpfc_abts_orig_MASK 0x00000001
#define lpfc_abts_orig_WORD word1
#define LPFC_ABTS_UNSOL_RSP 1
#define LPFC_ABTS_UNSOL_INT 0
uint32_t word2;
#define lpfc_abts_rxid_SHIFT 0
#define lpfc_abts_rxid_MASK 0x0000FFFF
#define lpfc_abts_rxid_WORD word2
#define lpfc_abts_oxid_SHIFT 16
#define lpfc_abts_oxid_MASK 0x0000FFFF
#define lpfc_abts_oxid_WORD word2
uint32_t word3;
uint32_t word4;
uint32_t word5_rsvd; /* Word5 must be reserved */
};
/* event queue entry structure */
struct lpfc_eqe {
uint32_t word0;
......@@ -1980,7 +2000,8 @@ struct lpfc_bmbx_create {
#define SGL_ALIGN_SZ 64
#define SGL_PAGE_SIZE 4096
/* align SGL addr on a size boundary - adjust address up */
#define NO_XRI ((uint16_t)-1)
#define NO_XRI ((uint16_t)-1)
struct wqe_common {
uint32_t word6;
#define wqe_xri_tag_SHIFT 0
......
......@@ -4931,7 +4931,8 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
phba->vpi_base = phba->sli4_hba.max_cfg_param.vpi_base;
phba->vfi_base = phba->sli4_hba.max_cfg_param.vfi_base;
phba->sli4_hba.next_rpi = phba->sli4_hba.max_cfg_param.rpi_base;
phba->max_vpi = phba->sli4_hba.max_cfg_param.max_vpi;
phba->max_vpi = (phba->sli4_hba.max_cfg_param.max_vpi > 0) ?
(phba->sli4_hba.max_cfg_param.max_vpi - 1) : 0;
phba->max_vports = phba->max_vpi;
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
"2003 cfg params XRI(B:%d M:%d), "
......
......@@ -1223,6 +1223,12 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport,
list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) &&
(ndlp == (struct lpfc_nodelist *) mb->context2)) {
if (phba->sli_rev == LPFC_SLI_REV4) {
spin_unlock_irq(&phba->hbalock);
lpfc_sli4_free_rpi(phba,
mb->u.mb.un.varRegLogin.rpi);
spin_lock_irq(&phba->hbalock);
}
mp = (struct lpfc_dmabuf *) (mb->context1);
if (mp) {
__lpfc_mbuf_free(phba, mp->virt, mp->phys);
......@@ -1230,6 +1236,7 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport,
}
lpfc_nlp_put(ndlp);
list_del(&mb->list);
phba->sli.mboxq_cnt--;
mempool_free(mb, phba->mbox_mem_pool);
}
}
......
......@@ -245,6 +245,36 @@ lpfc_send_sdev_queuedepth_change_event(struct lpfc_hba *phba,
return;
}
/**
* lpfc_change_queue_depth - Alter scsi device queue depth
* @sdev: Pointer the scsi device on which to change the queue depth.
* @qdepth: New queue depth to set the sdev to.
* @reason: The reason for the queue depth change.
*
* This function is called by the midlayer and the LLD to alter the queue
* depth for a scsi device. This function sets the queue depth to the new
* value and sends an event out to log the queue depth change.
**/
int
lpfc_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
{
struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata;
struct lpfc_hba *phba = vport->phba;
struct lpfc_rport_data *rdata;
unsigned long new_queue_depth, old_queue_depth;
old_queue_depth = sdev->queue_depth;
scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
new_queue_depth = sdev->queue_depth;
rdata = sdev->hostdata;
if (rdata)
lpfc_send_sdev_queuedepth_change_event(phba, vport,
rdata->pnode, sdev->lun,
old_queue_depth,
new_queue_depth);
return sdev->queue_depth;
}
/**
* lpfc_rampdown_queue_depth - Post RAMP_DOWN_QUEUE event to worker thread
* @phba: The Hba for which this call is being executed.
......@@ -309,8 +339,10 @@ lpfc_rampup_queue_depth(struct lpfc_vport *vport,
if (vport->cfg_lun_queue_depth <= queue_depth)
return;
spin_lock_irqsave(&phba->hbalock, flags);
if (((phba->last_ramp_up_time + QUEUE_RAMP_UP_INTERVAL) > jiffies) ||
((phba->last_rsrc_error_time + QUEUE_RAMP_UP_INTERVAL ) > jiffies)) {
if (time_before(jiffies,
phba->last_ramp_up_time + QUEUE_RAMP_UP_INTERVAL) ||
time_before(jiffies,
phba->last_rsrc_error_time + QUEUE_RAMP_UP_INTERVAL)) {
spin_unlock_irqrestore(&phba->hbalock, flags);
return;
}
......@@ -342,10 +374,9 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba)
struct lpfc_vport **vports;
struct Scsi_Host *shost;
struct scsi_device *sdev;
unsigned long new_queue_depth, old_queue_depth;
unsigned long new_queue_depth;
unsigned long num_rsrc_err, num_cmd_success;
int i;
struct lpfc_rport_data *rdata;
num_rsrc_err = atomic_read(&phba->num_rsrc_err);
num_cmd_success = atomic_read(&phba->num_cmd_success);
......@@ -363,22 +394,8 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba)
else
new_queue_depth = sdev->queue_depth -
new_queue_depth;
old_queue_depth = sdev->queue_depth;
if (sdev->ordered_tags)
scsi_adjust_queue_depth(sdev,
MSG_ORDERED_TAG,
new_queue_depth);
else
scsi_adjust_queue_depth(sdev,
MSG_SIMPLE_TAG,
new_queue_depth);
rdata = sdev->hostdata;
if (rdata)
lpfc_send_sdev_queuedepth_change_event(
phba, vports[i],
rdata->pnode,
sdev->lun, old_queue_depth,
new_queue_depth);
lpfc_change_queue_depth(sdev, new_queue_depth,
SCSI_QDEPTH_DEFAULT);
}
}
lpfc_destroy_vport_work_array(phba, vports);
......@@ -402,7 +419,6 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba)
struct Scsi_Host *shost;
struct scsi_device *sdev;
int i;
struct lpfc_rport_data *rdata;
vports = lpfc_create_vport_work_array(phba);
if (vports != NULL)
......@@ -412,22 +428,9 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba)
if (vports[i]->cfg_lun_queue_depth <=
sdev->queue_depth)
continue;
if (sdev->ordered_tags)
scsi_adjust_queue_depth(sdev,
MSG_ORDERED_TAG,
sdev->queue_depth+1);
else
scsi_adjust_queue_depth(sdev,
MSG_SIMPLE_TAG,
sdev->queue_depth+1);
rdata = sdev->hostdata;
if (rdata)
lpfc_send_sdev_queuedepth_change_event(
phba, vports[i],
rdata->pnode,
sdev->lun,
sdev->queue_depth - 1,
sdev->queue_depth);
lpfc_change_queue_depth(sdev,
sdev->queue_depth+1,
SCSI_QDEPTH_RAMP_UP);
}
}
lpfc_destroy_vport_work_array(phba, vports);
......@@ -2208,7 +2211,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
struct scsi_cmnd *cmd = lpfc_cmd->pCmd;
int result;
struct scsi_device *tmp_sdev;
int depth = 0;
int depth;
unsigned long flags;
struct lpfc_fast_path_event *fast_path_evt;
struct Scsi_Host *shost = cmd->device->host;
......@@ -2375,67 +2378,29 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
return;
}
if (!result)
lpfc_rampup_queue_depth(vport, queue_depth);
if (!result && pnode && NLP_CHK_NODE_ACT(pnode) &&
((jiffies - pnode->last_ramp_up_time) >
LPFC_Q_RAMP_UP_INTERVAL * HZ) &&
((jiffies - pnode->last_q_full_time) >
LPFC_Q_RAMP_UP_INTERVAL * HZ) &&
(vport->cfg_lun_queue_depth > queue_depth)) {
shost_for_each_device(tmp_sdev, shost) {
if (vport->cfg_lun_queue_depth > tmp_sdev->queue_depth){
if (tmp_sdev->id != scsi_id)
continue;
if (tmp_sdev->ordered_tags)
scsi_adjust_queue_depth(tmp_sdev,
MSG_ORDERED_TAG,
tmp_sdev->queue_depth+1);
else
scsi_adjust_queue_depth(tmp_sdev,
MSG_SIMPLE_TAG,
tmp_sdev->queue_depth+1);
pnode->last_ramp_up_time = jiffies;
}
}
lpfc_send_sdev_queuedepth_change_event(phba, vport, pnode,
0xFFFFFFFF,
queue_depth , queue_depth + 1);
}
/*
* Check for queue full. If the lun is reporting queue full, then
* back off the lun queue depth to prevent target overloads.
*/
if (result == SAM_STAT_TASK_SET_FULL && pnode &&
NLP_CHK_NODE_ACT(pnode)) {
pnode->last_q_full_time = jiffies;
shost_for_each_device(tmp_sdev, shost) {
if (tmp_sdev->id != scsi_id)
continue;
depth = scsi_track_queue_full(tmp_sdev,
tmp_sdev->queue_depth - 1);
}
/*
* The queue depth cannot be lowered any more.
* Modify the returned error code to store
* the final depth value set by
* scsi_track_queue_full.
*/
if (depth == -1)
depth = shost->cmd_per_lun;
if (depth) {
tmp_sdev->queue_depth-1);
if (depth <= 0)
continue;
lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
"0711 detected queue full - lun queue "
"depth adjusted to %d.\n", depth);
lpfc_send_sdev_queuedepth_change_event(phba, vport,
pnode, 0xFFFFFFFF,
depth+1, depth);
pnode,
tmp_sdev->lun,
depth+1, depth);
}
}
......@@ -3019,6 +2984,10 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
icmd->ulpLe = 1;
icmd->ulpClass = cmd->ulpClass;
/* ABTS WQE must go to the same WQ as the WQE to be aborted */
abtsiocb->fcp_wqidx = iocb->fcp_wqidx;
if (lpfc_is_link_up(phba))
icmd->ulpCommand = CMD_ABORT_XRI_CN;
else
......@@ -3596,6 +3565,7 @@ struct scsi_host_template lpfc_template = {
.shost_attrs = lpfc_hba_attrs,
.max_sectors = 0xFFFF,
.vendor_id = LPFC_NL_VENDOR_ID,
.change_queue_depth = lpfc_change_queue_depth,
};
struct scsi_host_template lpfc_vport_template = {
......@@ -3617,4 +3587,5 @@ struct scsi_host_template lpfc_vport_template = {
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = lpfc_vport_attrs,
.max_sectors = 0xFFFF,
.change_queue_depth = lpfc_change_queue_depth,
};
......@@ -5748,7 +5748,7 @@ static int
lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
union lpfc_wqe *wqe)
{
uint32_t payload_len = 0;
uint32_t xmit_len = 0, total_len = 0;
uint8_t ct = 0;
uint32_t fip;
uint32_t abort_tag;
......@@ -5757,6 +5757,8 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
uint16_t xritag;
struct ulp_bde64 *bpl = NULL;
uint32_t els_id = ELS_ID_DEFAULT;
int numBdes, i;
struct ulp_bde64 bde;
fip = phba->hba_flag & HBA_FIP_SUPPORT;
/* The fcp commands will set command type */
......@@ -5774,6 +5776,8 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
wqe->words[7] = 0; /* The ct field has moved so reset */
/* words0-2 bpl convert bde */
if (iocbq->iocb.un.genreq64.bdl.bdeFlags == BUFF_TYPE_BLP_64) {
numBdes = iocbq->iocb.un.genreq64.bdl.bdeSize /
sizeof(struct ulp_bde64);
bpl = (struct ulp_bde64 *)
((struct lpfc_dmabuf *)iocbq->context3)->virt;
if (!bpl)
......@@ -5786,9 +5790,14 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
* can assign it to the sgl.
*/
wqe->generic.bde.tus.w = le32_to_cpu(bpl->tus.w);
payload_len = wqe->generic.bde.tus.f.bdeSize;
xmit_len = wqe->generic.bde.tus.f.bdeSize;
total_len = 0;
for (i = 0; i < numBdes; i++) {
bde.tus.w = le32_to_cpu(bpl[i].tus.w);
total_len += bde.tus.f.bdeSize;
}
} else
payload_len = iocbq->iocb.un.fcpi64.bdl.bdeSize;
xmit_len = iocbq->iocb.un.fcpi64.bdl.bdeSize;
iocbq->iocb.ulpIoTag = iocbq->iotag;
cmnd = iocbq->iocb.ulpCommand;
......@@ -5802,7 +5811,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
iocbq->iocb.ulpCommand);
return IOCB_ERROR;
}
wqe->els_req.payload_len = payload_len;
wqe->els_req.payload_len = xmit_len;
/* Els_reguest64 has a TMO */
bf_set(wqe_tmo, &wqe->els_req.wqe_com,
iocbq->iocb.ulpTimeout);
......@@ -5831,6 +5840,15 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
bf_set(lpfc_wqe_gen_els_id, &wqe->generic, els_id);
break;
case CMD_XMIT_SEQUENCE64_CX:
bf_set(lpfc_wqe_gen_context, &wqe->generic,
iocbq->iocb.un.ulpWord[3]);
wqe->generic.word3 = 0;
bf_set(wqe_rcvoxid, &wqe->generic, iocbq->iocb.ulpContext);
bf_set(wqe_xc, &wqe->generic, 1);
/* The entire sequence is transmitted for this IOCB */
xmit_len = total_len;
cmnd = CMD_XMIT_SEQUENCE64_CR;
case CMD_XMIT_SEQUENCE64_CR:
/* word3 iocb=io_tag32 wqe=payload_offset */
/* payload offset used for multilpe outstanding
......@@ -5840,7 +5858,8 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
/* word4 relative_offset memcpy */
/* word5 r_ctl/df_ctl memcpy */
bf_set(lpfc_wqe_gen_pu, &wqe->generic, 0);
wqe->xmit_sequence.xmit_len = payload_len;
wqe->xmit_sequence.xmit_len = xmit_len;
command_type = OTHER_COMMAND;
break;
case CMD_XMIT_BCAST64_CN:
/* word3 iocb=iotag32 wqe=payload_len */
......@@ -5869,7 +5888,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
case CMD_FCP_IREAD64_CR:
/* FCP_CMD is always the 1st sgl entry */
wqe->fcp_iread.payload_len =
payload_len + sizeof(struct fcp_rsp);
xmit_len + sizeof(struct fcp_rsp);
/* word 4 (xfer length) should have been set on the memcpy */
......@@ -5906,7 +5925,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
* sgl[1] = rsp.
*
*/
wqe->gen_req.command_len = payload_len;
wqe->gen_req.command_len = xmit_len;
/* Word4 parameter copied in the memcpy */
/* Word5 [rctl, type, df_ctl, la] copied in memcpy */
/* word6 context tag copied in memcpy */
......@@ -5979,10 +5998,25 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
* iocbq from scratch.
*/
memset(wqe, 0, sizeof(union lpfc_wqe));
/* OX_ID is invariable to who sent ABTS to CT exchange */
bf_set(xmit_bls_rsp64_oxid, &wqe->xmit_bls_rsp,
iocbq->iocb.un.ulpWord[3]);
bf_set(xmit_bls_rsp64_rxid, &wqe->xmit_bls_rsp,
iocbq->sli4_xritag);
bf_get(lpfc_abts_oxid, &iocbq->iocb.un.bls_acc));
if (bf_get(lpfc_abts_orig, &iocbq->iocb.un.bls_acc) ==
LPFC_ABTS_UNSOL_INT) {
/* ABTS sent by initiator to CT exchange, the
* RX_ID field will be filled with the newly
* allocated responder XRI.
*/
bf_set(xmit_bls_rsp64_rxid, &wqe->xmit_bls_rsp,
iocbq->sli4_xritag);
} else {
/* ABTS sent by responder to CT exchange, the
* RX_ID field will be filled with the responder
* RX_ID from ABTS.
*/
bf_set(xmit_bls_rsp64_rxid, &wqe->xmit_bls_rsp,
bf_get(lpfc_abts_rxid, &iocbq->iocb.un.bls_acc));
}
bf_set(xmit_bls_rsp64_seqcnthi, &wqe->xmit_bls_rsp, 0xffff);
bf_set(wqe_xmit_bls_pt, &wqe->xmit_bls_rsp.wqe_dest, 0x1);
bf_set(wqe_ctxt_tag, &wqe->xmit_bls_rsp.wqe_com,
......@@ -6044,7 +6078,6 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
uint16_t xritag;
union lpfc_wqe wqe;
struct lpfc_sli_ring *pring = &phba->sli.ring[ring_number];
uint32_t fcp_wqidx;
if (piocb->sli4_xritag == NO_XRI) {
if (piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN ||
......@@ -6079,8 +6112,17 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
return IOCB_ERROR;
if (piocb->iocb_flag & LPFC_IO_FCP) {
fcp_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba);
if (lpfc_sli4_wq_put(phba->sli4_hba.fcp_wq[fcp_wqidx], &wqe))
/*
* For FCP command IOCB, get a new WQ index to distribute
* WQE across the WQsr. On the other hand, for abort IOCB,
* it carries the same WQ index to the original command
* IOCB.
*/
if ((piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) &&
(piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN))
piocb->fcp_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba);
if (lpfc_sli4_wq_put(phba->sli4_hba.fcp_wq[piocb->fcp_wqidx],
&wqe))
return IOCB_ERROR;
} else {
if (lpfc_sli4_wq_put(phba->sli4_hba.els_wq, &wqe))
......@@ -7070,6 +7112,9 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
iabt->ulpLe = 1;
iabt->ulpClass = icmd->ulpClass;
/* ABTS WQE must go to the same WQ as the WQE to be aborted */
abtsiocbp->fcp_wqidx = cmdiocb->fcp_wqidx;
if (phba->link_state >= LPFC_LINK_UP)
iabt->ulpCommand = CMD_ABORT_XRI_CN;
else
......@@ -7273,6 +7318,9 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring,
abtsiocb->iocb.ulpClass = cmd->ulpClass;
abtsiocb->vport = phba->pport;
/* ABTS WQE must go to the same WQ as the WQE to be aborted */
abtsiocb->fcp_wqidx = iocbq->fcp_wqidx;
if (lpfc_is_link_up(phba))
abtsiocb->iocb.ulpCommand = CMD_ABORT_XRI_CN;
else
......@@ -8671,7 +8719,6 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe)
uint32_t status;
unsigned long iflags;
lpfc_sli4_rq_release(hrq, drq);
if (bf_get(lpfc_rcqe_rq_id, rcqe) != hrq->queue_id)
goto out;
......@@ -8681,6 +8728,7 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe)
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"2537 Receive Frame Truncated!!\n");
case FC_STATUS_RQ_SUCCESS:
lpfc_sli4_rq_release(hrq, drq);
spin_lock_irqsave(&phba->hbalock, iflags);
dma_buf = lpfc_sli_hbqbuf_get(&phba->hbqs[0].hbq_buffer_list);
if (!dma_buf) {
......@@ -10997,8 +11045,8 @@ lpfc_sli4_seq_abort_acc(struct lpfc_hba *phba,
{
struct lpfc_iocbq *ctiocb = NULL;
struct lpfc_nodelist *ndlp;
uint16_t oxid;
uint32_t sid;
uint16_t oxid, rxid;
uint32_t sid, fctl;
IOCB_t *icmd;
if (!lpfc_is_link_up(phba))
......@@ -11006,6 +11054,7 @@ lpfc_sli4_seq_abort_acc(struct lpfc_hba *phba,
sid = sli4_sid_from_fc_hdr(fc_hdr);
oxid = be16_to_cpu(fc_hdr->fh_ox_id);
rxid = be16_to_cpu(fc_hdr->fh_rx_id);
ndlp = lpfc_findnode_did(phba->pport, sid);
if (!ndlp) {
......@@ -11020,9 +11069,12 @@ lpfc_sli4_seq_abort_acc(struct lpfc_hba *phba,
if (!ctiocb)
return;
/* Extract the F_CTL field from FC_HDR */
fctl = sli4_fctl_from_fc_hdr(fc_hdr);
icmd = &ctiocb->iocb;
icmd->un.xseq64.bdl.ulpIoTag32 = 0;
icmd->un.xseq64.bdl.bdeSize = 0;
icmd->un.xseq64.bdl.ulpIoTag32 = 0;
icmd->un.xseq64.w5.hcsw.Dfctl = 0;
icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_BA_ACC;
icmd->un.xseq64.w5.hcsw.Type = FC_TYPE_BLS;
......@@ -11033,13 +11085,30 @@ lpfc_sli4_seq_abort_acc(struct lpfc_hba *phba,
icmd->ulpLe = 1;
icmd->ulpClass = CLASS3;
icmd->ulpContext = ndlp->nlp_rpi;
icmd->un.ulpWord[3] = oxid;
ctiocb->sli4_xritag = NO_XRI;
ctiocb->iocb_cmpl = NULL;
ctiocb->vport = phba->pport;
ctiocb->iocb_cmpl = lpfc_sli4_seq_abort_acc_cmpl;
if (fctl & FC_FC_EX_CTX) {
/* ABTS sent by responder to CT exchange, construction
* of BA_ACC will use OX_ID from ABTS for the XRI_TAG
* field and RX_ID from ABTS for RX_ID field.
*/
bf_set(lpfc_abts_orig, &icmd->un.bls_acc, LPFC_ABTS_UNSOL_RSP);
bf_set(lpfc_abts_rxid, &icmd->un.bls_acc, rxid);
ctiocb->sli4_xritag = oxid;
} else {
/* ABTS sent by initiator to CT exchange, construction
* of BA_ACC will need to allocate a new XRI as for the
* XRI_TAG and RX_ID fields.
*/
bf_set(lpfc_abts_orig, &icmd->un.bls_acc, LPFC_ABTS_UNSOL_INT);
bf_set(lpfc_abts_rxid, &icmd->un.bls_acc, NO_XRI);
ctiocb->sli4_xritag = NO_XRI;
}
bf_set(lpfc_abts_oxid, &icmd->un.bls_acc, oxid);
/* Xmit CT abts accept on exchange <xid> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
"1200 Xmit CT ABTS ACC on exchange x%x Data: x%x\n",
......@@ -11066,19 +11135,31 @@ lpfc_sli4_handle_unsol_abort(struct lpfc_vport *vport,
{
struct lpfc_hba *phba = vport->phba;
struct fc_frame_header fc_hdr;
uint32_t fctl;
bool abts_par;
/* Try to abort partially assembled seq */
abts_par = lpfc_sli4_abort_partial_seq(vport, dmabuf);
/* Make a copy of fc_hdr before the dmabuf being released */
memcpy(&fc_hdr, dmabuf->hbuf.virt, sizeof(struct fc_frame_header));
fctl = sli4_fctl_from_fc_hdr(&fc_hdr);
/* Send abort to ULP if partially seq abort failed */
if (abts_par == false)
lpfc_sli4_send_seq_to_ulp(vport, dmabuf);
else
if (fctl & FC_FC_EX_CTX) {
/*
* ABTS sent by responder to exchange, just free the buffer
*/
lpfc_in_buf_free(phba, &dmabuf->dbuf);
} else {
/*
* ABTS sent by initiator to exchange, need to do cleanup
*/
/* Try to abort partially assembled seq */
abts_par = lpfc_sli4_abort_partial_seq(vport, dmabuf);
/* Send abort to ULP if partially seq abort failed */
if (abts_par == false)
lpfc_sli4_send_seq_to_ulp(vport, dmabuf);
else
lpfc_in_buf_free(phba, &dmabuf->dbuf);
}
/* Send basic accept (BA_ACC) to the abort requester */
lpfc_sli4_seq_abort_acc(phba, &fc_hdr);
}
......
......@@ -66,6 +66,7 @@ struct lpfc_iocbq {
uint8_t abort_count;
uint8_t rsvd2;
uint32_t drvrTimeout; /* driver timeout in seconds */
uint32_t fcp_wqidx; /* index to FCP work queue */
struct lpfc_vport *vport;/* virtual port pointer */
void *context1; /* caller context information */
void *context2; /* caller context information */
......
......@@ -63,6 +63,11 @@
(fc_hdr)->fh_s_id[1] << 8 | \
(fc_hdr)->fh_s_id[2])
#define sli4_fctl_from_fc_hdr(fc_hdr) \
((fc_hdr)->fh_f_ctl[0] << 16 | \
(fc_hdr)->fh_f_ctl[1] << 8 | \
(fc_hdr)->fh_f_ctl[2])
enum lpfc_sli4_queue_type {
LPFC_EQ,
LPFC_GCQ,
......
......@@ -700,6 +700,8 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
}
spin_unlock_irq(&phba->ndlp_lock);
}
if (vport->vpi_state != LPFC_VPI_REGISTERED)
goto skip_logo;
vport->unreg_vpi_cmpl = VPORT_INVAL;
timeout = msecs_to_jiffies(phba->fc_ratov * 2000);
if (!lpfc_issue_els_npiv_logo(vport, ndlp))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment