Esempio n. 1
0
int nvme_print_info(struct udevice *udev)
{
	struct nvme_ns *ns = dev_get_priv(udev);
	struct nvme_dev *dev = ns->dev;
	struct nvme_id_ns buf_ns, *id = &buf_ns;
	struct nvme_id_ctrl buf_ctrl, *ctrl = &buf_ctrl;

	if (nvme_identify(dev, 0, 1, (dma_addr_t)ctrl))
		return -EIO;

	print_optional_admin_cmd(le16_to_cpu(ctrl->oacs), ns->devnum);
	print_optional_nvm_cmd(le16_to_cpu(ctrl->oncs), ns->devnum);
	print_format_nvme_attributes(ctrl->fna, ns->devnum);

	if (nvme_identify(dev, ns->ns_id, 0, (dma_addr_t)id))
		return -EIO;

	print_formats(id, ns);
	print_data_protect_cap(id->dpc, ns->devnum);
	print_metadata_cap(id->mc, ns->devnum);

	return 0;
}
Esempio n. 2
0
int nvme_passthru(int fd, int ioctl_cmd, __u8 opcode, __u8 flags, __u16 rsvd,
		  __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10, __u32 cdw11,
		  __u32 cdw12, __u32 cdw13, __u32 cdw14, __u32 cdw15,
		  __u32 data_len, void *data, __u32 metadata_len,
		  void *metadata, __u32 timeout_ms, __u32 *result)
{
	struct nvme_passthru_cmd cmd = {
		.opcode		= opcode,
		.flags		= flags,
		.rsvd1		= rsvd,
		.nsid		= nsid,
		.cdw2		= cdw2,
		.cdw3		= cdw3,
		.metadata	= (__u64)(uintptr_t) metadata,
		.addr		= (__u64)(uintptr_t) data,
		.metadata_len	= metadata_len,
		.data_len	= data_len,
		.cdw10		= cdw10,
		.cdw11		= cdw11,
		.cdw12		= cdw12,
		.cdw13		= cdw13,
		.cdw14		= cdw14,
		.cdw15		= cdw15,
		.timeout_ms	= timeout_ms,
		.result		= 0,
	};
	int err;

	err = nvme_submit_passthru(fd, ioctl_cmd, &cmd);
	if (!err && result)
		*result = cmd.result;
	return err;
}

int nvme_io(int fd, __u8 opcode, __u64 slba, __u16 nblocks, __u16 control,
	    __u32 dsmgmt, __u32 reftag, __u16 apptag, __u16 appmask, void *data,
	    void *metadata)
{
	struct nvme_user_io io = {
		.opcode		= opcode,
		.flags		= 0,
		.control	= control,
		.nblocks	= nblocks,
		.rsvd		= 0,
		.metadata	= (__u64)(uintptr_t) metadata,
		.addr		= (__u64)(uintptr_t) data,
		.slba		= slba,
		.dsmgmt		= dsmgmt,
		.reftag		= reftag,
		.appmask	= apptag,
		.apptag		= appmask,
	};
	return ioctl(fd, NVME_IOCTL_SUBMIT_IO, &io);
}

int nvme_read(int fd, __u64 slba, __u16 nblocks, __u16 control, __u32 dsmgmt,
	      __u32 reftag, __u16 apptag, __u16 appmask, void *data,
	      void *metadata)
{
	return nvme_io(fd, nvme_cmd_read, slba, nblocks, control, dsmgmt,
		       reftag, apptag, appmask, data, metadata);
}

int nvme_write(int fd, __u64 slba, __u16 nblocks, __u16 control, __u32 dsmgmt,
	       __u32 reftag, __u16 apptag, __u16 appmask, void *data,
	       void *metadata)
{
	return nvme_io(fd, nvme_cmd_write, slba, nblocks, control, dsmgmt,
		       reftag, apptag, appmask, data, metadata);
}

