Commit 6f4267e3bd1211b3d09130e626b0b3d885077610
1 parent
0f1d87a2ac
Exists in
master
and in
4 other branches
[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>
Showing 4 changed files with 54 additions and 16 deletions Side-by-side Diff
drivers/scsi/scsi_lib.c
... | ... | @@ -1251,6 +1251,7 @@ |
1251 | 1251 | break; |
1252 | 1252 | case SDEV_QUIESCE: |
1253 | 1253 | case SDEV_BLOCK: |
1254 | + case SDEV_CREATED_BLOCK: | |
1254 | 1255 | /* |
1255 | 1256 | * If the devices is blocked we defer normal commands. |
1256 | 1257 | */ |
... | ... | @@ -2064,10 +2065,13 @@ |
2064 | 2065 | |
2065 | 2066 | switch (state) { |
2066 | 2067 | case SDEV_CREATED: |
2067 | - /* There are no legal states that come back to | |
2068 | - * created. This is the manually initialised start | |
2069 | - * state */ | |
2070 | - goto illegal; | |
2068 | + switch (oldstate) { | |
2069 | + case SDEV_CREATED_BLOCK: | |
2070 | + break; | |
2071 | + default: | |
2072 | + goto illegal; | |
2073 | + } | |
2074 | + break; | |
2071 | 2075 | |
2072 | 2076 | case SDEV_RUNNING: |
2073 | 2077 | switch (oldstate) { |
2074 | 2078 | |
2075 | 2079 | |
... | ... | @@ -2105,14 +2109,23 @@ |
2105 | 2109 | |
2106 | 2110 | case SDEV_BLOCK: |
2107 | 2111 | switch (oldstate) { |
2108 | - case SDEV_CREATED: | |
2109 | 2112 | case SDEV_RUNNING: |
2113 | + case SDEV_CREATED_BLOCK: | |
2110 | 2114 | break; |
2111 | 2115 | default: |
2112 | 2116 | goto illegal; |
2113 | 2117 | } |
2114 | 2118 | break; |
2115 | 2119 | |
2120 | + case SDEV_CREATED_BLOCK: | |
2121 | + switch (oldstate) { | |
2122 | + case SDEV_CREATED: | |
2123 | + break; | |
2124 | + default: | |
2125 | + goto illegal; | |
2126 | + } | |
2127 | + break; | |
2128 | + | |
2116 | 2129 | case SDEV_CANCEL: |
2117 | 2130 | switch (oldstate) { |
2118 | 2131 | case SDEV_CREATED: |
2119 | 2132 | |
... | ... | @@ -2394,9 +2407,13 @@ |
2394 | 2407 | int err = 0; |
2395 | 2408 | |
2396 | 2409 | err = scsi_device_set_state(sdev, SDEV_BLOCK); |
2397 | - if (err) | |
2398 | - return err; | |
2410 | + if (err) { | |
2411 | + err = scsi_device_set_state(sdev, SDEV_CREATED_BLOCK); | |
2399 | 2412 | |
2413 | + if (err) | |
2414 | + return err; | |
2415 | + } | |
2416 | + | |
2400 | 2417 | /* |
2401 | 2418 | * The device has transitioned to SDEV_BLOCK. Stop the |
2402 | 2419 | * block layer from calling the midlayer with this device's |
... | ... | @@ -2438,8 +2455,12 @@ |
2438 | 2455 | * and goose the device queue if successful. |
2439 | 2456 | */ |
2440 | 2457 | err = scsi_device_set_state(sdev, SDEV_RUNNING); |
2441 | - if (err) | |
2442 | - return err; | |
2458 | + if (err) { | |
2459 | + err = scsi_device_set_state(sdev, SDEV_CREATED); | |
2460 | + | |
2461 | + if (err) | |
2462 | + return err; | |
2463 | + } | |
2443 | 2464 | |
2444 | 2465 | spin_lock_irqsave(q->queue_lock, flags); |
2445 | 2466 | blk_start_queue(q); |
drivers/scsi/scsi_scan.c
... | ... | @@ -730,6 +730,8 @@ |
730 | 730 | static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, |
731 | 731 | int *bflags, int async) |
732 | 732 | { |
733 | + int ret; | |
734 | + | |
733 | 735 | /* |
734 | 736 | * XXX do not save the inquiry, since it can change underneath us, |
735 | 737 | * save just vendor/model/rev. |
736 | 738 | |
... | ... | @@ -885,8 +887,18 @@ |
885 | 887 | |
886 | 888 | /* set the device running here so that slave configure |
887 | 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); | |
889 | 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 | + } | |
901 | + | |
890 | 902 | if (*bflags & BLIST_MS_192_BYTES_FOR_3F) |
891 | 903 | sdev->use_192_bytes_for_3f = 1; |
892 | 904 | |
... | ... | @@ -899,7 +911,7 @@ |
899 | 911 | transport_configure_device(&sdev->sdev_gendev); |
900 | 912 | |
901 | 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 | 915 | if (ret) { |
904 | 916 | /* |
905 | 917 | * if LLDD reports slave not present, don't clutter |
drivers/scsi/scsi_sysfs.c
include/scsi/scsi_device.h
... | ... | @@ -42,9 +42,11 @@ |
42 | 42 | * originate in the mid-layer) */ |
43 | 43 | SDEV_OFFLINE, /* Device offlined (by error handling or |
44 | 44 | * user request */ |
45 | - SDEV_BLOCK, /* Device blocked by scsi lld. No scsi | |
46 | - * commands from user or midlayer should be issued | |
47 | - * to the scsi lld. */ | |
45 | + SDEV_BLOCK, /* Device blocked by scsi lld. No | |
46 | + * scsi commands from user or midlayer | |
47 | + * should be issued to the scsi | |
48 | + * lld. */ | |
49 | + SDEV_CREATED_BLOCK, /* same as above but for created devices */ | |
48 | 50 | }; |
49 | 51 | |
50 | 52 | enum scsi_device_event { |
51 | 53 | |
... | ... | @@ -393,11 +395,13 @@ |
393 | 395 | } |
394 | 396 | static 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 | } |
398 | 401 | static 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 | 407 | /* accessor functions for the SCSI parameters */ |