diff options
author | Keith Busch <keith.busch@intel.com> | 2013-07-15 17:02:22 -0400 |
---|---|---|
committer | Matthew Wilcox <matthew.r.wilcox@intel.com> | 2013-09-03 16:40:32 -0400 |
commit | 1894d8f16afe5ad54b732f0fa6c4e80bd4d40b91 (patch) | |
tree | f1451bcf63fc1ddc60b10ba0f502029da1119e7e | |
parent | f0b50732a979c55c2d15fe8ec4503fa5b3260c53 (diff) |
NVMe: Use normal shutdown
The NVMe spec recommends using the shutdown normal sequence when safely
taking the controller offline instead of hitting CC.EN on the next
start-up to reset the controller. The spec recommends a minimum of 1
second for the shutdown complete. This patch waits 2 seconds to be on
the safe side.
Signed-off-by: Keith Busch <keith.busch@intel.com>
Signed-off-by: Matthew Wilcox <matthew.r.wilcox@intel.com>
-rw-r--r-- | drivers/block/nvme-core.c | 26 | ||||
-rw-r--r-- | include/linux/nvme.h | 2 |
2 files changed, 28 insertions, 0 deletions
diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 1595ffba8a66..23bb5a70d810 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c | |||
@@ -1221,6 +1221,30 @@ static int nvme_enable_ctrl(struct nvme_dev *dev, u64 cap) | |||
1221 | return nvme_wait_ready(dev, cap, true); | 1221 | return nvme_wait_ready(dev, cap, true); |
1222 | } | 1222 | } |
1223 | 1223 | ||
1224 | static int nvme_shutdown_ctrl(struct nvme_dev *dev) | ||
1225 | { | ||
1226 | unsigned long timeout; | ||
1227 | u32 cc; | ||
1228 | |||
1229 | cc = (readl(&dev->bar->cc) & ~NVME_CC_SHN_MASK) | NVME_CC_SHN_NORMAL; | ||
1230 | writel(cc, &dev->bar->cc); | ||
1231 | |||
1232 | timeout = 2 * HZ + jiffies; | ||
1233 | while ((readl(&dev->bar->csts) & NVME_CSTS_SHST_MASK) != | ||
1234 | NVME_CSTS_SHST_CMPLT) { | ||
1235 | msleep(100); | ||
1236 | if (fatal_signal_pending(current)) | ||
1237 | return -EINTR; | ||
1238 | if (time_after(jiffies, timeout)) { | ||
1239 | dev_err(&dev->pci_dev->dev, | ||
1240 | "Device shutdown incomplete; abort shutdown\n"); | ||
1241 | return -ENODEV; | ||
1242 | } | ||
1243 | } | ||
1244 | |||
1245 | return 0; | ||
1246 | } | ||
1247 | |||
1224 | static int nvme_configure_admin_queue(struct nvme_dev *dev) | 1248 | static int nvme_configure_admin_queue(struct nvme_dev *dev) |
1225 | { | 1249 | { |
1226 | int result; | 1250 | int result; |
@@ -1943,6 +1967,8 @@ static void nvme_dev_shutdown(struct nvme_dev *dev) | |||
1943 | list_del_init(&dev->node); | 1967 | list_del_init(&dev->node); |
1944 | spin_unlock(&dev_list_lock); | 1968 | spin_unlock(&dev_list_lock); |
1945 | 1969 | ||
1970 | if (dev->bar) | ||
1971 | nvme_shutdown_ctrl(dev); | ||
1946 | nvme_dev_unmap(dev); | 1972 | nvme_dev_unmap(dev); |
1947 | } | 1973 | } |
1948 | 1974 | ||
diff --git a/include/linux/nvme.h b/include/linux/nvme.h index 3403c8f06fa0..26ebcf41c213 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h | |||
@@ -53,6 +53,7 @@ enum { | |||
53 | NVME_CC_SHN_NONE = 0 << 14, | 53 | NVME_CC_SHN_NONE = 0 << 14, |
54 | NVME_CC_SHN_NORMAL = 1 << 14, | 54 | NVME_CC_SHN_NORMAL = 1 << 14, |
55 | NVME_CC_SHN_ABRUPT = 2 << 14, | 55 | NVME_CC_SHN_ABRUPT = 2 << 14, |
56 | NVME_CC_SHN_MASK = 3 << 14, | ||
56 | NVME_CC_IOSQES = 6 << 16, | 57 | NVME_CC_IOSQES = 6 << 16, |
57 | NVME_CC_IOCQES = 4 << 20, | 58 | NVME_CC_IOCQES = 4 << 20, |
58 | NVME_CSTS_RDY = 1 << 0, | 59 | NVME_CSTS_RDY = 1 << 0, |
@@ -60,6 +61,7 @@ enum { | |||
60 | NVME_CSTS_SHST_NORMAL = 0 << 2, | 61 | NVME_CSTS_SHST_NORMAL = 0 << 2, |
61 | NVME_CSTS_SHST_OCCUR = 1 << 2, | 62 | NVME_CSTS_SHST_OCCUR = 1 << 2, |
62 | NVME_CSTS_SHST_CMPLT = 2 << 2, | 63 | NVME_CSTS_SHST_CMPLT = 2 << 2, |
64 | NVME_CSTS_SHST_MASK = 3 << 2, | ||
63 | }; | 65 | }; |
64 | 66 | ||
65 | #define NVME_VS(major, minor) (major << 16 | minor) | 67 | #define NVME_VS(major, minor) (major << 16 | minor) |