Skip to content

Commit a35b29b

Browse files
Karan Tilak Kumarmartinkpetersen
authored andcommitted
scsi: fnic: Fix crash in fnic_wq_cmpl_handler when FDMI times out
When both the RHBA and RPA FDMI requests time out, fnic reuses a frame to send ABTS for each of them. On send completion, this causes an attempt to free the same frame twice that leads to a crash. Fix crash by allocating separate frames for RHBA and RPA, and modify ABTS logic accordingly. Tested by checking MDS for FDMI information. Tested by using instrumented driver to: - Drop PLOGI response - Drop RHBA response - Drop RPA response - Drop RHBA and RPA response - Drop PLOGI response + ABTS response - Drop RHBA response + ABTS response - Drop RPA response + ABTS response - Drop RHBA and RPA response + ABTS response for both of them Fixes: 09c1e6a ("scsi: fnic: Add and integrate support for FDMI") Reviewed-by: Sesidhar Baddela <[email protected]> Reviewed-by: Arulprabhu Ponnusamy <[email protected]> Reviewed-by: Gian Carlo Boffa <[email protected]> Tested-by: Arun Easi <[email protected]> Co-developed-by: Arun Easi <[email protected]> Signed-off-by: Arun Easi <[email protected]> Tested-by: Karan Tilak Kumar <[email protected]> Cc: [email protected] Signed-off-by: Karan Tilak Kumar <[email protected]> Link: https://lore.kernel.org/r/[email protected] Reviewed-by: John Meneghini <[email protected]> Signed-off-by: Martin K. Petersen <[email protected]>
1 parent 2e083cd commit a35b29b

File tree

3 files changed

+87
-29
lines changed

3 files changed

+87
-29
lines changed

drivers/scsi/fnic/fdls_disc.c

Lines changed: 85 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -763,47 +763,69 @@ static void fdls_send_fabric_abts(struct fnic_iport_s *iport)
763763
iport->fabric.timer_pending = 1;
764764
}
765765

766-
static void fdls_send_fdmi_abts(struct fnic_iport_s *iport)
766+
static uint8_t *fdls_alloc_init_fdmi_abts_frame(struct fnic_iport_s *iport,
767+
uint16_t oxid)
767768
{
768-
uint8_t *frame;
769+
struct fc_frame_header *pfdmi_abts;
769770
uint8_t d_id[3];
771+
uint8_t *frame;
770772
struct fnic *fnic = iport->fnic;
771-
struct fc_frame_header *pfabric_abts;
772-
unsigned long fdmi_tov;
773-
uint16_t oxid;
774-
uint16_t frame_size = FNIC_ETH_FCOE_HDRS_OFFSET +
775-
sizeof(struct fc_frame_header);
776773

777774
frame = fdls_alloc_frame(iport);
778775
if (frame == NULL) {
779776
FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
780777
"Failed to allocate frame to send FDMI ABTS");
781-
return;
778+
return NULL;
782779
}
783780

784-
pfabric_abts = (struct fc_frame_header *) (frame + FNIC_ETH_FCOE_HDRS_OFFSET);
781+
pfdmi_abts = (struct fc_frame_header *) (frame + FNIC_ETH_FCOE_HDRS_OFFSET);
785782
fdls_init_fabric_abts_frame(frame, iport);
786783