int nvme_compare(int fd, __u64 slba, __u16 nblocks, __u16 control, __u32 dsmgmt,
		 __u32 reftag, __u16 apptag, __u16 appmask, void *data,
		 void *metadata)
{
	return nvme_io(fd, nvme_cmd_compare, slba, nblocks, control, dsmgmt,
		       reftag, apptag, appmask, data, metadata);
}

int nvme_passthru_io(int fd, __u8 opcode, __u8 flags, __u16 rsvd,
		     __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10,
		     __u32 cdw11, __u32 cdw12, __u32 cdw13, __u32 cdw14,
		     __u32 cdw15, __u32 data_len, void *data,
		     __u32 metadata_len, void *metadata, __u32 timeout_ms)
{
	return nvme_passthru(fd, NVME_IOCTL_IO_CMD, opcode, flags, rsvd, nsid,
			     cdw2, cdw3, cdw10, cdw11, cdw12, cdw13, cdw14,
			     cdw15, data_len, data, metadata_len, metadata,
			     timeout_ms, NULL);
}

int nvme_write_zeros(int fd, __u32 nsid, __u64 slba, __u16 nlb,
		     __u16 control, __u32 reftag, __u16 apptag, __u16 appmask)
{
	struct nvme_passthru_cmd cmd = {
		.opcode		= nvme_cmd_write_zeroes,
		.nsid		= nsid,
		.cdw10		= slba & 0xffffffff,
		.cdw11		= slba >> 32,
		.cdw12		= nlb | (control << 16),
		.cdw14		= reftag,
		.cdw15		= apptag | (appmask << 16),
	};

	return nvme_submit_io_passthru(fd, &cmd);
}

int nvme_write_uncorrectable(int fd, __u32 nsid, __u64 slba, __u16 nlb)
{
	struct nvme_passthru_cmd cmd = {
		.opcode		= nvme_cmd_write_uncor,
		.nsid		= nsid,
		.cdw10		= slba & 0xffffffff,
		.cdw11		= slba >> 32,
		.cdw12		= nlb,
	};

	return nvme_submit_io_passthru(fd, &cmd);
}

int nvme_flush(int fd, __u32 nsid)
{
	struct nvme_passthru_cmd cmd = {
		.opcode		= nvme_cmd_flush,
		.nsid		= nsid,
	};

	return nvme_submit_io_passthru(fd, &cmd);
}

int nvme_dsm(int fd, __u32 nsid, __u32 cdw11, struct nvme_dsm_range *dsm,
	     __u16 nr_ranges)
{
	struct nvme_passthru_cmd cmd = {
		.opcode		= nvme_cmd_dsm,
		.nsid		= nsid,
		.addr		= (__u64)(uintptr_t) dsm,
		.data_len	= nr_ranges * sizeof(*dsm),
		.cdw10		= nr_ranges - 1,
		.cdw11		= cdw11,
	};

	return nvme_submit_io_passthru(fd, &cmd);
}

struct nvme_dsm_range *nvme_setup_dsm_range(__u32 *ctx_attrs, __u32 *llbas,
					    __u64 *slbas, __u16 nr_ranges)
{
	int i;
	struct nvme_dsm_range *dsm = malloc(nr_ranges * sizeof(*dsm));

	if (!dsm)
		exit(ENOMEM);
	for (i = 0; i < nr_ranges; i++) {
		dsm[i].cattr = htole32(ctx_attrs[i]);
		dsm[i].nlb = htole32(llbas[i]);
		dsm[i].slba = htole64(slbas[i]);
	}
	return dsm;
}

int nvme_resv_acquire(int fd, __u32 nsid, __u8 rtype, __u8 racqa,
		      bool iekey, __u64 crkey, __u64 nrkey)
{
	__le64 payload[2] = { htole64(crkey), htole64(nrkey) };
	__u32 cdw10 = racqa | (iekey ? 1 << 3 : 0) | rtype << 8;
	struct nvme_passthru_cmd cmd = {
		.opcode		= nvme_cmd_resv_acquire,
		.nsid		= nsid,
		.cdw10		= cdw10,
		.addr		= (__u64)(uintptr_t) (payload),
		.data_len	= sizeof(payload),
	};

	return nvme_submit_io_passthru(fd, &cmd);
}

