10SN/A/*-
2157SN/A * Copyright (C) 2012 Intel Corporation
30SN/A * All rights reserved.
40SN/A *
50SN/A * Redistribution and use in source and binary forms, with or without
60SN/A * modification, are permitted provided that the following conditions
7157SN/A * are met:
80SN/A * 1. Redistributions of source code must retain the above copyright
9157SN/A *    notice, this list of conditions and the following disclaimer.
100SN/A * 2. Redistributions in binary form must reproduce the above copyright
110SN/A *    notice, this list of conditions and the following disclaimer in the
120SN/A *    documentation and/or other materials provided with the distribution.
130SN/A *
140SN/A * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
150SN/A * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
160SN/A * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
170SN/A * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
180SN/A * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
190SN/A * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
200SN/A * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21157SN/A * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22157SN/A * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23157SN/A * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
240SN/A * SUCH DAMAGE.
250SN/A */
260SN/A
270SN/A#include <sys/cdefs.h>
280SN/A__FBSDID("$FreeBSD$");
290SN/A
300SN/A#include "nvme_private.h"
310SN/A
320SN/Aint
330SN/Anvme_ns_cmd_read(struct nvme_namespace *ns, void *payload, uint64_t lba,
34704Savstepan    uint32_t lba_count, nvme_cb_fn_t cb_fn, void *cb_arg)
350SN/A{
360SN/A	struct nvme_request	*req;
37704Savstepan	struct nvme_command	*cmd;
380SN/A
39704Savstepan	req = nvme_allocate_request_vaddr(payload,
400SN/A	    lba_count*nvme_ns_get_sector_size(ns), cb_fn, cb_arg);
41704Savstepan
420SN/A	if (req == NULL)
430SN/A		return (ENOMEM);
440SN/A	cmd = &req->cmd;
450SN/A	cmd->opc = NVME_OPC_READ;
460SN/A	cmd->nsid = ns->id;
47704Savstepan
48704Savstepan	/* TODO: create a read command data structure */
49704Savstepan	*(uint64_t *)&cmd->cdw10 = lba;
500SN/A	cmd->cdw12 = lba_count-1;
510SN/A
520SN/A	nvme_ctrlr_submit_io_request(ns->ctrlr, req);
530SN/A
540SN/A	return (0);
550SN/A}
560SN/A
57704Savstepanint
580SN/Anvme_ns_cmd_read_bio(struct nvme_namespace *ns, struct bio *bp,
590SN/A    nvme_cb_fn_t cb_fn, void *cb_arg)
600SN/A{
610SN/A	struct nvme_request	*req;
620SN/A	struct nvme_command	*cmd;
63704Savstepan	uint64_t		lba;
64704Savstepan	uint64_t		lba_count;
650SN/A
660SN/A	req = nvme_allocate_request_bio(bp, cb_fn, cb_arg);
670SN/A
680SN/A	if (req == NULL)
690SN/A		return (ENOMEM);
70704Savstepan	cmd = &req->cmd;
71704Savstepan	cmd->opc = NVME_OPC_READ;
72704Savstepan	cmd->nsid = ns->id;
73704Savstepan
74704Savstepan	lba = bp->bio_offset / nvme_ns_get_sector_size(ns);
75704Savstepan	lba_count = bp->bio_bcount / nvme_ns_get_sector_size(ns);
760SN/A
770SN/A	/* TODO: create a read command data structure */
780SN/A	*(uint64_t *)&cmd->cdw10 = lba;
790SN/A	cmd->cdw12 = lba_count-1;
800SN/A
810SN/A	nvme_ctrlr_submit_io_request(ns->ctrlr, req);
820SN/A
830SN/A	return (0);
840SN/A}
850SN/A
860SN/Aint
870SN/Anvme_ns_cmd_write(struct nvme_namespace *ns, void *payload, uint64_t lba,
880SN/A    uint32_t lba_count, nvme_cb_fn_t cb_fn, void *cb_arg)
890SN/A{
900SN/A	struct nvme_request	*req;
910SN/A	struct nvme_command	*cmd;
920SN/A
930SN/A	req = nvme_allocate_request_vaddr(payload,
94	    lba_count*nvme_ns_get_sector_size(ns), cb_fn, cb_arg);
95
96	if (req == NULL)
97		return (ENOMEM);
98
99	cmd = &req->cmd;
100	cmd->opc = NVME_OPC_WRITE;
101	cmd->nsid = ns->id;
102
103	/* TODO: create a write command data structure */
104	*(uint64_t *)&cmd->cdw10 = lba;
105	cmd->cdw12 = lba_count-1;
106
107	nvme_ctrlr_submit_io_request(ns->ctrlr, req);
108
109	return (0);
110}
111
112int
113nvme_ns_cmd_write_bio(struct nvme_namespace *ns, struct bio *bp,
114    nvme_cb_fn_t cb_fn, void *cb_arg)
115{
116	struct nvme_request	*req;
117	struct nvme_command	*cmd;
118	uint64_t		lba;
119	uint64_t		lba_count;
120
121	req = nvme_allocate_request_bio(bp, cb_fn, cb_arg);
122
123	if (req == NULL)
124		return (ENOMEM);
125	cmd = &req->cmd;
126	cmd->opc = NVME_OPC_WRITE;
127	cmd->nsid = ns->id;
128
129	lba = bp->bio_offset / nvme_ns_get_sector_size(ns);
130	lba_count = bp->bio_bcount / nvme_ns_get_sector_size(ns);
131
132	/* TODO: create a write command data structure */
133	*(uint64_t *)&cmd->cdw10 = lba;
134	cmd->cdw12 = lba_count-1;
135
136	nvme_ctrlr_submit_io_request(ns->ctrlr, req);
137
138	return (0);
139}
140
141int
142nvme_ns_cmd_deallocate(struct nvme_namespace *ns, void *payload,
143    uint8_t num_ranges, nvme_cb_fn_t cb_fn, void *cb_arg)
144{
145	struct nvme_request	*req;
146	struct nvme_command	*cmd;
147
148	req = nvme_allocate_request_vaddr(payload,
149	    num_ranges * sizeof(struct nvme_dsm_range), cb_fn, cb_arg);
150
151	if (req == NULL)
152		return (ENOMEM);
153
154	cmd = &req->cmd;
155	cmd->opc = NVME_OPC_DATASET_MANAGEMENT;
156	cmd->nsid = ns->id;
157
158	/* TODO: create a delete command data structure */
159	cmd->cdw10 = num_ranges - 1;
160	cmd->cdw11 = NVME_DSM_ATTR_DEALLOCATE;
161
162	nvme_ctrlr_submit_io_request(ns->ctrlr, req);
163
164	return (0);
165}
166
167int
168nvme_ns_cmd_flush(struct nvme_namespace *ns, nvme_cb_fn_t cb_fn, void *cb_arg)
169{
170	struct nvme_request	*req;
171	struct nvme_command	*cmd;
172
173	req = nvme_allocate_request_null(cb_fn, cb_arg);
174
175	if (req == NULL)
176		return (ENOMEM);
177
178	cmd = &req->cmd;
179	cmd->opc = NVME_OPC_FLUSH;
180	cmd->nsid = ns->id;
181
182	nvme_ctrlr_submit_io_request(ns->ctrlr, req);
183
184	return (0);
185}
186