diff options
author | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-08-22 17:53:31 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-10-03 12:46:13 -0400 |
commit | 6f4267e3bd1211b3d09130e626b0b3d885077610 (patch) | |
tree | e9350f919238866c3bcd9c340ffea639a0c5de1d /drivers/scsi/scsi_lib.c | |
parent | 0f1d87a2acb8fd1f2ef8af109a785123ddc1a6cb (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.c | 39 |
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); |