787784
hton24(d_id, FC_FID_MGMT_SERV);
788-
FNIC_STD_SET_D_ID(*pfabric_abts, d_id);
785+
FNIC_STD_SET_D_ID(*pfdmi_abts, d_id);
786+
FNIC_STD_SET_OX_ID(*pfdmi_abts, oxid);
787+
788+
return frame;
789+
}
790+
791+
static void fdls_send_fdmi_abts(struct fnic_iport_s *iport)
792+
{
793+
uint8_t *frame;
794+
unsigned long fdmi_tov;
795+
uint16_t frame_size = FNIC_ETH_FCOE_HDRS_OFFSET +
796+
sizeof(struct fc_frame_header);
789797

790798
if (iport->fabric.fdmi_pending & FDLS_FDMI_PLOGI_PENDING) {
791-
oxid = iport->active_oxid_fdmi_plogi;
792-
FNIC_STD_SET_OX_ID(*pfabric_abts, oxid);
799+
frame = fdls_alloc_init_fdmi_abts_frame(iport,
800+
iport->active_oxid_fdmi_plogi);
801+
if (frame == NULL)
802+
return;
803+
793804
fnic_send_fcoe_frame(iport, frame, frame_size);
794805
} else {
795806
if (iport->fabric.fdmi_pending & FDLS_FDMI_REG_HBA_PENDING) {
796-
oxid = iport->active_oxid_fdmi_rhba;
797-
FNIC_STD_SET_OX_ID(*pfabric_abts, oxid);
807+
frame = fdls_alloc_init_fdmi_abts_frame(iport,
808+
iport->active_oxid_fdmi_rhba);
809+
if (frame == NULL)
810+
return;
811+
798812
fnic_send_fcoe_frame(iport, frame, frame_size);
799813
}
800814
if (iport->fabric.fdmi_pending & FDLS_FDMI_RPA_PENDING) {
801-
oxid = iport->active_oxid_fdmi_rpa;
802-
FNIC_STD_SET_OX_ID(*pfabric_abts, oxid);
815+
frame = fdls_alloc_init_fdmi_abts_frame(iport,
816+
iport->active_oxid_fdmi_rpa);
817+
if (frame == NULL) {
818+
if (iport->fabric.fdmi_pending & FDLS_FDMI_REG_HBA_PENDING)
819+
goto arm_timer;
820+
else
821+
return;
822+
}
823+
803824
fnic_send_fcoe_frame(iport, frame, frame_size);
804825
}
805826
}
806827

828+
arm_timer:
807829
fdmi_tov = jiffies + msecs_to_jiffies(2 * iport->e_d_tov);
808830
mod_timer(&iport->fabric.fdmi_timer, round_jiffies(fdmi_tov));
809831
iport->fabric.fdmi_pending |= FDLS_FDMI_ABORT_PENDING;
@@ -2245,6 +2267,21 @@ void fdls_fabric_timer_callback(struct timer_list *t)
22452267
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
22462268
}
22472269