int nvme_resv_register(int fd, __u32 nsid, __u8 rrega, __u8 cptpl,
		       bool iekey, __u64 crkey, __u64 nrkey)
{
	__le64 payload[2] = { htole64(crkey), htole64(nrkey) };
	__u32 cdw10 = rrega | (iekey ? 1 << 3 : 0) | cptpl << 30;

	struct nvme_passthru_cmd cmd = {
		.opcode		= nvme_cmd_resv_register,
		.nsid		= nsid,
		.cdw10		= cdw10,
		.addr		= (__u64)(uintptr_t) (payload),
		.data_len	= sizeof(payload),
	};

	return nvme_submit_io_passthru(fd, &cmd);
}

int nvme_resv_release(int fd, __u32 nsid, __u8 rtype, __u8 rrela,
		      bool iekey, __u64 crkey)
{
	__le64 payload[1] = { htole64(crkey) };
	__u32 cdw10 = rrela | (iekey ? 1 << 3 : 0) | rtype << 8;

	struct nvme_passthru_cmd cmd = {
		.opcode		= nvme_cmd_resv_register,
		.nsid		= nsid,
		.cdw10		= cdw10,
		.addr		= (__u64)(uintptr_t) (payload),
		.data_len	= sizeof(payload),
	};

	return nvme_submit_io_passthru(fd, &cmd);
}

int nvme_resv_report(int fd, __u32 nsid, __u32 numd, void *data)
{
	struct nvme_passthru_cmd cmd = {
		.opcode		= nvme_cmd_resv_report,
		.nsid		= nsid,
		.addr		= (__u64)(uintptr_t) data,
		.data_len	= numd << 2,
	};

	return nvme_submit_io_passthru(fd, &cmd);
}

int nvme_passthru_admin(int fd, __u8 opcode, __u8 flags, __u16 rsvd,
			__u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10,
			__u32 cdw11, __u32 cdw12, __u32 cdw13, __u32 cdw14,
			__u32 cdw15, __u32 data_len, void *data,
			__u32 metadata_len, void *metadata, __u32 timeout_ms)
{
	return nvme_passthru(fd, NVME_IOCTL_ADMIN_CMD, opcode, flags, rsvd,
			     nsid, cdw2, cdw3, cdw10, cdw11, cdw12, cdw13,
			     cdw14, cdw15, data_len, data, metadata_len,
			     metadata, timeout_ms, NULL);
}

int nvme_identify(int fd, __u32 nsid, __u32 cdw10, void *data)
{
	struct nvme_admin_cmd cmd = {
		.opcode		= nvme_admin_identify,
		.nsid		= nsid,
		.addr		= (__u64)(uintptr_t) data,
		.data_len	= 0x1000,
		.cdw10		= cdw10,
	};

	return nvme_submit_admin_passthru(fd, &cmd);
}

int nvme_identify_ctrl(int fd, void *data)
{
	return nvme_identify(fd, 0, 1, data);
}

int nvme_identify_ns(int fd, __u32 nsid, bool present, void *data)
{
	int cns = present ? NVME_ID_CNS_NS_PRESENT : NVME_ID_CNS_NS;

	return nvme_identify(fd, nsid, cns, data);
}

int nvme_identify_ns_list(int fd, __u32 nsid, bool all, void *data)
{
	int cns = all ? NVME_ID_CNS_NS_ACTIVE_LIST : NVME_ID_CNS_NS_PRESENT_LIST;

	return nvme_identify(fd, nsid, cns, data);
}

int nvme_identify_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data)
{
	int cns = nsid ? NVME_ID_CNS_CTRL_NS_LIST : NVME_ID_CNS_CTRL_LIST;

	return nvme_identify(fd, nsid, (cntid << 16) | cns, data);
}

