aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ieee1394/sbp2.c
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2006-08-14 12:59:00 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2006-09-17 13:34:44 -0400
commit2cccbb555c77e641de9008660e08bdf17fc4206a (patch)
tree62cd3291088cce86f8a4ef9e25b1072b5c16ae2e /drivers/ieee1394/sbp2.c
parent902abed1587805fe8513e10aef6643f58a6de0a6 (diff)
ieee1394: sbp2: prevent rare deadlock in shutdown
Scsi_remove_device() may go into uninterruptible sleep if blocked. Therefore sbp2_remove() unblocks the Scsi_Host before the device is requested to be removed. But there could be another 1394 bus reset after that which would block the host again. The 1394 subsystem won't call sbp2_update() concurrently to sbp2_remove(), which is why there is no chance for sbp2_remove() to be unblocked by sbp2_update(). The fix is to tell sbp2's bus reset handler when a device is to be shut down so that it skips scsi_block_requests() on that host. As before, any new commands after a reset without reconnect will be failed quickly by sbp2scsi_queuecommand(). In the long term, means to go without scsi_block_requests() should be found. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/ieee1394/sbp2.c')
-rw-r--r--drivers/ieee1394/sbp2.c21
1 files changed, 11 insertions, 10 deletions
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index 3cb6b479b2ef..017259cc34f3 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -478,7 +478,7 @@ static void sbp2util_notify_fetch_agent(struct scsi_id_instance_data *scsi_id,
478 * There is a small window after a bus reset within which the node 478 * There is a small window after a bus reset within which the node
479 * entry's generation is current but the reconnect wasn't completed. 479 * entry's generation is current but the reconnect wasn't completed.
480 */ 480 */
481 if (atomic_read(&scsi_id->unfinished_reset)) 481 if (unlikely(atomic_read(&scsi_id->state) == SBP2LU_STATE_IN_RESET))
482 return; 482 return;
483 483
484 if (hpsb_node_write(scsi_id->ne, 484 if (hpsb_node_write(scsi_id->ne,
@@ -489,7 +489,7 @@ static void sbp2util_notify_fetch_agent(struct scsi_id_instance_data *scsi_id,
489 * Now accept new SCSI commands, unless a bus reset happended during 489 * Now accept new SCSI commands, unless a bus reset happended during
490 * hpsb_node_write. 490 * hpsb_node_write.
491 */ 491 */
492 if (!atomic_read(&scsi_id->unfinished_reset)) 492 if (likely(atomic_read(&scsi_id->state) != SBP2LU_STATE_IN_RESET))
493 scsi_unblock_requests(scsi_id->scsi_host); 493 scsi_unblock_requests(scsi_id->scsi_host);
494} 494}
495 495
@@ -756,7 +756,7 @@ static int sbp2_remove(struct device *dev)
756 sbp2scsi_complete_all_commands(scsi_id, DID_NO_CONNECT); 756 sbp2scsi_complete_all_commands(scsi_id, DID_NO_CONNECT);
757 /* scsi_remove_device() will trigger shutdown functions of SCSI 757 /* scsi_remove_device() will trigger shutdown functions of SCSI
758 * highlevel drivers which would deadlock if blocked. */ 758 * highlevel drivers which would deadlock if blocked. */
759 atomic_set(&scsi_id->unfinished_reset, 0); 759 atomic_set(&scsi_id->state, SBP2LU_STATE_IN_SHUTDOWN);
760 scsi_unblock_requests(scsi_id->scsi_host); 760 scsi_unblock_requests(scsi_id->scsi_host);
761 } 761 }
762 sdev = scsi_id->sdev; 762 sdev = scsi_id->sdev;
@@ -811,7 +811,7 @@ static int sbp2_update(struct unit_directory *ud)
811 /* Accept new commands unless there was another bus reset in the 811 /* Accept new commands unless there was another bus reset in the
812 * meantime. */ 812 * meantime. */
813 if (hpsb_node_entry_valid(scsi_id->ne)) { 813 if (hpsb_node_entry_valid(scsi_id->ne)) {
814 atomic_set(&scsi_id->unfinished_reset, 0); 814 atomic_set(&scsi_id->state, SBP2LU_STATE_RUNNING);
815 scsi_unblock_requests(scsi_id->scsi_host); 815 scsi_unblock_requests(scsi_id->scsi_host);
816 } 816 }
817 return 0; 817 return 0;
@@ -842,7 +842,7 @@ static struct scsi_id_instance_data *sbp2_alloc_device(struct unit_directory *ud
842 INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_completed); 842 INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_completed);
843 INIT_LIST_HEAD(&scsi_id->scsi_list); 843 INIT_LIST_HEAD(&scsi_id->scsi_list);
844 spin_lock_init(&scsi_id->sbp2_command_orb_lock); 844 spin_lock_init(&scsi_id->sbp2_command_orb_lock);
845 atomic_set(&scsi_id->unfinished_reset, 0); 845 atomic_set(&scsi_id->state, SBP2LU_STATE_RUNNING);
846 INIT_WORK(&scsi_id->protocol_work, NULL, NULL); 846 INIT_WORK(&scsi_id->protocol_work, NULL, NULL);
847 847
848 ud->device.driver_data = scsi_id; 848 ud->device.driver_data = scsi_id;
@@ -926,13 +926,14 @@ static void sbp2_host_reset(struct hpsb_host *host)
926 struct scsi_id_instance_data *scsi_id; 926 struct scsi_id_instance_data *scsi_id;
927 927
928 hi = hpsb_get_hostinfo(&sbp2_highlevel, host); 928 hi = hpsb_get_hostinfo(&sbp2_highlevel, host);
929 929 if (!hi)
930 if (hi) { 930 return;
931 list_for_each_entry(scsi_id, &hi->scsi_ids, scsi_list) { 931 list_for_each_entry(scsi_id, &hi->scsi_ids, scsi_list)
932 atomic_set(&scsi_id->unfinished_reset, 1); 932 if (likely(atomic_read(&scsi_id->state) !=
933 SBP2LU_STATE_IN_SHUTDOWN)) {
934 atomic_set(&scsi_id->state, SBP2LU_STATE_IN_RESET);
933 scsi_block_requests(scsi_id->scsi_host); 935 scsi_block_requests(scsi_id->scsi_host);
934 } 936 }
935 }
936} 937}
937 938
938/* 939/*