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) |
