You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
nvme: LightNVM support
The first generation of Open-Channel SSDs is based on NVMe. The NVMe driver is extended with support for the LightNVM command set. Detection is made through PCI IDs. Current supported devices are the qemu nvme simulator and CNEX Labs Westlake SSD. The qemu nvme enables support through vendor specific bits in the namespace identification and the CNEX Labs Westlake SSD implements a LightNVM compatible firmware and is detected using the same method as qemu. After detection, vendor specific codes are used to identify the device and enumerate supported features. Reviewed-by: Keith Busch <keith.busch@intel.com> Signed-off-by: Javier González <jg@lightnvm.io> Signed-off-by: Matias Bjørling <m@bjorling.me> Signed-off-by: Jens Axboe <axboe@fb.com>
This commit is contained in:
committed by
Jens Axboe
parent
ae1519ec44
commit
ca0640850e
@@ -1,4 +1,4 @@
|
||||
|
||||
obj-$(CONFIG_BLK_DEV_NVME) += nvme.o
|
||||
|
||||
nvme-y += pci.o scsi.o
|
||||
nvme-y += pci.o scsi.o lightnvm.o
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,6 +22,11 @@
|
||||
extern unsigned char nvme_io_timeout;
|
||||
#define NVME_IO_TIMEOUT (nvme_io_timeout * HZ)
|
||||
|
||||
enum {
|
||||
NVME_NS_LBA = 0,
|
||||
NVME_NS_LIGHTNVM = 1,
|
||||
};
|
||||
|
||||
/*
|
||||
* Represents an NVM Express device. Each nvme_dev is a PCI function.
|
||||
*/
|
||||
@@ -84,6 +89,7 @@ struct nvme_ns {
|
||||
u16 ms;
|
||||
bool ext;
|
||||
u8 pi_type;
|
||||
int type;
|
||||
u64 mode_select_num_blocks;
|
||||
u32 mode_select_block_len;
|
||||
};
|
||||
@@ -130,4 +136,8 @@ int nvme_sg_io(struct nvme_ns *ns, struct sg_io_hdr __user *u_hdr);
|
||||
int nvme_sg_io32(struct nvme_ns *ns, unsigned long arg);
|
||||
int nvme_sg_get_version_num(int __user *ip);
|
||||
|
||||
int nvme_nvm_ns_supported(struct nvme_ns *ns, struct nvme_id_ns *id);
|
||||
int nvme_nvm_register(struct request_queue *q, char *disk_name);
|
||||
void nvme_nvm_unregister(struct request_queue *q, char *disk_name);
|
||||
|
||||
#endif /* _NVME_H */
|
||||
|
||||
+28
-11
@@ -1948,6 +1948,9 @@ static void nvme_free_ns(struct kref *kref)
|
||||
{
|
||||
struct nvme_ns *ns = container_of(kref, struct nvme_ns, kref);
|
||||
|
||||
if (ns->type == NVME_NS_LIGHTNVM)
|
||||
nvme_nvm_unregister(ns->queue, ns->disk->disk_name);
|
||||
|
||||
spin_lock(&dev_list_lock);
|
||||
ns->disk->private_data = NULL;
|
||||
spin_unlock(&dev_list_lock);
|
||||
@@ -2017,6 +2020,16 @@ static int nvme_revalidate_disk(struct gendisk *disk)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (nvme_nvm_ns_supported(ns, id) && ns->type != NVME_NS_LIGHTNVM) {
|
||||
if (nvme_nvm_register(ns->queue, disk->disk_name)) {
|
||||
dev_warn(dev->dev,
|
||||
"%s: LightNVM init failure\n", __func__);
|
||||
kfree(id);
|
||||
return -ENODEV;
|
||||
}
|
||||
ns->type = NVME_NS_LIGHTNVM;
|
||||
}
|
||||
|
||||
old_ms = ns->ms;
|
||||
lbaf = id->flbas & NVME_NS_FLBAS_LBA_MASK;
|
||||
ns->lba_shift = id->lbaf[lbaf].ds;
|
||||
@@ -2048,7 +2061,9 @@ static int nvme_revalidate_disk(struct gendisk *disk)
|
||||
!ns->ext)
|
||||
nvme_init_integrity(ns);
|
||||
|
||||
if (ns->ms && !(ns->ms == 8 && ns->pi_type) && !blk_get_integrity(disk))
|
||||
if ((ns->ms && !(ns->ms == 8 && ns->pi_type) &&
|
||||
!blk_get_integrity(disk)) ||
|
||||
ns->type == NVME_NS_LIGHTNVM)
|
||||
set_capacity(disk, 0);
|
||||
else
|
||||
set_capacity(disk, le64_to_cpup(&id->nsze) << (ns->lba_shift - 9));
|
||||
@@ -2171,17 +2186,19 @@ static void nvme_alloc_ns(struct nvme_dev *dev, unsigned nsid)
|
||||
goto out_free_disk;
|
||||
|
||||
kref_get(&dev->kref);
|
||||
add_disk(ns->disk);
|
||||
if (ns->ms) {
|
||||
struct block_device *bd = bdget_disk(ns->disk, 0);
|
||||
if (!bd)
|
||||
return;
|
||||
if (blkdev_get(bd, FMODE_READ, NULL)) {
|
||||
bdput(bd);
|
||||
return;
|
||||
if (ns->type != NVME_NS_LIGHTNVM) {
|
||||
add_disk(ns->disk);
|
||||
if (ns->ms) {
|
||||
struct block_device *bd = bdget_disk(ns->disk, 0);
|
||||
if (!bd)
|
||||
return;
|
||||
if (blkdev_get(bd, FMODE_READ, NULL)) {
|
||||
bdput(bd);
|
||||
return;
|
||||
}
|
||||
blkdev_reread_part(bd);
|
||||
blkdev_put(bd, FMODE_READ);
|
||||
}
|
||||
blkdev_reread_part(bd);
|
||||
blkdev_put(bd, FMODE_READ);
|
||||
}
|
||||
return;
|
||||
out_free_disk:
|
||||
|
||||
Reference in New Issue
Block a user