aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/scsi_lib.c
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@HansenPartnership.com>2008-08-22 17:53:31 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-10-03 12:46:13 -0400
commit6f4267e3bd1211b3d09130e626b0b3d885077610 (patch)
treee9350f919238866c3bcd9c340ffea639a0c5de1d /drivers/scsi/scsi_lib.c
parent0f1d87a2acb8fd1f2ef8af109a785123ddc1a6cb (diff)
[SCSI] Update the SCSI state model to allow blocking in the created state
Brian King <brking@linux.vnet.ibm.com> reported that fibre channel devices can oops during scanning if their ports block (because the device goes from CREATED -> BLOCK -> RUNNING rather than CREATED -> BLOCK -> CREATED). Fix this by adding a new state: CREATED_BLOCK which can only transition back to CREATED and disallow the CREATED -> BLOCK transition. Now both the created and blocked states that the mid-layer recognises can include CREATED_BLOCK. Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/scsi_lib.c')
-rw-r--r--drivers/scsi/scsi_lib.c39
1 files changed, 30 insertions, 9 deletions
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 62307bd794a..d2884bffa1b 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -1251,6 +1251,7 @@ int scsi_prep_state_check(struct scsi_device *sdev, struct request *req)
1251 break; 1251 break;
1252 case SDEV_QUIESCE: 1252 case SDEV_QUIESCE:
1253 case SDEV_BLOCK: 1253 case SDEV_BLOCK:
1254 case SDEV_CREATED_BLOCK:
1254 /* 1255 /*
1255 * If the devices is blocked we defer normal commands. 1256 * If the devices is blocked we defer normal commands.
1256 */ 1257 */
@@ -2064,10 +2065,13 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
2064 2065
2065 switch (state) { 2066 switch (state) {
2066 case SDEV_CREATED: 2067 case SDEV_CREATED:
2067 /* There are no legal states that come back to 2068 switch (oldstate) {
2068 * created. This is the manually initialised start 2069 case SDEV_CREATED_BLOCK:
2069 * state */ 2070 break;
2070 goto illegal; 2071 default:
2072 goto illegal;
2073 }
2074 break;
2071 2075
2072 case SDEV_RUNNING: 2076 case SDEV_RUNNING:
2073 switch (oldstate) { 2077 switch (oldstate) {
@@ -2105,8 +2109,17 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
2105 2109
2106 case SDEV_BLOCK: 2110 case SDEV_BLOCK:
2107 switch (oldstate) { 2111 switch (oldstate) {
2108 case SDEV_CREATED:
2109 case SDEV_RUNNING: 2112 case SDEV_RUNNING:
2113 case SDEV_CREATED_BLOCK:
2114 break;
2115 default:
2116 goto illegal;
2117 }
2118 break;
2119
2120 case SDEV_CREATED_BLOCK:
2121 switch (oldstate) {
2122 case SDEV_CREATED:
2110 break; 2123 break;
2111 default: 2124 default:
2112 goto illegal; 2125 goto illegal;
@@ -2394,8 +2407,12 @@ scsi_internal_device_block(struct scsi_device *sdev)
2394 int err = 0; 2407 int err = 0;
2395 2408
2396 err = scsi_device_set_state(sdev, SDEV_BLOCK); 2409 err = scsi_device_set_state(sdev, SDEV_BLOCK);
2397 if (err) 2410 if (err) {
2398 return err; 2411 err = scsi_device_set_state(sdev, SDEV_CREATED_BLOCK);
2412
2413 if (err)
2414 return err;
2415 }
2399 2416
2400 /* 2417 /*
2401 * The device has transitioned to SDEV_BLOCK. Stop the 2418 * The device has transitioned to SDEV_BLOCK. Stop the
@@ -2438,8 +2455,12 @@ scsi_internal_device_unblock(struct scsi_device *sdev)
2438 * and goose the device queue if successful. 2455 * and goose the device queue if successful.
2439 */ 2456 */
2440 err = scsi_device_set_state(sdev, SDEV_RUNNING); 2457 err = scsi_device_set_state(sdev, SDEV_RUNNING);
2441 if (err) 2458 if (err) {
2442 return err; 2459 err = scsi_device_set_state(sdev, SDEV_CREATED);
2460
2461 if (err)
2462 return err;
2463 }
2443 2464
2444 spin_lock_irqsave(q->queue_lock, flags); 2465 spin_lock_irqsave(q->queue_lock, flags);
2445 blk_start_queue(q); 2466 blk_start_queue(q);