Send a shutdown notification in the driver unload path, to ensure
notification gets sent in cases where system shuts down with driver unloaded. Sponsored by: Intel Reviewed by: carl MFC after: 3 days
This commit is contained in:
parent
88d961f32e
commit
56183abc2b
@ -157,30 +157,14 @@ nvme_shutdown(void)
|
||||
{
|
||||
device_t *devlist;
|
||||
struct nvme_controller *ctrlr;
|
||||
union cc_register cc;
|
||||
union csts_register csts;
|
||||
int dev, devcount;
|
||||
|
||||
if (devclass_get_devices(nvme_devclass, &devlist, &devcount))
|
||||
return;
|
||||
|
||||
for (dev = 0; dev < devcount; dev++) {
|
||||
/*
|
||||
* Only notify controller of shutdown when a real shutdown is
|
||||
* in process, not when a module unload occurs. It seems at
|
||||
* least some controllers (Chatham at least) don't let you
|
||||
* re-enable the controller after shutdown notification has
|
||||
* been received.
|
||||
*/
|
||||
ctrlr = DEVICE2SOFTC(devlist[dev]);
|
||||
cc.raw = nvme_mmio_read_4(ctrlr, cc);
|
||||
cc.bits.shn = NVME_SHN_NORMAL;
|
||||
nvme_mmio_write_4(ctrlr, cc, cc.raw);
|
||||
csts.raw = nvme_mmio_read_4(ctrlr, csts);
|
||||
while (csts.bits.shst != NVME_SHST_COMPLETE) {
|
||||
DELAY(5);
|
||||
csts.raw = nvme_mmio_read_4(ctrlr, csts);
|
||||
}
|
||||
nvme_ctrlr_shutdown(ctrlr);
|
||||
}
|
||||
|
||||
free(devlist, M_TEMP);
|
||||
|
@ -170,27 +170,30 @@ struct nvme_registers
|
||||
union cap_lo_register cap_lo;
|
||||
union cap_hi_register cap_hi;
|
||||
|
||||
uint32_t vs; /* version */
|
||||
uint32_t intms; /* interrupt mask set */
|
||||
uint32_t intmc; /* interrupt mask clear */
|
||||
uint32_t vs; /* version */
|
||||
uint32_t intms; /* interrupt mask set */
|
||||
uint32_t intmc; /* interrupt mask clear */
|
||||
|
||||
/** controller configuration */
|
||||
union cc_register cc;
|
||||
|
||||
uint32_t reserved1;
|
||||
uint32_t csts; /* controller status */
|
||||
uint32_t reserved2;
|
||||
uint32_t reserved1;
|
||||
|
||||
/** controller status */
|
||||
union csts_register csts;
|
||||
|
||||
uint32_t reserved2;
|
||||
|
||||
/** admin queue attributes */
|
||||
union aqa_register aqa;
|
||||
|
||||
uint64_t asq; /* admin submission queue base addr */
|
||||
uint64_t acq; /* admin completion queue base addr */
|
||||
uint32_t reserved3[0x3f2];
|
||||
uint64_t asq; /* admin submission queue base addr */
|
||||
uint64_t acq; /* admin completion queue base addr */
|
||||
uint32_t reserved3[0x3f2];
|
||||
|
||||
struct {
|
||||
uint32_t sq_tdbl; /* submission queue tail doorbell */
|
||||
uint32_t cq_hdbl; /* completion queue head doorbell */
|
||||
uint32_t sq_tdbl; /* submission queue tail doorbell */
|
||||
uint32_t cq_hdbl; /* completion queue head doorbell */
|
||||
} doorbell[1] __packed;
|
||||
} __packed;
|
||||
|
||||
|
@ -1117,6 +1117,21 @@ nvme_ctrlr_destruct(struct nvme_controller *ctrlr, device_t dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Notify the controller of a shutdown, even though this is due to
|
||||
* a driver unload, not a system shutdown (this path is not invoked
|
||||
* during shutdown). This ensures the controller receives a
|
||||
* shutdown notification in case the system is shutdown before
|
||||
* reloading the driver.
|
||||
*
|
||||
* Chatham does not let you re-enable the controller after shutdown
|
||||
* notification has been received, so do not send it in this case.
|
||||
* This is OK because Chatham does not depend on the shutdown
|
||||
* notification anyways.
|
||||
*/
|
||||
if (pci_get_devid(ctrlr->dev) != CHATHAM_PCI_ID)
|
||||
nvme_ctrlr_shutdown(ctrlr);
|
||||
|
||||
nvme_ctrlr_disable(ctrlr);
|
||||
taskqueue_free(ctrlr->taskqueue);
|
||||
|
||||
@ -1162,6 +1177,26 @@ nvme_ctrlr_destruct(struct nvme_controller *ctrlr, device_t dev)
|
||||
pci_release_msi(dev);
|
||||
}
|
||||
|
||||
void
|
||||
nvme_ctrlr_shutdown(struct nvme_controller *ctrlr)
|
||||
{
|
||||
union cc_register cc;
|
||||
union csts_register csts;
|
||||
int ticks = 0;
|
||||
|
||||
cc.raw = nvme_mmio_read_4(ctrlr, cc);
|
||||
cc.bits.shn = NVME_SHN_NORMAL;
|
||||
nvme_mmio_write_4(ctrlr, cc, cc.raw);
|
||||
csts.raw = nvme_mmio_read_4(ctrlr, csts);
|
||||
while ((csts.bits.shst != NVME_SHST_COMPLETE) && (ticks++ < 5*hz)) {
|
||||
pause("nvme shn", 1);
|
||||
csts.raw = nvme_mmio_read_4(ctrlr, csts);
|
||||
}
|
||||
if (csts.bits.shst != NVME_SHST_COMPLETE)
|
||||
nvme_printf(ctrlr, "did not complete shutdown within 5 seconds "
|
||||
"of notification\n");
|
||||
}
|
||||
|
||||
void
|
||||
nvme_ctrlr_submit_admin_request(struct nvme_controller *ctrlr,
|
||||
struct nvme_request *req)
|
||||
|
@ -433,6 +433,7 @@ void nvme_completion_poll_cb(void *arg, const struct nvme_completion *cpl);
|
||||
|
||||
int nvme_ctrlr_construct(struct nvme_controller *ctrlr, device_t dev);
|
||||
void nvme_ctrlr_destruct(struct nvme_controller *ctrlr, device_t dev);
|
||||
void nvme_ctrlr_shutdown(struct nvme_controller *ctrlr);
|
||||
int nvme_ctrlr_hw_reset(struct nvme_controller *ctrlr);
|
||||
void nvme_ctrlr_reset(struct nvme_controller *ctrlr);
|
||||
/* ctrlr defined as void * to allow use with config_intrhook. */
|
||||
|
Loading…
Reference in New Issue
Block a user