2270+
void fdls_fdmi_retry_plogi(struct fnic_iport_s *iport)
2271+
{
2272+
struct fnic *fnic = iport->fnic;
2273+
2274+
iport->fabric.fdmi_pending = 0;
2275+
/* If max retries not exhausted, start over from fdmi plogi */
2276+
if (iport->fabric.fdmi_retry < FDLS_FDMI_MAX_RETRY) {
2277+
iport->fabric.fdmi_retry++;
2278+
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
2279+
"Retry FDMI PLOGI. FDMI retry: %d",
2280+
iport->fabric.fdmi_retry);
2281+
fdls_send_fdmi_plogi(iport);
2282+
}
2283+
}
2284+
22482285
void fdls_fdmi_timer_callback(struct timer_list *t)
22492286
{
22502287
struct fnic_fdls_fabric_s *fabric = timer_container_of(fabric, t,
@@ -2291,14 +2328,7 @@ void fdls_fdmi_timer_callback(struct timer_list *t)
22912328
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
22922329
"fdmi timer callback : 0x%x\n", iport->fabric.fdmi_pending);
22932330

2294-
iport->fabric.fdmi_pending = 0;
2295-
/* If max retries not exhaused, start over from fdmi plogi */
2296-
if (iport->fabric.fdmi_retry < FDLS_FDMI_MAX_RETRY) {
2297-
iport->fabric.fdmi_retry++;
2298-
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
2299-
"retry fdmi timer %d", iport->fabric.fdmi_retry);
2300-
fdls_send_fdmi_plogi(iport);
2301-
}
2331+
fdls_fdmi_retry_plogi(iport);
23022332
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
23032333
"fdmi timer callback : 0x%x\n", iport->fabric.fdmi_pending);
23042334
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
@@ -3716,11 +3746,32 @@ static void fdls_process_fdmi_abts_rsp(struct fnic_iport_s *iport,
37163746
switch (FNIC_FRAME_TYPE(oxid)) {
37173747
case FNIC_FRAME_TYPE_FDMI_PLOGI:
37183748
fdls_free_oxid(iport, oxid, &iport->active_oxid_fdmi_plogi);
3749+
3750+
iport->fabric.fdmi_pending &= ~FDLS_FDMI_PLOGI_PENDING;
3751+
iport->fabric.fdmi_pending &= ~FDLS_FDMI_ABORT_PENDING;
37193752
break;
37203753
case FNIC_FRAME_TYPE_FDMI_RHBA:
3754+
iport->fabric.fdmi_pending &= ~FDLS_FDMI_REG_HBA_PENDING;
3755+
3756+
/* If RPA is still pending, don't turn off ABORT PENDING.
3757+
* We count on the timer to detect the ABTS timeout and take
3758+
* corrective action.
3759+
*/
3760+
if (!(iport->fabric.fdmi_pending & FDLS_FDMI_RPA_PENDING))
3761+
iport->fabric.fdmi_pending &= ~FDLS_FDMI_ABORT_PENDING;
3762+
37213763
fdls_free_oxid(iport, oxid, &iport->active_oxid_fdmi_rhba);
37223764
break;
37233765
case FNIC_FRAME_TYPE_FDMI_RPA:
3766+
iport->fabric.fdmi_pending &= ~FDLS_FDMI_RPA_PENDING;
3767+
3768+
/* If RHBA is still pending, don't turn off ABORT PENDING.
3769+
* We count on the timer to detect the ABTS timeout and take
3770+
* corrective action.
3771+
*/
3772+
if (!(iport->fabric.fdmi_pending & FDLS_FDMI_REG_HBA_PENDING))
3773+
iport->fabric.fdmi_pending &= ~FDLS_FDMI_ABORT_PENDING;
3774+
37243775
fdls_free_oxid(iport, oxid, &iport->active_oxid_fdmi_rpa);
37253776
break;
37263777
default:
@@ -3730,10 +3781,16 @@ static void fdls_process_fdmi_abts_rsp(struct fnic_iport_s *iport,
37303781
break;
37313782
}
37323783

3733-
timer_delete_sync(&iport->fabric.fdmi_timer);
3734-
iport->fabric.fdmi_pending &= ~FDLS_FDMI_ABORT_PENDING;
3735-
3736-
fdls_send_fdmi_plogi(iport);
3784+
/*
3785+
* Only if ABORT PENDING is off, delete the timer, and if no other
3786+
* operations are pending, retry FDMI.
3787+
* Otherwise, let the timer pop and take the appropriate action.
3788+
*/
3789+
if (!(iport->fabric.fdmi_pending & FDLS_FDMI_ABORT_PENDING)) {
3790+
timer_delete_sync(&iport->fabric.fdmi_timer);
3791+
if (!iport->fabric.fdmi_pending)
3792+
fdls_fdmi_retry_plogi(iport);
3793+
}
37373794
}
37383795

37393796
static void

drivers/scsi/fnic/fnic.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
#define DRV_NAME "fnic"
3232
#define DRV_DESCRIPTION "Cisco FCoE HBA Driver"
33-
#define DRV_VERSION "1.8.0.0"
33+
#define DRV_VERSION "1.8.0.1"
3434
#define PFX DRV_NAME ": "
3535
#define DFX DRV_NAME "%d: "
3636

drivers/scsi/fnic/fnic_fdls.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,7 @@ void fdls_send_tport_abts(struct fnic_iport_s *iport,
394394
bool fdls_delete_tport(struct fnic_iport_s *iport,
395395
struct fnic_tport_s *tport);
396396
void fdls_fdmi_timer_callback(struct timer_list *t);
397+
void fdls_fdmi_retry_plogi(struct fnic_iport_s *iport);
397398

398399
/* fnic_fcs.c */
399400
void fnic_fdls_init(struct fnic *fnic, int usefip);

0 commit comments

Comments
 (0)