diff options
author | mdr@sgi.com <mdr@sgi.com> | 2006-05-01 14:07:04 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-05-10 10:54:42 -0400 |
commit | 6dd727da92290193d0f74fa39f3ad53f423524db (patch) | |
tree | 156b847c2d65ab8679ab6805256244e5cf80805f | |
parent | 0b18ac42aa036c7fa217f178aa6a02c66e19e0a1 (diff) |
[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: Michael Reed <mdr@sgi.com>
Signed-off-by: Eric Moore <Eric.Moore@lsil.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r-- | drivers/message/fusion/mptfc.c | 11 |
1 files changed, 7 insertions, 4 deletions
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index e1fb5a166366..856487741ef4 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c | |||
@@ -341,9 +341,6 @@ mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid) | |||
341 | rid->port_name = ((u64)pg0->WWPN.High) << 32 | (u64)pg0->WWPN.Low; | 341 | rid->port_name = ((u64)pg0->WWPN.High) << 32 | (u64)pg0->WWPN.Low; |
342 | rid->port_id = pg0->PortIdentifier; | 342 | rid->port_id = pg0->PortIdentifier; |
343 | rid->roles = FC_RPORT_ROLE_UNKNOWN; | 343 | rid->roles = FC_RPORT_ROLE_UNKNOWN; |
344 | rid->roles |= FC_RPORT_ROLE_FCP_TARGET; | ||
345 | if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR) | ||
346 | rid->roles |= FC_RPORT_ROLE_FCP_INITIATOR; | ||
347 | 344 | ||
348 | return 0; | 345 | return 0; |
349 | } | 346 | } |
@@ -357,10 +354,15 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) | |||
357 | int new_ri = 1; | 354 | int new_ri = 1; |
358 | u64 pn, nn; | 355 | u64 pn, nn; |
359 | VirtTarget *vtarget; | 356 | VirtTarget *vtarget; |
357 | u32 roles = FC_RPORT_ROLE_UNKNOWN; | ||
360 | 358 | ||
361 | if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0) | 359 | if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0) |
362 | return; | 360 | return; |
363 | 361 | ||
362 | roles |= FC_RPORT_ROLE_FCP_TARGET; | ||
363 | if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR) | ||
364 | roles |= FC_RPORT_ROLE_FCP_INITIATOR; | ||
365 | |||
364 | /* scan list looking for a match */ | 366 | /* scan list looking for a match */ |
365 | list_for_each_entry(ri, &ioc->fc_rports, list) { | 367 | list_for_each_entry(ri, &ioc->fc_rports, list) { |
366 | pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; | 368 | 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 | vtarget->bus_id = pg0->CurrentBus; | 402 | vtarget->bus_id = pg0->CurrentBus; |
401 | } | 403 | } |
402 | } | 404 | } |
403 | /* once dd_data is filled in, commands will issue to hardware */ | ||
404 | *((struct mptfc_rport_info **)rport->dd_data) = ri; | 405 | *((struct mptfc_rport_info **)rport->dd_data) = ri; |
406 | /* scan will be scheduled once rport becomes a target */ | ||
407 | fc_remote_port_rolechg(rport,roles); | ||
405 | 408 | ||
406 | pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; | 409 | pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; |
407 | nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low; | 410 | nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low; |