aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/scsi/scsi_lib.c39
-rw-r--r--drivers/scsi/scsi_scan.c16
-rw-r--r--drivers/scsi/scsi_sysfs.c1
-rw-r--r--include/scsi/scsi_device.h14
4 files changed, 54 insertions, 16 deletions
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 62307bd794a9..d2884bffa1b9 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);
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 2926baaac31e..334862e26a1b 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -730,6 +730,8 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
730static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, 730static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
731 int *bflags, int async) 731 int *bflags, int async)
732{ 732{
733 int ret;
734
733 /* 735 /*
734 * XXX do not save the inquiry, since it can change underneath us, 736 * XXX do not save the inquiry, since it can change underneath us,
735 * save just vendor/model/rev. 737 * save just vendor/model/rev.
@@ -885,7 +887,17 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
885 887
886 /* set the device running here so that slave configure 888 /* set the device running here so that slave configure
887 * may do I/O */ 889 * may do I/O */
888 scsi_device_set_state(sdev, SDEV_RUNNING); 890 ret = scsi_device_set_state(sdev, SDEV_RUNNING);
891 if (ret) {
892 ret = scsi_device_set_state(sdev, SDEV_BLOCK);
893
894 if (ret) {
895 sdev_printk(KERN_ERR, sdev,
896 "in wrong state %s to complete scan\n",
897 scsi_device_state_name(sdev->sdev_state));
898 return SCSI_SCAN_NO_RESPONSE;
899 }
900 }
889 901
890 if (*bflags & BLIST_MS_192_BYTES_FOR_3F) 902 if (*bflags & BLIST_MS_192_BYTES_FOR_3F)
891 sdev->use_192_bytes_for_3f = 1; 903 sdev->use_192_bytes_for_3f = 1;
@@ -899,7 +911,7 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
899 transport_configure_device(&sdev->sdev_gendev); 911 transport_configure_device(&sdev->sdev_gendev);
900 912
901 if (sdev->host->hostt->slave_configure) { 913 if (sdev->host->hostt->slave_configure) {
902 int ret = sdev->host->hostt->slave_configure(sdev); 914 ret = sdev->host->hostt->slave_configure(sdev);
903 if (ret) { 915 if (ret) {
904 /* 916 /*
905 * if LLDD reports slave not present, don't clutter 917 * if LLDD reports slave not present, don't clutter
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index ab3c71869be5..09d311d559d1 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -34,6 +34,7 @@ static const struct {
34 { SDEV_QUIESCE, "quiesce" }, 34 { SDEV_QUIESCE, "quiesce" },
35 { SDEV_OFFLINE, "offline" }, 35 { SDEV_OFFLINE, "offline" },
36 { SDEV_BLOCK, "blocked" }, 36 { SDEV_BLOCK, "blocked" },
37 { SDEV_CREATED_BLOCK, "created-blocked" },
37}; 38};
38 39
39const char *scsi_device_state_name(enum scsi_device_state state) 40const char *scsi_device_state_name(enum scsi_device_state state)
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index cc46652e4658..b49e725be039 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -42,9 +42,11 @@ enum scsi_device_state {
42 * originate in the mid-layer) */ 42 * originate in the mid-layer) */
43 SDEV_OFFLINE, /* Device offlined (by error handling or 43 SDEV_OFFLINE, /* Device offlined (by error handling or
44 * user request */ 44 * user request */
45 SDEV_BLOCK, /* Device blocked by scsi lld. No scsi 45 SDEV_BLOCK, /* Device blocked by scsi lld. No
46 * commands from user or midlayer should be issued 46 * scsi commands from user or midlayer
47 * to the scsi lld. */ 47 * should be issued to the scsi
48 * lld. */
49 SDEV_CREATED_BLOCK, /* same as above but for created devices */
48}; 50};
49 51
50enum scsi_device_event { 52enum scsi_device_event {
@@ -393,11 +395,13 @@ static inline int scsi_device_online(struct scsi_device *sdev)
393} 395}
394static inline int scsi_device_blocked(struct scsi_device *sdev) 396static inline int scsi_device_blocked(struct scsi_device *sdev)
395{ 397{
396 return sdev->sdev_state == SDEV_BLOCK; 398 return sdev->sdev_state == SDEV_BLOCK ||
399 sdev->sdev_state == SDEV_CREATED_BLOCK;
397} 400}
398static inline int scsi_device_created(struct scsi_device *sdev) 401static inline int scsi_device_created(struct scsi_device *sdev)
399{ 402{
400 return sdev->sdev_state == SDEV_CREATED; 403 return sdev->sdev_state == SDEV_CREATED ||
404 sdev->sdev_state == SDEV_CREATED_BLOCK;
401} 405}
402 406
403/* accessor functions for the SCSI parameters */ 407/* accessor functions for the SCSI parameters */