Commit 6dd727da authored by mdr@sgi.com's avatar mdr@sgi.com Committed by James Bottomley

[SCSI] mptfc: race between mptfc_register_dev and mptfc_target_alloc

A race condition exists in mptfc between the thread registering a device
with the fc transport and the scan work generated by the transport.
This race existed prior to the application of the mptfc bug fix patch.

mptfc_register_dev() calls fc_remote_port_add() with the FC_RPORT_ROLE_TARGET
bit set in the rport ids passed to the function.  Having this bit set causes
fc_remote_port_add() to schedule a scan of the device.

This scan can execute before mptfc_register_dev() can fill in the dd_data
in the rport structure.  When this happens, mptfc_target_alloc() will fail
because dd_data is null.

Attached is a patch which fixes the problem.  The patch changes the rport ids
passed to fc_remote_port_add() to not have the TARGET bit set.  This prevents
the scan from being scheduled.  After mptfc_register_dev() fills in the rport
dd_data field, fc_remote_port_rolechg() is called, changing the role of the
rport to TARGET.  Thus, the scan is scheduled after dd_data is filled
in which prevents the failure in mptfc_target_alloc().
Signed-off-by: default avatarMichael Reed <mdr@sgi.com>
Signed-off-by: default avatarEric Moore <Eric.Moore@lsil.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 0b18ac42
...@@ -341,9 +341,6 @@ mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid) ...@@ -341,9 +341,6 @@ mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid)
rid->port_name = ((u64)pg0->WWPN.High) << 32 | (u64)pg0->WWPN.Low; rid->port_name = ((u64)pg0->WWPN.High) << 32 | (u64)pg0->WWPN.Low;
rid->port_id = pg0->PortIdentifier; rid->port_id = pg0->PortIdentifier;
rid->roles = FC_RPORT_ROLE_UNKNOWN; rid->roles = FC_RPORT_ROLE_UNKNOWN;
rid->roles |= FC_RPORT_ROLE_FCP_TARGET;
if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)
rid->roles |= FC_RPORT_ROLE_FCP_INITIATOR;
return 0; return 0;
} }
...@@ -357,10 +354,15 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) ...@@ -357,10 +354,15 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
int new_ri = 1; int new_ri = 1;
u64 pn, nn; u64 pn, nn;
VirtTarget *vtarget; VirtTarget *vtarget;
u32 roles = FC_RPORT_ROLE_UNKNOWN;
if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0) if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0)
return; return;
roles |= FC_RPORT_ROLE_FCP_TARGET;
if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)
roles |= FC_RPORT_ROLE_FCP_INITIATOR;
/* scan list looking for a match */ /* scan list looking for a match */
list_for_each_entry(ri, &ioc->fc_rports, list) { list_for_each_entry(ri, &ioc->fc_rports, list) {
pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
...@@ -400,8 +402,9 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) ...@@ -400,8 +402,9 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
vtarget->bus_id = pg0->CurrentBus; vtarget->bus_id = pg0->CurrentBus;
} }
} }
/* once dd_data is filled in, commands will issue to hardware */
*((struct mptfc_rport_info **)rport->dd_data) = ri; *((struct mptfc_rport_info **)rport->dd_data) = ri;
/* scan will be scheduled once rport becomes a target */
fc_remote_port_rolechg(rport,roles);
pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low; nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
......
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