int nvme_get_log(int fd, __u32 nsid, __u32 cdw10, __u32 data_len, void *data)
{
	struct nvme_admin_cmd cmd = {
		.opcode		= nvme_admin_get_log_page,
		.nsid		= nsid,
		.addr		= (__u64)(uintptr_t) data,
		.data_len	= data_len,
		.cdw10		= cdw10,
	};
	return nvme_submit_admin_passthru(fd, &cmd);
}

int nvme_log(int fd, __u32 nsid, __u8 log_id, __u32 data_len, void *data)
{
	__u32 cdw10 = log_id | ((data_len >> 2) - 1) << 16;

	return nvme_get_log(fd, nsid, cdw10, data_len, data);
}

int nvme_fw_log(int fd, struct nvme_firmware_log_page *fw_log)
{
	return nvme_log(fd, 0xffffffff, NVME_LOG_FW_SLOT, sizeof(*fw_log), fw_log);
}

int nvme_error_log(int fd, __u32 nsid, int entries,
		   struct nvme_error_log_page *err_log)
{
	return nvme_log(fd, nsid, NVME_LOG_ERROR, entries * sizeof(*err_log), err_log);
}

int nvme_smart_log(int fd, __u32 nsid, struct nvme_smart_log *smart_log)
{
	return nvme_log(fd, nsid, NVME_LOG_SMART, sizeof(*smart_log), smart_log);
}

int nvme_intel_smart_log(int fd, __u32 nsid,
			 struct nvme_additional_smart_log *intel_smart_log)
{
	return nvme_log(fd, nsid, 0xca, sizeof(*intel_smart_log),
			intel_smart_log);
}

int nvme_feature(int fd, __u8 opcode, __u32 nsid, __u32 cdw10, __u32 cdw11,
		 __u32 data_len, void *data, __u32 *result)
{
	struct nvme_admin_cmd cmd = {
		.opcode		= opcode,
		.nsid		= nsid,
		.cdw10		= cdw10,
		.cdw11		= cdw11,
		.addr		= (__u64)(uintptr_t) data,
		.data_len	= data_len,
	};
	int err;

	err = nvme_submit_admin_passthru(fd, &cmd);
	if (!err && result)
		*result = cmd.result;
	return err;
}

int nvme_set_feature(int fd, __u32 nsid, __u8 fid, __u32 value, bool save,
		     __u32 data_len, void *data, __u32 *result)
{
	__u32 cdw10 = fid | (save ? 1 << 31 : 0);

	return nvme_feature(fd, nvme_admin_set_features, nsid, cdw10, value,
			    data_len, data, result);
}

int nvme_get_feature(int fd, __u32 nsid, __u8 fid, __u8 sel, __u32 cdw11,
		     __u32 data_len, void *data, __u32 *result)
{
	__u32 cdw10 = fid | sel << 8;

	return nvme_feature(fd, nvme_admin_get_features, nsid, cdw10, cdw11,
			    data_len, data, result);
}

int nvme_format(int fd, __u32 nsid, __u8 lbaf, __u8 ses, __u8 pi,
		__u8 pil, __u8 ms, __u32 timeout)
{
	__u32 cdw10 = lbaf | ms << 4 | pi << 5 | pil << 8 | ses << 9;
	struct nvme_admin_cmd cmd = {
		.opcode		= nvme_admin_format_nvm,
		.nsid		= nsid,
		.cdw10		= cdw10,
		.timeout_ms	= timeout,
	};

	return nvme_submit_admin_passthru(fd, &cmd);
}

