drivers/nvme/target/zns.c

Source file repositories/reference/linux-study-clean/drivers/nvme/target/zns.c

File Facts

System
Linux kernel
Corpus path
drivers/nvme/target/zns.c
Extension
.c
Size
15673 bytes
Lines
624
Domain
Representative Device Path
Bucket
PCIe NVMe Storage Path
Inferred role
Representative Device Path: implementation source
Status
source implementation candidate

Why This File Exists

Part of the selected hardware vertical slice: PCI discovery, driver binding, NVMe queues, block requests, DMA, interrupts, and completion.

Dependency Surface

Detected Declarations

Annotated Snippet

struct nvmet_report_zone_data {
	struct nvmet_req *req;
	u64 out_buf_offset;
	u64 out_nr_zones;
	u64 nr_zones;
	u8 zrasf;
};

static int nvmet_bdev_report_zone_cb(struct blk_zone *z, unsigned i, void *d)
{
	static const unsigned int nvme_zrasf_to_blk_zcond[] = {
		[NVME_ZRASF_ZONE_STATE_EMPTY]	 = BLK_ZONE_COND_EMPTY,
		[NVME_ZRASF_ZONE_STATE_IMP_OPEN] = BLK_ZONE_COND_IMP_OPEN,
		[NVME_ZRASF_ZONE_STATE_EXP_OPEN] = BLK_ZONE_COND_EXP_OPEN,
		[NVME_ZRASF_ZONE_STATE_CLOSED]	 = BLK_ZONE_COND_CLOSED,
		[NVME_ZRASF_ZONE_STATE_READONLY] = BLK_ZONE_COND_READONLY,
		[NVME_ZRASF_ZONE_STATE_FULL]	 = BLK_ZONE_COND_FULL,
		[NVME_ZRASF_ZONE_STATE_OFFLINE]	 = BLK_ZONE_COND_OFFLINE,
	};
	struct nvmet_report_zone_data *rz = d;

	if (rz->zrasf != NVME_ZRASF_ZONE_REPORT_ALL &&
	    z->cond != nvme_zrasf_to_blk_zcond[rz->zrasf])
		return 0;

	if (rz->nr_zones < rz->out_nr_zones) {
		struct nvme_zone_descriptor zdesc = { };
		u16 status;

		zdesc.zcap = nvmet_sect_to_lba(rz->req->ns, z->capacity);
		zdesc.zslba = nvmet_sect_to_lba(rz->req->ns, z->start);
		zdesc.wp = nvmet_sect_to_lba(rz->req->ns, z->wp);
		zdesc.za = z->reset ? 1 << 2 : 0;
		zdesc.zs = z->cond << 4;
		zdesc.zt = z->type;

		status = nvmet_copy_to_sgl(rz->req, rz->out_buf_offset, &zdesc,
					   sizeof(zdesc));
		if (status)
			return -EINVAL;

		rz->out_buf_offset += sizeof(zdesc);
	}

	rz->nr_zones++;

	return 0;
}

static unsigned long nvmet_req_nr_zones_from_slba(struct nvmet_req *req)
{
	unsigned int sect = nvmet_lba_to_sect(req->ns, req->cmd->zmr.slba);

	return bdev_nr_zones(req->ns->bdev) - bdev_zone_no(req->ns->bdev, sect);
}

static unsigned long get_nr_zones_from_buf(struct nvmet_req *req, u32 bufsize)
{
	if (bufsize <= sizeof(struct nvme_zone_report))
		return 0;

	return (bufsize - sizeof(struct nvme_zone_report)) /
		sizeof(struct nvme_zone_descriptor);
}

static void nvmet_bdev_zone_zmgmt_recv_work(struct work_struct *w)
{
	struct nvmet_req *req = container_of(w, struct nvmet_req, z.zmgmt_work);
	sector_t start_sect = nvmet_lba_to_sect(req->ns, req->cmd->zmr.slba);
	unsigned long req_slba_nr_zones = nvmet_req_nr_zones_from_slba(req);
	u32 out_bufsize = (le32_to_cpu(req->cmd->zmr.numd) + 1) << 2;
	__le64 nr_zones;
	u16 status;
	int ret;
	struct nvmet_report_zone_data rz_data = {
		.out_nr_zones = get_nr_zones_from_buf(req, out_bufsize),
		/* leave the place for report zone header */
		.out_buf_offset = sizeof(struct nvme_zone_report),
		.zrasf = req->cmd->zmr.zrasf,
		.nr_zones = 0,
		.req = req,
	};

	status = nvmet_bdev_validate_zone_mgmt_recv(req);
	if (status)
		goto out;

	if (!req_slba_nr_zones) {
		status = NVME_SC_SUCCESS;
		goto out;

Annotation

Implementation Notes