1301771Simp/*-
2301771Simp * Copyright (c) 2015 Netflix, Inc.
3301771Simp * All rights reserved.
4301771Simp *
5301771Simp * Redistribution and use in source and binary forms, with or without
6301771Simp * modification, are permitted provided that the following conditions
7301771Simp * are met:
8301771Simp * 1. Redistributions of source code must retain the above copyright
9301771Simp *    notice, this list of conditions and the following disclaimer,
10301771Simp *    without modification, immediately at the beginning of the file.
11301771Simp * 2. Redistributions in binary form must reproduce the above copyright
12301771Simp *    notice, this list of conditions and the following disclaimer in the
13301771Simp *    documentation and/or other materials provided with the distribution.
14301771Simp *
15301771Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16301771Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17301771Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18301771Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19301771Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20301771Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21301771Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22301771Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23301771Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24301771Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25301771Simp *
26301771Simp * derived from ata_xpt.c: Copyright (c) 2009 Alexander Motin <mav@FreeBSD.org>
27301771Simp */
28301771Simp
29301771Simp#include <sys/cdefs.h>
30301771Simp__FBSDID("$FreeBSD: stable/11/sys/cam/nvme/nvme_xpt.c 351754 2019-09-03 16:24:44Z mav $");
31301771Simp
32301771Simp#include <sys/param.h>
33301771Simp#include <sys/bus.h>
34301771Simp#include <sys/endian.h>
35301771Simp#include <sys/systm.h>
36301771Simp#include <sys/types.h>
37301771Simp#include <sys/malloc.h>
38301771Simp#include <sys/kernel.h>
39301771Simp#include <sys/time.h>
40301771Simp#include <sys/conf.h>
41301771Simp#include <sys/fcntl.h>
42301771Simp#include <sys/sbuf.h>
43301771Simp
44301771Simp#include <sys/lock.h>
45301771Simp#include <sys/mutex.h>
46301771Simp#include <sys/sysctl.h>
47301771Simp
48301771Simp#include <cam/cam.h>
49301771Simp#include <cam/cam_ccb.h>
50301771Simp#include <cam/cam_queue.h>
51301771Simp#include <cam/cam_periph.h>
52301771Simp#include <cam/cam_sim.h>
53301771Simp#include <cam/cam_xpt.h>
54301771Simp#include <cam/cam_xpt_sim.h>
55301771Simp#include <cam/cam_xpt_periph.h>
56301771Simp#include <cam/cam_xpt_internal.h>
57301771Simp#include <cam/cam_debug.h>
58301771Simp
59301771Simp#include <cam/scsi/scsi_all.h>
60301771Simp#include <cam/scsi/scsi_message.h>
61301771Simp#include <cam/nvme/nvme_all.h>
62301771Simp#include <machine/stdarg.h>	/* for xpt_print below */
63301771Simp#include "opt_cam.h"
64301771Simp
65301771Simpstruct nvme_quirk_entry {
66301771Simp	u_int quirks;
67301771Simp#define CAM_QUIRK_MAXTAGS 1
68301771Simp	u_int mintags;
69301771Simp	u_int maxtags;
70301771Simp};
71301771Simp
72301771Simp/* Not even sure why we need this */
73301771Simpstatic periph_init_t nvme_probe_periph_init;
74301771Simp
75301771Simpstatic struct periph_driver nvme_probe_driver =
76301771Simp{
77301771Simp	nvme_probe_periph_init, "nvme_probe",
78301771Simp	TAILQ_HEAD_INITIALIZER(nvme_probe_driver.units), /* generation */ 0,
79301771Simp	CAM_PERIPH_DRV_EARLY
80301771Simp};
81301771Simp
82301771SimpPERIPHDRIVER_DECLARE(nvme_probe, nvme_probe_driver);
83301771Simp
84301771Simptypedef enum {
85301771Simp	NVME_PROBE_IDENTIFY,
86301771Simp	NVME_PROBE_DONE,
87301771Simp	NVME_PROBE_INVALID,
88301771Simp	NVME_PROBE_RESET
89301771Simp} nvme_probe_action;
90301771Simp
91301771Simpstatic char *nvme_probe_action_text[] = {
92301771Simp	"NVME_PROBE_IDENTIFY",
93301771Simp	"NVME_PROBE_DONE",
94301771Simp	"NVME_PROBE_INVALID",
95301771Simp	"NVME_PROBE_RESET",
96301771Simp};
97301771Simp
98301771Simp#define NVME_PROBE_SET_ACTION(softc, newaction)	\
99301771Simpdo {									\
100301771Simp	char **text;							\
101301771Simp	text = nvme_probe_action_text;					\
102301771Simp	CAM_DEBUG((softc)->periph->path, CAM_DEBUG_PROBE,		\
103301771Simp	    ("Probe %s to %s\n", text[(softc)->action],			\
104301771Simp	    text[(newaction)]));					\
105301771Simp	(softc)->action = (newaction);					\
106301771Simp} while(0)
107301771Simp
108301771Simptypedef enum {
109301771Simp	NVME_PROBE_NO_ANNOUNCE	= 0x04
110301771Simp} nvme_probe_flags;
111301771Simp
112301771Simptypedef struct {
113301771Simp	TAILQ_HEAD(, ccb_hdr) request_ccbs;
114301771Simp	nvme_probe_action	action;
115301771Simp	nvme_probe_flags	flags;
116301771Simp	int		restart;
117301771Simp	struct cam_periph *periph;
118301771Simp} nvme_probe_softc;
119301771Simp
120301771Simpstatic struct nvme_quirk_entry nvme_quirk_table[] =
121301771Simp{
122301771Simp	{
123301771Simp//		{
124301771Simp//		  T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED,
125301771Simp//		  /*vendor*/"*", /*product*/"*", /*revision*/"*"
126301771Simp//		},
127301771Simp		.quirks = 0, .mintags = 0, .maxtags = 0
128301771Simp	},
129301771Simp};
130301771Simp
131301771Simpstatic const int nvme_quirk_table_size =
132301771Simp	sizeof(nvme_quirk_table) / sizeof(*nvme_quirk_table);
133301771Simp
134301771Simpstatic cam_status	nvme_probe_register(struct cam_periph *periph,
135301771Simp				      void *arg);
136301771Simpstatic void	 nvme_probe_schedule(struct cam_periph *nvme_probe_periph);
137301771Simpstatic void	 nvme_probe_start(struct cam_periph *periph, union ccb *start_ccb);
138301771Simpstatic void	 nvme_probe_cleanup(struct cam_periph *periph);
139301778Simp//static void	 nvme_find_quirk(struct cam_ed *device);
140301771Simpstatic void	 nvme_scan_lun(struct cam_periph *periph,
141301771Simp			       struct cam_path *path, cam_flags flags,
142301771Simp			       union ccb *ccb);
143301771Simpstatic struct cam_ed *
144301771Simp		 nvme_alloc_device(struct cam_eb *bus, struct cam_et *target,
145301771Simp				   lun_id_t lun_id);
146301771Simpstatic void	 nvme_device_transport(struct cam_path *path);
147301771Simpstatic void	 nvme_dev_async(u_int32_t async_code,
148301771Simp				struct cam_eb *bus,
149301771Simp				struct cam_et *target,
150301771Simp				struct cam_ed *device,
151301771Simp				void *async_arg);
152301771Simpstatic void	 nvme_action(union ccb *start_ccb);
153301771Simpstatic void	 nvme_announce_periph(struct cam_periph *periph);
154328820Smavstatic void	 nvme_proto_announce(struct cam_ed *device);
155328820Smavstatic void	 nvme_proto_denounce(struct cam_ed *device);
156328820Smavstatic void	 nvme_proto_debug_out(union ccb *ccb);
157301771Simp
158328819Smavstatic struct xpt_xport_ops nvme_xport_ops = {
159301771Simp	.alloc_device = nvme_alloc_device,
160301771Simp	.action = nvme_action,
161301771Simp	.async = nvme_dev_async,
162301771Simp	.announce = nvme_announce_periph,
163301771Simp};
164328819Smav#define NVME_XPT_XPORT(x, X)			\
165328819Smavstatic struct xpt_xport nvme_xport_ ## x = {	\
166328819Smav	.xport = XPORT_ ## X,			\
167328819Smav	.name = #x,				\
168328819Smav	.ops = &nvme_xport_ops,			\
169328819Smav};						\
170328819SmavCAM_XPT_XPORT(nvme_xport_ ## x);
171301771Simp
172328819SmavNVME_XPT_XPORT(nvme, NVME);
173328705Smav
174328819Smav#undef NVME_XPT_XPORT
175301771Simp
176328820Smavstatic struct xpt_proto_ops nvme_proto_ops = {
177328820Smav	.announce = nvme_proto_announce,
178328820Smav	.denounce = nvme_proto_denounce,
179328820Smav	.debug_out = nvme_proto_debug_out,
180328820Smav};
181328820Smavstatic struct xpt_proto nvme_proto = {
182328820Smav	.proto = PROTO_NVME,
183328820Smav	.name = "nvme",
184328820Smav	.ops = &nvme_proto_ops,
185328820Smav};
186328820SmavCAM_XPT_PROTO(nvme_proto);
187328820Smav
188301771Simpstatic void
189301771Simpnvme_probe_periph_init()
190301771Simp{
191328705Smav
192301771Simp}
193301771Simp
194301771Simpstatic cam_status
195301771Simpnvme_probe_register(struct cam_periph *periph, void *arg)
196301771Simp{
197301771Simp	union ccb *request_ccb;	/* CCB representing the probe request */
198301771Simp	cam_status status;
199301771Simp	nvme_probe_softc *softc;
200301771Simp
201301771Simp	request_ccb = (union ccb *)arg;
202301771Simp	if (request_ccb == NULL) {
203301771Simp		printf("nvme_probe_register: no probe CCB, "
204301771Simp		       "can't register device\n");
205301771Simp		return(CAM_REQ_CMP_ERR);
206301771Simp	}
207301771Simp
208301771Simp	softc = (nvme_probe_softc *)malloc(sizeof(*softc), M_CAMXPT, M_ZERO | M_NOWAIT);
209301771Simp
210301771Simp	if (softc == NULL) {
211301771Simp		printf("nvme_probe_register: Unable to probe new device. "
212301771Simp		       "Unable to allocate softc\n");
213301771Simp		return(CAM_REQ_CMP_ERR);
214301771Simp	}
215301771Simp	TAILQ_INIT(&softc->request_ccbs);
216301771Simp	TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h,
217301771Simp			  periph_links.tqe);
218301771Simp	softc->flags = 0;
219301771Simp	periph->softc = softc;
220301771Simp	softc->periph = periph;
221301771Simp	softc->action = NVME_PROBE_INVALID;
222301771Simp	status = cam_periph_acquire(periph);
223301771Simp	if (status != CAM_REQ_CMP) {
224301771Simp		return (status);
225301771Simp	}
226301771Simp	CAM_DEBUG(periph->path, CAM_DEBUG_PROBE, ("Probe started\n"));
227301771Simp
228301771Simp//	nvme_device_transport(periph->path);
229301771Simp	nvme_probe_schedule(periph);
230301771Simp
231301771Simp	return(CAM_REQ_CMP);
232301771Simp}
233301771Simp
234301771Simpstatic void
235301771Simpnvme_probe_schedule(struct cam_periph *periph)
236301771Simp{
237301771Simp	union ccb *ccb;
238301771Simp	nvme_probe_softc *softc;
239301771Simp
240301771Simp	softc = (nvme_probe_softc *)periph->softc;
241301771Simp	ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs);
242301771Simp
243301771Simp	NVME_PROBE_SET_ACTION(softc, NVME_PROBE_IDENTIFY);
244301771Simp
245301771Simp	if (ccb->crcn.flags & CAM_EXPECT_INQ_CHANGE)
246301771Simp		softc->flags |= NVME_PROBE_NO_ANNOUNCE;
247301771Simp	else
248301771Simp		softc->flags &= ~NVME_PROBE_NO_ANNOUNCE;
249301771Simp
250301771Simp	xpt_schedule(periph, CAM_PRIORITY_XPT);
251301771Simp}
252301771Simp
253301771Simpstatic void
254301771Simpnvme_probe_start(struct cam_periph *periph, union ccb *start_ccb)
255301771Simp{
256301771Simp	struct ccb_nvmeio *nvmeio;
257301771Simp	struct ccb_scsiio *csio;
258301771Simp	nvme_probe_softc *softc;
259301771Simp	struct cam_path *path;
260301771Simp	const struct nvme_namespace_data *nvme_data;
261301771Simp	lun_id_t lun;
262301771Simp
263301771Simp	CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("nvme_probe_start\n"));
264301771Simp
265301771Simp	softc = (nvme_probe_softc *)periph->softc;
266301771Simp	path = start_ccb->ccb_h.path;
267301771Simp	nvmeio = &start_ccb->nvmeio;
268301771Simp	csio = &start_ccb->csio;
269301771Simp	nvme_data = periph->path->device->nvme_data;
270301771Simp
271301771Simp	if (softc->restart) {
272301771Simp		softc->restart = 0;
273301771Simp		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED)
274301771Simp			NVME_PROBE_SET_ACTION(softc, NVME_PROBE_RESET);
275301771Simp		else
276301771Simp			NVME_PROBE_SET_ACTION(softc, NVME_PROBE_IDENTIFY);
277301771Simp	}
278301771Simp
279301771Simp	/*
280301771Simp	 * Other transports have to ask their SIM to do a lot of action.
281301771Simp	 * NVMe doesn't, so don't do the dance. Just do things
282301771Simp	 * directly.
283301771Simp	 */
284301771Simp	switch (softc->action) {
285301771Simp	case NVME_PROBE_RESET:
286301771Simp		/* FALLTHROUGH */
287301771Simp	case NVME_PROBE_IDENTIFY:
288301771Simp		nvme_device_transport(path);
289301771Simp		/*
290301771Simp		 * Test for lun == CAM_LUN_WILDCARD is lame, but
291301771Simp		 * appears to be necessary here. XXX
292301771Simp		 */
293301771Simp		lun = xpt_path_lun_id(periph->path);
294301771Simp		if (lun == CAM_LUN_WILDCARD ||
295301771Simp		    periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
296301771Simp			path->device->flags &= ~CAM_DEV_UNCONFIGURED;
297301771Simp			xpt_acquire_device(path->device);
298301771Simp			start_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
299301771Simp			xpt_action(start_ccb);
300301771Simp			xpt_async(AC_FOUND_DEVICE, path, start_ccb);
301301771Simp		}
302301771Simp		NVME_PROBE_SET_ACTION(softc, NVME_PROBE_DONE);
303301771Simp		break;
304301771Simp	default:
305301771Simp		panic("nvme_probe_start: invalid action state 0x%x\n", softc->action);
306301771Simp	}
307301771Simp	/*
308301771Simp	 * Probing is now done. We need to complete any lingering items
309301771Simp	 * in the queue, though there shouldn't be any.
310301771Simp	 */
311301771Simp	xpt_release_ccb(start_ccb);
312301771Simp	CAM_DEBUG(periph->path, CAM_DEBUG_PROBE, ("Probe completed\n"));
313301771Simp	while ((start_ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs))) {
314301771Simp		TAILQ_REMOVE(&softc->request_ccbs,
315301771Simp		    &start_ccb->ccb_h, periph_links.tqe);
316301771Simp		start_ccb->ccb_h.status = CAM_REQ_CMP;
317301771Simp		xpt_done(start_ccb);
318301771Simp	}
319301771Simp	cam_periph_invalidate(periph);
320328705Smav	/* Can't release periph since we hit a (possibly bogus) assertion */
321328705Smav//	cam_periph_release_locked(periph);
322301771Simp}
323301771Simp
324301771Simpstatic void
325301771Simpnvme_probe_cleanup(struct cam_periph *periph)
326301771Simp{
327328705Smav
328301771Simp	free(periph->softc, M_CAMXPT);
329301771Simp}
330301771Simp
331301778Simp#if 0
332301771Simp/* XXX should be used, don't delete */
333301771Simpstatic void
334301771Simpnvme_find_quirk(struct cam_ed *device)
335301771Simp{
336301771Simp	struct nvme_quirk_entry *quirk;
337301771Simp	caddr_t	match;
338301771Simp
339301771Simp	match = cam_quirkmatch((caddr_t)&device->nvme_data,
340301771Simp			       (caddr_t)nvme_quirk_table,
341301771Simp			       nvme_quirk_table_size,
342301771Simp			       sizeof(*nvme_quirk_table), nvme_identify_match);
343301771Simp
344301771Simp	if (match == NULL)
345301771Simp		panic("xpt_find_quirk: device didn't match wildcard entry!!");
346301771Simp
347301771Simp	quirk = (struct nvme_quirk_entry *)match;
348301771Simp	device->quirk = quirk;
349301771Simp	if (quirk->quirks & CAM_QUIRK_MAXTAGS) {
350301771Simp		device->mintags = quirk->mintags;
351301771Simp		device->maxtags = quirk->maxtags;
352301771Simp	}
353301771Simp}
354301778Simp#endif
355301771Simp
356301771Simpstatic void
357301771Simpnvme_scan_lun(struct cam_periph *periph, struct cam_path *path,
358301771Simp	     cam_flags flags, union ccb *request_ccb)
359301771Simp{
360301771Simp	struct ccb_pathinq cpi;
361301771Simp	cam_status status;
362301771Simp	struct cam_periph *old_periph;
363301771Simp	int lock;
364301771Simp
365301771Simp	CAM_DEBUG(path, CAM_DEBUG_TRACE, ("nvme_scan_lun\n"));
366301771Simp
367350804Smav	xpt_path_inq(&cpi, path);
368301771Simp
369301771Simp	if (cpi.ccb_h.status != CAM_REQ_CMP) {
370301771Simp		if (request_ccb != NULL) {
371301771Simp			request_ccb->ccb_h.status = cpi.ccb_h.status;
372301771Simp			xpt_done(request_ccb);
373301771Simp		}
374301771Simp		return;
375301771Simp	}
376301771Simp
377301771Simp	if (xpt_path_lun_id(path) == CAM_LUN_WILDCARD) {
378301771Simp		CAM_DEBUG(path, CAM_DEBUG_TRACE, ("nvme_scan_lun ignoring bus\n"));
379301771Simp		request_ccb->ccb_h.status = CAM_REQ_CMP;	/* XXX signal error ? */
380301771Simp		xpt_done(request_ccb);
381301771Simp		return;
382301771Simp	}
383301771Simp
384301771Simp	lock = (xpt_path_owned(path) == 0);
385301771Simp	if (lock)
386301771Simp		xpt_path_lock(path);
387301771Simp	if ((old_periph = cam_periph_find(path, "nvme_probe")) != NULL) {
388301771Simp		if ((old_periph->flags & CAM_PERIPH_INVALID) == 0) {
389301771Simp			nvme_probe_softc *softc;
390301771Simp
391301771Simp			softc = (nvme_probe_softc *)old_periph->softc;
392301771Simp			TAILQ_INSERT_TAIL(&softc->request_ccbs,
393301771Simp				&request_ccb->ccb_h, periph_links.tqe);
394301771Simp			softc->restart = 1;
395301771Simp			CAM_DEBUG(path, CAM_DEBUG_TRACE,
396301771Simp			    ("restarting nvme_probe device\n"));
397301771Simp		} else {
398301771Simp			request_ccb->ccb_h.status = CAM_REQ_CMP_ERR;
399301771Simp			CAM_DEBUG(path, CAM_DEBUG_TRACE,
400301771Simp			    ("Failing to restart nvme_probe device\n"));
401301771Simp			xpt_done(request_ccb);
402301771Simp		}
403301771Simp	} else {
404301771Simp		CAM_DEBUG(path, CAM_DEBUG_TRACE,
405301771Simp		    ("Adding nvme_probe device\n"));
406301771Simp		status = cam_periph_alloc(nvme_probe_register, NULL, nvme_probe_cleanup,
407301771Simp					  nvme_probe_start, "nvme_probe",
408301771Simp					  CAM_PERIPH_BIO,
409301771Simp					  request_ccb->ccb_h.path, NULL, 0,
410301771Simp					  request_ccb);
411301771Simp
412301771Simp		if (status != CAM_REQ_CMP) {
413301771Simp			xpt_print(path, "xpt_scan_lun: cam_alloc_periph "
414301771Simp			    "returned an error, can't continue probe\n");
415301771Simp			request_ccb->ccb_h.status = status;
416301771Simp			xpt_done(request_ccb);
417301771Simp		}
418301771Simp	}
419301771Simp	if (lock)
420301771Simp		xpt_path_unlock(path);
421301771Simp}
422301771Simp
423301771Simpstatic struct cam_ed *
424301771Simpnvme_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id)
425301771Simp{
426301771Simp	struct nvme_quirk_entry *quirk;
427301771Simp	struct cam_ed *device;
428301771Simp
429301771Simp	device = xpt_alloc_device(bus, target, lun_id);
430301771Simp	if (device == NULL)
431301771Simp		return (NULL);
432301771Simp
433301771Simp	/*
434301771Simp	 * Take the default quirk entry until we have inquiry
435301771Simp	 * data from nvme and can determine a better quirk to use.
436301771Simp	 */
437301771Simp	quirk = &nvme_quirk_table[nvme_quirk_table_size - 1];
438301771Simp	device->quirk = (void *)quirk;
439301771Simp	device->mintags = 0;
440301771Simp	device->maxtags = 0;
441301771Simp	device->inq_flags = 0;
442301771Simp	device->queue_flags = 0;
443301771Simp	device->device_id = NULL;	/* XXX Need to set this somewhere */
444301771Simp	device->device_id_len = 0;
445301771Simp	device->serial_num = NULL;	/* XXX Need to set this somewhere */
446301771Simp	device->serial_num_len = 0;
447301771Simp	return (device);
448301771Simp}
449301771Simp
450301771Simpstatic void
451301771Simpnvme_device_transport(struct cam_path *path)
452301771Simp{
453301771Simp	struct ccb_pathinq cpi;
454301771Simp	struct ccb_trans_settings cts;
455301771Simp	/* XXX get data from nvme namespace and other info ??? */
456301771Simp
457301771Simp	/* Get transport information from the SIM */
458350804Smav	xpt_path_inq(&cpi, path);
459301771Simp
460301771Simp	path->device->transport = cpi.transport;
461301771Simp	path->device->transport_version = cpi.transport_version;
462301771Simp
463301771Simp	path->device->protocol = cpi.protocol;
464301771Simp	path->device->protocol_version = cpi.protocol_version;
465301771Simp
466301771Simp	/* Tell the controller what we think */
467301771Simp	xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
468301771Simp	cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
469301771Simp	cts.type = CTS_TYPE_CURRENT_SETTINGS;
470301771Simp	cts.transport = path->device->transport;
471301771Simp	cts.transport_version = path->device->transport_version;
472301771Simp	cts.protocol = path->device->protocol;
473301771Simp	cts.protocol_version = path->device->protocol_version;
474301771Simp	cts.proto_specific.valid = 0;
475301771Simp	cts.xport_specific.valid = 0;
476301771Simp	xpt_action((union ccb *)&cts);
477301771Simp}
478301771Simp
479301771Simpstatic void
480301771Simpnvme_dev_advinfo(union ccb *start_ccb)
481301771Simp{
482301771Simp	struct cam_ed *device;
483301771Simp	struct ccb_dev_advinfo *cdai;
484351754Smav	off_t amt;
485301771Simp
486351754Smav	xpt_path_assert(start_ccb->ccb_h.path, MA_OWNED);
487301771Simp	start_ccb->ccb_h.status = CAM_REQ_INVALID;
488301771Simp	device = start_ccb->ccb_h.path->device;
489301771Simp	cdai = &start_ccb->cdai;
490301771Simp	switch(cdai->buftype) {
491301771Simp	case CDAI_TYPE_SCSI_DEVID:
492301771Simp		if (cdai->flags & CDAI_FLAG_STORE)
493301771Simp			return;
494301771Simp		cdai->provsiz = device->device_id_len;
495301771Simp		if (device->device_id_len == 0)
496301771Simp			break;
497301771Simp		amt = device->device_id_len;
498301771Simp		if (cdai->provsiz > cdai->bufsiz)
499301771Simp			amt = cdai->bufsiz;
500301771Simp		memcpy(cdai->buf, device->device_id, amt);
501301771Simp		break;
502301771Simp	case CDAI_TYPE_SERIAL_NUM:
503301771Simp		if (cdai->flags & CDAI_FLAG_STORE)
504301771Simp			return;
505301771Simp		cdai->provsiz = device->serial_num_len;
506301771Simp		if (device->serial_num_len == 0)
507301771Simp			break;
508301771Simp		amt = device->serial_num_len;
509301771Simp		if (cdai->provsiz > cdai->bufsiz)
510301771Simp			amt = cdai->bufsiz;
511301771Simp		memcpy(cdai->buf, device->serial_num, amt);
512301771Simp		break;
513301771Simp	case CDAI_TYPE_PHYS_PATH:
514301771Simp		if (cdai->flags & CDAI_FLAG_STORE) {
515301771Simp			if (device->physpath != NULL)
516301771Simp				free(device->physpath, M_CAMXPT);
517301771Simp			device->physpath_len = cdai->bufsiz;
518301771Simp			/* Clear existing buffer if zero length */
519301771Simp			if (cdai->bufsiz == 0)
520301771Simp				break;
521301771Simp			device->physpath = malloc(cdai->bufsiz, M_CAMXPT, M_NOWAIT);
522301771Simp			if (device->physpath == NULL) {
523301771Simp				start_ccb->ccb_h.status = CAM_REQ_ABORTED;
524301771Simp				return;
525301771Simp			}
526301771Simp			memcpy(device->physpath, cdai->buf, cdai->bufsiz);
527301771Simp		} else {
528301771Simp			cdai->provsiz = device->physpath_len;
529301771Simp			if (device->physpath_len == 0)
530301771Simp				break;
531301771Simp			amt = device->physpath_len;
532301771Simp			if (cdai->provsiz > cdai->bufsiz)
533301771Simp				amt = cdai->bufsiz;
534301771Simp			memcpy(cdai->buf, device->physpath, amt);
535301771Simp		}
536301771Simp		break;
537328735Smav	case CDAI_TYPE_NVME_CNTRL:
538328735Smav		if (cdai->flags & CDAI_FLAG_STORE)
539328735Smav			return;
540328735Smav		amt = sizeof(struct nvme_controller_data);
541328735Smav		cdai->provsiz = amt;
542328735Smav		if (amt > cdai->bufsiz)
543328735Smav			amt = cdai->bufsiz;
544328735Smav		memcpy(cdai->buf, device->nvme_cdata, amt);
545328735Smav		break;
546328735Smav	case CDAI_TYPE_NVME_NS:
547328735Smav		if (cdai->flags & CDAI_FLAG_STORE)
548328735Smav			return;
549328735Smav		amt = sizeof(struct nvme_namespace_data);
550328735Smav		cdai->provsiz = amt;
551328735Smav		if (amt > cdai->bufsiz)
552328735Smav			amt = cdai->bufsiz;
553328735Smav		memcpy(cdai->buf, device->nvme_data, amt);
554328735Smav		break;
555301771Simp	default:
556301771Simp		return;
557301771Simp	}
558301771Simp	start_ccb->ccb_h.status = CAM_REQ_CMP;
559301771Simp
560301771Simp	if (cdai->flags & CDAI_FLAG_STORE) {
561301771Simp		xpt_async(AC_ADVINFO_CHANGED, start_ccb->ccb_h.path,
562301771Simp			  (void *)(uintptr_t)cdai->buftype);
563301771Simp	}
564301771Simp}
565301771Simp
566301771Simpstatic void
567301771Simpnvme_action(union ccb *start_ccb)
568301771Simp{
569301771Simp	CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE,
570301771Simp	    ("nvme_action: func= %#x\n", start_ccb->ccb_h.func_code));
571301771Simp
572301771Simp	switch (start_ccb->ccb_h.func_code) {
573301771Simp	case XPT_SCAN_BUS:
574301771Simp	case XPT_SCAN_TGT:
575301771Simp	case XPT_SCAN_LUN:
576301771Simp		nvme_scan_lun(start_ccb->ccb_h.path->periph,
577301771Simp			      start_ccb->ccb_h.path, start_ccb->crcn.flags,
578301771Simp			      start_ccb);
579301771Simp		break;
580301771Simp	case XPT_DEV_ADVINFO:
581301771Simp		nvme_dev_advinfo(start_ccb);
582301771Simp		break;
583301771Simp
584301771Simp	default:
585301771Simp		xpt_action_default(start_ccb);
586301771Simp		break;
587301771Simp	}
588301771Simp}
589301771Simp
590301771Simp/*
591301771Simp * Handle any per-device event notifications that require action by the XPT.
592301771Simp */
593301771Simpstatic void
594301771Simpnvme_dev_async(u_int32_t async_code, struct cam_eb *bus, struct cam_et *target,
595301771Simp	      struct cam_ed *device, void *async_arg)
596301771Simp{
597301771Simp
598301771Simp	/*
599301771Simp	 * We only need to handle events for real devices.
600301771Simp	 */
601301771Simp	if (target->target_id == CAM_TARGET_WILDCARD
602301771Simp	 || device->lun_id == CAM_LUN_WILDCARD)
603301771Simp		return;
604301771Simp
605301771Simp	if (async_code == AC_LOST_DEVICE &&
606301771Simp	    (device->flags & CAM_DEV_UNCONFIGURED) == 0) {
607301771Simp		device->flags |= CAM_DEV_UNCONFIGURED;
608301771Simp		xpt_release_device(device);
609301771Simp	}
610301771Simp}
611301771Simp
612301771Simpstatic void
613301771Simpnvme_announce_periph(struct cam_periph *periph)
614301771Simp{
615301771Simp	struct	ccb_pathinq cpi;
616301771Simp	struct	ccb_trans_settings cts;
617301771Simp	struct	cam_path *path = periph->path;
618301771Simp
619301771Simp	cam_periph_assert(periph, MA_OWNED);
620301771Simp
621301771Simp	xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
622301771Simp	cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
623301771Simp	cts.type = CTS_TYPE_CURRENT_SETTINGS;
624301771Simp	xpt_action((union ccb*)&cts);
625301771Simp	if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
626301771Simp		return;
627301771Simp	/* Ask the SIM for its base transfer speed */
628350804Smav	xpt_path_inq(&cpi, periph->path);
629301771Simp	/* XXX NVME STUFF HERE */
630301771Simp	printf("\n");
631301771Simp}
632328820Smav
633328820Smavstatic void
634328820Smavnvme_proto_announce(struct cam_ed *device)
635328820Smav{
636335166Smav
637328820Smav	nvme_print_ident(device->nvme_cdata, device->nvme_data);
638328820Smav}
639328820Smav
640328820Smavstatic void
641328820Smavnvme_proto_denounce(struct cam_ed *device)
642328820Smav{
643335166Smav
644328820Smav	nvme_print_ident(device->nvme_cdata, device->nvme_data);
645328820Smav}
646328820Smav
647328820Smavstatic void
648328820Smavnvme_proto_debug_out(union ccb *ccb)
649328820Smav{
650328820Smav	char cdb_str[(sizeof(struct nvme_command) * 3) + 1];
651328820Smav
652328820Smav	if (ccb->ccb_h.func_code != XPT_NVME_IO)
653328820Smav		return;
654328820Smav
655328820Smav	CAM_DEBUG(ccb->ccb_h.path,
656328820Smav	    CAM_DEBUG_CDB,("%s. NCB: %s\n", nvme_op_string(&ccb->nvmeio.cmd),
657328820Smav		nvme_cmd_string(&ccb->nvmeio.cmd, cdb_str, sizeof(cdb_str))));
658328820Smav}
659328820Smav
660