int nvme_ns_create(int fd, __u64 nsze, __u64 ncap, __u8 flbas,
		   __u8 dps, __u8 nmic, __u32 *result)
{
	struct nvme_id_ns ns = {
		.nsze		= htole64(nsze),
		.ncap		= htole64(ncap),
		.flbas		= flbas,
		.dps		= dps,
		.nmic		= nmic,
	};
	struct nvme_admin_cmd cmd = {
		.opcode		= nvme_admin_ns_mgmt,
		.addr		= (__u64)(uintptr_t) ((void *)&ns),
		.cdw10		= 0,
		.data_len	= 0x1000,
	};
	int err;

	err = nvme_submit_admin_passthru(fd, &cmd);
	if (!err && result)
		*result = cmd.result;
	return err;
}

int nvme_ns_delete(int fd, __u32 nsid)
{
	struct nvme_admin_cmd cmd = {
		.opcode		= nvme_admin_ns_mgmt,
		.nsid		= nsid,
		.cdw10		= 1,
	};

	return nvme_submit_admin_passthru(fd, &cmd);
}

int nvme_ns_attachment(int fd, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist,
		       bool attach)
{
	int i;
	__u8 buf[0x1000];
	struct nvme_controller_list *cntlist =
					(struct nvme_controller_list *)buf;
	struct nvme_admin_cmd cmd = {
		.opcode		= nvme_admin_ns_attach,
		.nsid		= nsid,
		.addr		= (__u64)(uintptr_t) cntlist,
		.cdw10		= attach ? 0 : 1,
		.data_len	= 0x1000,
	};

	memset(buf, 0, sizeof(buf));
	cntlist->num = num_ctrls;
	for (i = 0; i < cntlist->num; i++)
		cntlist->identifier[i] = htole16((__u16) ctrlist[i]);

	return nvme_submit_admin_passthru(fd, &cmd);
}

int nvme_ns_attach_ctrls(int fd, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist)
{
	return nvme_ns_attachment(fd, nsid, num_ctrls, ctrlist, true);
}

int nvme_ns_detach_ctrls(int fd, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist)
{
	return nvme_ns_attachment(fd, nsid, num_ctrls, ctrlist, false);
}

int nvme_fw_download(int fd, __u32 offset, __u32 data_len, void *data)
{
	struct nvme_admin_cmd cmd = {
		.opcode		= nvme_admin_download_fw,
		.addr		= (__u64)(uintptr_t) data,
		.data_len	= data_len,
		.cdw10		= (data_len >> 2) - 1,
		.cdw11		= offset >> 2,
	};

	return nvme_submit_admin_passthru(fd, &cmd);
}

int nvme_fw_activate(int fd, __u8 slot, __u8 action)
{
	struct nvme_admin_cmd cmd = {
		.opcode		= nvme_admin_activate_fw,
		.cdw10		= (action << 3) | slot,
	};

	return nvme_submit_admin_passthru(fd, &cmd);
}

int nvme_sec_send(int fd, __u32 nsid, __u8 nssf, __u16 spsp,
		  __u8 secp, __u32 tl, __u32 data_len, void *data, __u32 *result)
{
	struct nvme_admin_cmd cmd = {
		.opcode		= nvme_admin_security_send,
		.addr		= (__u64)(uintptr_t) data,
		.data_len	= data_len,
		.nsid		= nsid,
		.cdw10		= secp << 24 | spsp << 8 | nssf,
		.cdw11		= tl,
	};
	int err;

	err = nvme_submit_admin_passthru(fd, &cmd);
	if (!err && result)
		*result = cmd.result;
	return err;
}

int nvme_sec_recv(int fd, __u32 nsid, __u8 nssf, __u16 spsp,
		  __u8 secp, __u32 al, __u32 data_len, void *data, __u32 *result)
{
	struct nvme_admin_cmd cmd = {
		.opcode		= nvme_admin_security_recv,
		.nsid		= nsid,
		.cdw10		= secp << 24 | spsp << 8 | nssf,
		.cdw11		= al,
		.addr		= (__u64)(uintptr_t) data,
		.data_len	= data_len,
	};
	int err;

	err = nvme_submit_admin_passthru(fd, &cmd);
	if (!err && result)
		*result = cmd.result;
	return err;
}