nvme/quirk: Add a delay before checking for adapter readiness
When disabling the controller, the specification says the register NVME_REG_CC should be written and then driver needs to wait the adapter to be ready, which is checked by reading another register bit (NVME_CSTS_RDY). There's a timeout validation in this checking, so in case this timeout is reached the driver gives up and removes the adapter from the system. After a firmware activation procedure, the PCI_DEVICE(0x1c58, 0x0003) (HGST adapter) end up being removed if we issue a reset_controller, because driver keeps verifying the NVME_REG_CSTS until the timeout is reached. This patch adds a necessary quirk for this adapter, by introducing a delay before nvme_wait_ready(), so the reset procedure is able to be completed. This quirk is needed because just increasing the timeout is not enough in case of this adapter - the driver must wait before start reading NVME_REG_CSTS register on this specific device. Signed-off-by: Guilherme G. Piccoli <gpiccoli@linux.vnet.ibm.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Jens Axboe <axboe@fb.com>
This commit is contained in:
		
							parent
							
								
									41d512e51b
								
							
						
					
					
						commit
						54adc01055
					
				| @ -1109,6 +1109,15 @@ int nvme_disable_ctrl(struct nvme_ctrl *ctrl, u64 cap) | |||||||
| 	ret = ctrl->ops->reg_write32(ctrl, NVME_REG_CC, ctrl->ctrl_config); | 	ret = ctrl->ops->reg_write32(ctrl, NVME_REG_CC, ctrl->ctrl_config); | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		return ret; | 		return ret; | ||||||
|  | 
 | ||||||
|  | 	/* Checking for ctrl->tagset is a trick to avoid sleeping on module
 | ||||||
|  | 	 * load, since we only need the quirk on reset_controller. Notice | ||||||
|  | 	 * that the HGST device needs this delay only in firmware activation | ||||||
|  | 	 * procedure; unfortunately we have no (easy) way to verify this. | ||||||
|  | 	 */ | ||||||
|  | 	if ((ctrl->quirks & NVME_QUIRK_DELAY_BEFORE_CHK_RDY) && ctrl->tagset) | ||||||
|  | 		msleep(NVME_QUIRK_DELAY_AMOUNT); | ||||||
|  | 
 | ||||||
| 	return nvme_wait_ready(ctrl, cap, false); | 	return nvme_wait_ready(ctrl, cap, false); | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(nvme_disable_ctrl); | EXPORT_SYMBOL_GPL(nvme_disable_ctrl); | ||||||
|  | |||||||
| @ -68,8 +68,21 @@ enum nvme_quirks { | |||||||
| 	 * logical blocks. | 	 * logical blocks. | ||||||
| 	 */ | 	 */ | ||||||
| 	NVME_QUIRK_DISCARD_ZEROES		= (1 << 2), | 	NVME_QUIRK_DISCARD_ZEROES		= (1 << 2), | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * The controller needs a delay before starts checking the device | ||||||
|  | 	 * readiness, which is done by reading the NVME_CSTS_RDY bit. | ||||||
|  | 	 */ | ||||||
|  | 	NVME_QUIRK_DELAY_BEFORE_CHK_RDY		= (1 << 3), | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | /* The below value is the specific amount of delay needed before checking
 | ||||||
|  |  * readiness in case of the PCI_DEVICE(0x1c58, 0x0003), which needs the | ||||||
|  |  * NVME_QUIRK_DELAY_BEFORE_CHK_RDY quirk enabled. The value (in ms) was | ||||||
|  |  * found empirically. | ||||||
|  |  */ | ||||||
|  | #define NVME_QUIRK_DELAY_AMOUNT		2000 | ||||||
|  | 
 | ||||||
| enum nvme_ctrl_state { | enum nvme_ctrl_state { | ||||||
| 	NVME_CTRL_NEW, | 	NVME_CTRL_NEW, | ||||||
| 	NVME_CTRL_LIVE, | 	NVME_CTRL_LIVE, | ||||||
|  | |||||||
| @ -2094,6 +2094,8 @@ static const struct pci_device_id nvme_id_table[] = { | |||||||
| 				NVME_QUIRK_DISCARD_ZEROES, }, | 				NVME_QUIRK_DISCARD_ZEROES, }, | ||||||
| 	{ PCI_VDEVICE(INTEL, 0x5845),	/* Qemu emulated controller */ | 	{ PCI_VDEVICE(INTEL, 0x5845),	/* Qemu emulated controller */ | ||||||
| 		.driver_data = NVME_QUIRK_IDENTIFY_CNS, }, | 		.driver_data = NVME_QUIRK_IDENTIFY_CNS, }, | ||||||
|  | 	{ PCI_DEVICE(0x1c58, 0x0003),	/* HGST adapter */ | ||||||
|  | 		.driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, | ||||||
| 	{ PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_EXPRESS, 0xffffff) }, | 	{ PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_EXPRESS, 0xffffff) }, | ||||||
| 	{ PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2001) }, | 	{ PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2001) }, | ||||||
| 	{ 0, } | 	{ 0, } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user