1195534Sscottl/*-
2195534Sscottl * Copyright (c) 2009 Alexander Motin <mav@FreeBSD.org>
3195534Sscottl * All rights reserved.
4195534Sscottl *
5195534Sscottl * Redistribution and use in source and binary forms, with or without
6195534Sscottl * modification, are permitted provided that the following conditions
7195534Sscottl * are met:
8195534Sscottl * 1. Redistributions of source code must retain the above copyright
9195534Sscottl *    notice, this list of conditions and the following disclaimer,
10195534Sscottl *    without modification, immediately at the beginning of the file.
11195534Sscottl * 2. Redistributions in binary form must reproduce the above copyright
12195534Sscottl *    notice, this list of conditions and the following disclaimer in the
13195534Sscottl *    documentation and/or other materials provided with the distribution.
14195534Sscottl *
15195534Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16195534Sscottl * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17195534Sscottl * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18195534Sscottl * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19195534Sscottl * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20195534Sscottl * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21195534Sscottl * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22195534Sscottl * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23195534Sscottl * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24195534Sscottl * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25195534Sscottl */
26195534Sscottl
27195534Sscottl#include <sys/cdefs.h>
28195534Sscottl__FBSDID("$FreeBSD: stable/11/sys/cam/ata/ata_xpt.c 351754 2019-09-03 16:24:44Z mav $");
29195534Sscottl
30195534Sscottl#include <sys/param.h>
31195534Sscottl#include <sys/bus.h>
32195534Sscottl#include <sys/endian.h>
33195534Sscottl#include <sys/systm.h>
34195534Sscottl#include <sys/types.h>
35195534Sscottl#include <sys/malloc.h>
36195534Sscottl#include <sys/kernel.h>
37195534Sscottl#include <sys/time.h>
38195534Sscottl#include <sys/conf.h>
39195534Sscottl#include <sys/fcntl.h>
40195534Sscottl#include <sys/sbuf.h>
41195534Sscottl
42307606Ssephe#include <sys/eventhandler.h>
43195534Sscottl#include <sys/lock.h>
44195534Sscottl#include <sys/mutex.h>
45195534Sscottl#include <sys/sysctl.h>
46195534Sscottl
47195534Sscottl#include <cam/cam.h>
48195534Sscottl#include <cam/cam_ccb.h>
49195534Sscottl#include <cam/cam_queue.h>
50195534Sscottl#include <cam/cam_periph.h>
51195534Sscottl#include <cam/cam_sim.h>
52195534Sscottl#include <cam/cam_xpt.h>
53195534Sscottl#include <cam/cam_xpt_sim.h>
54195534Sscottl#include <cam/cam_xpt_periph.h>
55195534Sscottl#include <cam/cam_xpt_internal.h>
56195534Sscottl#include <cam/cam_debug.h>
57195534Sscottl
58195534Sscottl#include <cam/scsi/scsi_all.h>
59195534Sscottl#include <cam/scsi/scsi_message.h>
60195534Sscottl#include <cam/ata/ata_all.h>
61195534Sscottl#include <machine/stdarg.h>	/* for xpt_print below */
62195534Sscottl#include "opt_cam.h"
63195534Sscottl
64199178Smavstruct ata_quirk_entry {
65195534Sscottl	struct scsi_inquiry_pattern inq_pat;
66195534Sscottl	u_int8_t quirks;
67199178Smav#define	CAM_QUIRK_MAXTAGS	0x01
68236234Smav	u_int mintags;
69195534Sscottl	u_int maxtags;
70195534Sscottl};
71195534Sscottl
72195534Sscottlstatic periph_init_t probe_periph_init;
73195534Sscottl
74195534Sscottlstatic struct periph_driver probe_driver =
75195534Sscottl{
76195653Smav	probe_periph_init, "aprobe",
77198708Smav	TAILQ_HEAD_INITIALIZER(probe_driver.units), /* generation */ 0,
78198708Smav	CAM_PERIPH_DRV_EARLY
79195534Sscottl};
80195534Sscottl
81195653SmavPERIPHDRIVER_DECLARE(aprobe, probe_driver);
82195534Sscottl
83195534Sscottltypedef enum {
84195534Sscottl	PROBE_RESET,
85195534Sscottl	PROBE_IDENTIFY,
86203421Smav	PROBE_SPINUP,
87195534Sscottl	PROBE_SETMODE,
88207499Smav	PROBE_SETPM,
89207499Smav	PROBE_SETAPST,
90207499Smav	PROBE_SETDMAAA,
91220602Smav	PROBE_SETAN,
92198708Smav	PROBE_SET_MULTI,
93195534Sscottl	PROBE_INQUIRY,
94195534Sscottl	PROBE_FULL_INQUIRY,
95195534Sscottl	PROBE_PM_PID,
96195534Sscottl	PROBE_PM_PRV,
97235897Smav	PROBE_IDENTIFY_SES,
98235897Smav	PROBE_IDENTIFY_SAFTE,
99236613Smav	PROBE_DONE,
100195534Sscottl	PROBE_INVALID
101195534Sscottl} probe_action;
102195534Sscottl
103195534Sscottlstatic char *probe_action_text[] = {
104195534Sscottl	"PROBE_RESET",
105195534Sscottl	"PROBE_IDENTIFY",
106203421Smav	"PROBE_SPINUP",
107195534Sscottl	"PROBE_SETMODE",
108207499Smav	"PROBE_SETPM",
109207499Smav	"PROBE_SETAPST",
110207499Smav	"PROBE_SETDMAAA",
111220602Smav	"PROBE_SETAN",
112198708Smav	"PROBE_SET_MULTI",
113195534Sscottl	"PROBE_INQUIRY",
114195534Sscottl	"PROBE_FULL_INQUIRY",
115195534Sscottl	"PROBE_PM_PID",
116195534Sscottl	"PROBE_PM_PRV",
117235897Smav	"PROBE_IDENTIFY_SES",
118235897Smav	"PROBE_IDENTIFY_SAFTE",
119236613Smav	"PROBE_DONE",
120195534Sscottl	"PROBE_INVALID"
121195534Sscottl};
122195534Sscottl
123195534Sscottl#define PROBE_SET_ACTION(softc, newaction)	\
124195534Sscottldo {									\
125195534Sscottl	char **text;							\
126195534Sscottl	text = probe_action_text;					\
127236613Smav	CAM_DEBUG((softc)->periph->path, CAM_DEBUG_PROBE,		\
128195534Sscottl	    ("Probe %s to %s\n", text[(softc)->action],			\
129195534Sscottl	    text[(newaction)]));					\
130195534Sscottl	(softc)->action = (newaction);					\
131195534Sscottl} while(0)
132195534Sscottl
133195534Sscottltypedef enum {
134195534Sscottl	PROBE_NO_ANNOUNCE	= 0x04
135195534Sscottl} probe_flags;
136195534Sscottl
137195534Sscottltypedef struct {
138195534Sscottl	TAILQ_HEAD(, ccb_hdr) request_ccbs;
139203385Smav	struct ata_params	ident_data;
140195534Sscottl	probe_action	action;
141195534Sscottl	probe_flags	flags;
142195534Sscottl	uint32_t	pm_pid;
143195534Sscottl	uint32_t	pm_prv;
144203108Smav	int		restart;
145203421Smav	int		spinup;
146209744Smav	int		faults;
147207499Smav	u_int		caps;
148195534Sscottl	struct cam_periph *periph;
149195534Sscottl} probe_softc;
150195534Sscottl
151199178Smavstatic struct ata_quirk_entry ata_quirk_table[] =
152195534Sscottl{
153195534Sscottl	{
154195534Sscottl		/* Default tagged queuing parameters for all devices */
155195534Sscottl		{
156195534Sscottl		  T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED,
157195534Sscottl		  /*vendor*/"*", /*product*/"*", /*revision*/"*"
158195534Sscottl		},
159236234Smav		/*quirks*/0, /*mintags*/0, /*maxtags*/0
160195534Sscottl	},
161195534Sscottl};
162195534Sscottl
163195534Sscottlstatic cam_status	proberegister(struct cam_periph *periph,
164195534Sscottl				      void *arg);
165195534Sscottlstatic void	 probeschedule(struct cam_periph *probe_periph);
166195534Sscottlstatic void	 probestart(struct cam_periph *periph, union ccb *start_ccb);
167236437Smavstatic void	 proberequestdefaultnegotiation(struct cam_periph *periph);
168195534Sscottlstatic void	 probedone(struct cam_periph *periph, union ccb *done_ccb);
169195534Sscottlstatic void	 probecleanup(struct cam_periph *periph);
170199178Smavstatic void	 ata_find_quirk(struct cam_ed *device);
171195534Sscottlstatic void	 ata_scan_bus(struct cam_periph *periph, union ccb *ccb);
172195534Sscottlstatic void	 ata_scan_lun(struct cam_periph *periph,
173195534Sscottl			       struct cam_path *path, cam_flags flags,
174195534Sscottl			       union ccb *ccb);
175195534Sscottlstatic void	 xptscandone(struct cam_periph *periph, union ccb *done_ccb);
176195534Sscottlstatic struct cam_ed *
177195534Sscottl		 ata_alloc_device(struct cam_eb *bus, struct cam_et *target,
178195534Sscottl				   lun_id_t lun_id);
179195534Sscottlstatic void	 ata_device_transport(struct cam_path *path);
180236437Smavstatic void	 ata_get_transfer_settings(struct ccb_trans_settings *cts);
181199178Smavstatic void	 ata_set_transfer_settings(struct ccb_trans_settings *cts,
182256843Smav					    struct cam_path *path,
183195534Sscottl					    int async_update);
184195534Sscottlstatic void	 ata_dev_async(u_int32_t async_code,
185195534Sscottl				struct cam_eb *bus,
186195534Sscottl				struct cam_et *target,
187195534Sscottl				struct cam_ed *device,
188195534Sscottl				void *async_arg);
189195534Sscottlstatic void	 ata_action(union ccb *start_ccb);
190204220Smavstatic void	 ata_announce_periph(struct cam_periph *periph);
191328820Smavstatic void	 ata_proto_announce(struct cam_ed *device);
192328820Smavstatic void	 ata_proto_denounce(struct cam_ed *device);
193328820Smavstatic void	 ata_proto_debug_out(union ccb *ccb);
194328820Smavstatic void	 semb_proto_announce(struct cam_ed *device);
195328820Smavstatic void	 semb_proto_denounce(struct cam_ed *device);
196195534Sscottl
197230912Smavstatic int ata_dma = 1;
198230912Smavstatic int atapi_dma = 1;
199230912Smav
200230912SmavTUNABLE_INT("hw.ata.ata_dma", &ata_dma);
201230912SmavTUNABLE_INT("hw.ata.atapi_dma", &atapi_dma);
202230912Smav
203328819Smavstatic struct xpt_xport_ops ata_xport_ops = {
204195534Sscottl	.alloc_device = ata_alloc_device,
205195534Sscottl	.action = ata_action,
206195534Sscottl	.async = ata_dev_async,
207204220Smav	.announce = ata_announce_periph,
208195534Sscottl};
209328819Smav#define ATA_XPT_XPORT(x, X)			\
210328819Smavstatic struct xpt_xport ata_xport_ ## x = {	\
211328819Smav	.xport = XPORT_ ## X,			\
212328819Smav	.name = #x,				\
213328819Smav	.ops = &ata_xport_ops,			\
214328819Smav};						\
215328819SmavCAM_XPT_XPORT(ata_xport_ ## x);
216195534Sscottl
217328819SmavATA_XPT_XPORT(ata, ATA);
218328819SmavATA_XPT_XPORT(sata, SATA);
219195534Sscottl
220328819Smav#undef ATA_XPORT_XPORT
221328819Smav
222328820Smavstatic struct xpt_proto_ops ata_proto_ops_ata = {
223328820Smav	.announce = ata_proto_announce,
224328820Smav	.denounce = ata_proto_denounce,
225328820Smav	.debug_out = ata_proto_debug_out,
226328820Smav};
227328820Smavstatic struct xpt_proto ata_proto_ata = {
228328820Smav	.proto = PROTO_ATA,
229328820Smav	.name = "ata",
230328820Smav	.ops = &ata_proto_ops_ata,
231328820Smav};
232328820Smav
233328820Smavstatic struct xpt_proto_ops ata_proto_ops_satapm = {
234328820Smav	.announce = ata_proto_announce,
235328820Smav	.denounce = ata_proto_denounce,
236328820Smav	.debug_out = ata_proto_debug_out,
237328820Smav};
238328820Smavstatic struct xpt_proto ata_proto_satapm = {
239328820Smav	.proto = PROTO_SATAPM,
240328820Smav	.name = "satapm",
241328820Smav	.ops = &ata_proto_ops_satapm,
242328820Smav};
243328820Smav
244328820Smavstatic struct xpt_proto_ops ata_proto_ops_semb = {
245328820Smav	.announce = semb_proto_announce,
246328820Smav	.denounce = semb_proto_denounce,
247328820Smav	.debug_out = ata_proto_debug_out,
248328820Smav};
249328820Smavstatic struct xpt_proto ata_proto_semb = {
250328820Smav	.proto = PROTO_SEMB,
251328820Smav	.name = "semb",
252328820Smav	.ops = &ata_proto_ops_semb,
253328820Smav};
254328820Smav
255328820SmavCAM_XPT_PROTO(ata_proto_ata);
256328820SmavCAM_XPT_PROTO(ata_proto_satapm);
257328820SmavCAM_XPT_PROTO(ata_proto_semb);
258328820Smav
259195534Sscottlstatic void
260195534Sscottlprobe_periph_init()
261195534Sscottl{
262195534Sscottl}
263195534Sscottl
264195534Sscottlstatic cam_status
265195534Sscottlproberegister(struct cam_periph *periph, void *arg)
266195534Sscottl{
267195534Sscottl	union ccb *request_ccb;	/* CCB representing the probe request */
268195534Sscottl	cam_status status;
269195534Sscottl	probe_softc *softc;
270195534Sscottl
271195534Sscottl	request_ccb = (union ccb *)arg;
272195534Sscottl	if (request_ccb == NULL) {
273195534Sscottl		printf("proberegister: no probe CCB, "
274195534Sscottl		       "can't register device\n");
275195534Sscottl		return(CAM_REQ_CMP_ERR);
276195534Sscottl	}
277195534Sscottl
278203421Smav	softc = (probe_softc *)malloc(sizeof(*softc), M_CAMXPT, M_ZERO | M_NOWAIT);
279195534Sscottl
280195534Sscottl	if (softc == NULL) {
281195534Sscottl		printf("proberegister: Unable to probe new device. "
282195534Sscottl		       "Unable to allocate softc\n");
283195534Sscottl		return(CAM_REQ_CMP_ERR);
284195534Sscottl	}
285195534Sscottl	TAILQ_INIT(&softc->request_ccbs);
286195534Sscottl	TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h,
287195534Sscottl			  periph_links.tqe);
288195534Sscottl	softc->flags = 0;
289195534Sscottl	periph->softc = softc;
290195534Sscottl	softc->periph = periph;
291195534Sscottl	softc->action = PROBE_INVALID;
292195534Sscottl	status = cam_periph_acquire(periph);
293195534Sscottl	if (status != CAM_REQ_CMP) {
294195534Sscottl		return (status);
295195534Sscottl	}
296236613Smav	CAM_DEBUG(periph->path, CAM_DEBUG_PROBE, ("Probe started\n"));
297256843Smav	ata_device_transport(periph->path);
298195534Sscottl	probeschedule(periph);
299195534Sscottl	return(CAM_REQ_CMP);
300195534Sscottl}
301195534Sscottl
302195534Sscottlstatic void
303195534Sscottlprobeschedule(struct cam_periph *periph)
304195534Sscottl{
305195534Sscottl	union ccb *ccb;
306195534Sscottl	probe_softc *softc;
307195534Sscottl
308195534Sscottl	softc = (probe_softc *)periph->softc;
309195534Sscottl	ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs);
310195534Sscottl
311198389Smav	if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) ||
312235897Smav	    periph->path->device->protocol == PROTO_SATAPM ||
313235897Smav	    periph->path->device->protocol == PROTO_SEMB)
314195534Sscottl		PROBE_SET_ACTION(softc, PROBE_RESET);
315195534Sscottl	else
316195534Sscottl		PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
317195534Sscottl
318195534Sscottl	if (ccb->crcn.flags & CAM_EXPECT_INQ_CHANGE)
319195534Sscottl		softc->flags |= PROBE_NO_ANNOUNCE;
320195534Sscottl	else
321195534Sscottl		softc->flags &= ~PROBE_NO_ANNOUNCE;
322195534Sscottl
323203108Smav	xpt_schedule(periph, CAM_PRIORITY_XPT);
324195534Sscottl}
325195534Sscottl
326195534Sscottlstatic void
327195534Sscottlprobestart(struct cam_periph *periph, union ccb *start_ccb)
328195534Sscottl{
329199747Smav	struct ccb_trans_settings cts;
330195534Sscottl	struct ccb_ataio *ataio;
331195534Sscottl	struct ccb_scsiio *csio;
332195534Sscottl	probe_softc *softc;
333198708Smav	struct cam_path *path;
334198708Smav	struct ata_params *ident_buf;
335350805Smav	u_int oif;
336195534Sscottl
337195534Sscottl	CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probestart\n"));
338195534Sscottl
339195534Sscottl	softc = (probe_softc *)periph->softc;
340198708Smav	path = start_ccb->ccb_h.path;
341195534Sscottl	ataio = &start_ccb->ataio;
342195534Sscottl	csio = &start_ccb->csio;
343198708Smav	ident_buf = &periph->path->device->ident_data;
344195534Sscottl
345203108Smav	if (softc->restart) {
346203108Smav		softc->restart = 0;
347203108Smav		if ((path->device->flags & CAM_DEV_UNCONFIGURED) ||
348235897Smav		    path->device->protocol == PROTO_SATAPM ||
349235897Smav		    path->device->protocol == PROTO_SEMB)
350203108Smav			softc->action = PROBE_RESET;
351203108Smav		else
352203108Smav			softc->action = PROBE_IDENTIFY;
353203108Smav	}
354195534Sscottl	switch (softc->action) {
355195534Sscottl	case PROBE_RESET:
356195534Sscottl		cam_fill_ataio(ataio,
357195534Sscottl		      0,
358195534Sscottl		      probedone,
359195534Sscottl		      /*flags*/CAM_DIR_NONE,
360198389Smav		      0,
361195534Sscottl		      /*data_ptr*/NULL,
362195534Sscottl		      /*dxfer_len*/0,
363203108Smav		      15 * 1000);
364195534Sscottl		ata_reset_cmd(ataio);
365195534Sscottl		break;
366195534Sscottl	case PROBE_IDENTIFY:
367195534Sscottl		cam_fill_ataio(ataio,
368195534Sscottl		      1,
369195534Sscottl		      probedone,
370195534Sscottl		      /*flags*/CAM_DIR_IN,
371198389Smav		      0,
372203385Smav		      /*data_ptr*/(u_int8_t *)&softc->ident_data,
373203385Smav		      /*dxfer_len*/sizeof(softc->ident_data),
374195534Sscottl		      30 * 1000);
375350805Smav		if (path->device->protocol == PROTO_ATA)
376196659Smav			ata_28bit_cmd(ataio, ATA_ATA_IDENTIFY, 0, 0, 0);
377195534Sscottl		else
378196659Smav			ata_28bit_cmd(ataio, ATA_ATAPI_IDENTIFY, 0, 0, 0);
379195534Sscottl		break;
380203421Smav	case PROBE_SPINUP:
381203421Smav		if (bootverbose)
382203421Smav			xpt_print(path, "Spinning up device\n");
383203421Smav		cam_fill_ataio(ataio,
384203421Smav		      1,
385203421Smav		      probedone,
386203421Smav		      /*flags*/CAM_DIR_NONE | CAM_HIGH_POWER,
387203421Smav		      0,
388203421Smav		      /*data_ptr*/NULL,
389203421Smav		      /*dxfer_len*/0,
390203421Smav		      30 * 1000);
391203421Smav		ata_28bit_cmd(ataio, ATA_SETFEATURES, ATA_SF_PUIS_SPINUP, 0, 0);
392203421Smav		break;
393195534Sscottl	case PROBE_SETMODE:
394199747Smav	{
395199747Smav		int mode, wantmode;
396199747Smav
397199747Smav		mode = 0;
398199747Smav		/* Fetch user modes from SIM. */
399199747Smav		bzero(&cts, sizeof(cts));
400203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
401199747Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
402199747Smav		cts.type = CTS_TYPE_USER_SETTINGS;
403199747Smav		xpt_action((union ccb *)&cts);
404199747Smav		if (path->device->transport == XPORT_ATA) {
405199747Smav			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_MODE)
406199747Smav				mode = cts.xport_specific.ata.mode;
407199747Smav		} else {
408199799Smav			if (cts.xport_specific.sata.valid & CTS_SATA_VALID_MODE)
409199747Smav				mode = cts.xport_specific.sata.mode;
410199747Smav		}
411350805Smav		if (path->device->protocol == PROTO_ATA) {
412230912Smav			if (ata_dma == 0 && (mode == 0 || mode > ATA_PIO_MAX))
413230912Smav				mode = ATA_PIO_MAX;
414230912Smav		} else {
415230912Smav			if (atapi_dma == 0 && (mode == 0 || mode > ATA_PIO_MAX))
416230912Smav				mode = ATA_PIO_MAX;
417230912Smav		}
418199747Smavnegotiate:
419199747Smav		/* Honor device capabilities. */
420199747Smav		wantmode = mode = ata_max_mode(ident_buf, mode);
421199747Smav		/* Report modes to SIM. */
422199747Smav		bzero(&cts, sizeof(cts));
423203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
424199747Smav		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
425199747Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
426199747Smav		if (path->device->transport == XPORT_ATA) {
427199747Smav			cts.xport_specific.ata.mode = mode;
428199747Smav			cts.xport_specific.ata.valid = CTS_ATA_VALID_MODE;
429199747Smav		} else {
430199747Smav			cts.xport_specific.sata.mode = mode;
431199747Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_MODE;
432199747Smav		}
433199747Smav		xpt_action((union ccb *)&cts);
434200171Smav		/* Fetch current modes from SIM. */
435199747Smav		bzero(&cts, sizeof(cts));
436203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
437199747Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
438199747Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
439199747Smav		xpt_action((union ccb *)&cts);
440199747Smav		if (path->device->transport == XPORT_ATA) {
441199747Smav			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_MODE)
442199747Smav				mode = cts.xport_specific.ata.mode;
443199747Smav		} else {
444350545Sbrooks			if (cts.xport_specific.sata.valid & CTS_SATA_VALID_MODE)
445199747Smav				mode = cts.xport_specific.sata.mode;
446199747Smav		}
447199747Smav		/* If SIM disagree - renegotiate. */
448199747Smav		if (mode != wantmode)
449199747Smav			goto negotiate;
450220886Smav		/* Remember what transport thinks about DMA. */
451350805Smav		oif = path->device->inq_flags;
452220886Smav		if (mode < ATA_DMA)
453220886Smav			path->device->inq_flags &= ~SID_DMA;
454220886Smav		else
455220886Smav			path->device->inq_flags |= SID_DMA;
456350805Smav		if (path->device->inq_flags != oif)
457350805Smav			xpt_async(AC_GETDEV_CHANGED, path, NULL);
458195534Sscottl		cam_fill_ataio(ataio,
459195534Sscottl		      1,
460195534Sscottl		      probedone,
461196353Smav		      /*flags*/CAM_DIR_NONE,
462196353Smav		      0,
463196353Smav		      /*data_ptr*/NULL,
464196353Smav		      /*dxfer_len*/0,
465195534Sscottl		      30 * 1000);
466199747Smav		ata_28bit_cmd(ataio, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
467195534Sscottl		break;
468199747Smav	}
469207499Smav	case PROBE_SETPM:
470207499Smav		cam_fill_ataio(ataio,
471207499Smav		    1,
472207499Smav		    probedone,
473207499Smav		    CAM_DIR_NONE,
474207499Smav		    0,
475207499Smav		    NULL,
476207499Smav		    0,
477207499Smav		    30*1000);
478207499Smav		ata_28bit_cmd(ataio, ATA_SETFEATURES,
479207499Smav		    (softc->caps & CTS_SATA_CAPS_H_PMREQ) ? 0x10 : 0x90,
480207499Smav		    0, 0x03);
481207499Smav		break;
482207499Smav	case PROBE_SETAPST:
483207499Smav		cam_fill_ataio(ataio,
484207499Smav		    1,
485207499Smav		    probedone,
486207499Smav		    CAM_DIR_NONE,
487207499Smav		    0,
488207499Smav		    NULL,
489207499Smav		    0,
490207499Smav		    30*1000);
491207499Smav		ata_28bit_cmd(ataio, ATA_SETFEATURES,
492207499Smav		    (softc->caps & CTS_SATA_CAPS_H_APST) ? 0x10 : 0x90,
493207499Smav		    0, 0x07);
494207499Smav		break;
495207499Smav	case PROBE_SETDMAAA:
496207499Smav		cam_fill_ataio(ataio,
497207499Smav		    1,
498207499Smav		    probedone,
499207499Smav		    CAM_DIR_NONE,
500207499Smav		    0,
501207499Smav		    NULL,
502207499Smav		    0,
503207499Smav		    30*1000);
504207499Smav		ata_28bit_cmd(ataio, ATA_SETFEATURES,
505207499Smav		    (softc->caps & CTS_SATA_CAPS_H_DMAAA) ? 0x10 : 0x90,
506207499Smav		    0, 0x02);
507207499Smav		break;
508220602Smav	case PROBE_SETAN:
509270327Simp		/* Remember what transport thinks about AEN. */
510350805Smav		oif = path->device->inq_flags;
511270327Simp		if (softc->caps & CTS_SATA_CAPS_H_AN)
512238886Smav			path->device->inq_flags |= SID_AEN;
513238886Smav		else
514238886Smav			path->device->inq_flags &= ~SID_AEN;
515350805Smav		if (path->device->inq_flags != oif)
516350805Smav			xpt_async(AC_GETDEV_CHANGED, path, NULL);
517220602Smav		cam_fill_ataio(ataio,
518220602Smav		    1,
519220602Smav		    probedone,
520220602Smav		    CAM_DIR_NONE,
521220602Smav		    0,
522220602Smav		    NULL,
523220602Smav		    0,
524220602Smav		    30*1000);
525220602Smav		ata_28bit_cmd(ataio, ATA_SETFEATURES,
526220602Smav		    (softc->caps & CTS_SATA_CAPS_H_AN) ? 0x10 : 0x90,
527220602Smav		    0, 0x05);
528220602Smav		break;
529198708Smav	case PROBE_SET_MULTI:
530198708Smav	{
531200171Smav		u_int sectors, bytecount;
532198708Smav
533200171Smav		bytecount = 8192;	/* SATA maximum */
534200171Smav		/* Fetch user bytecount from SIM. */
535200171Smav		bzero(&cts, sizeof(cts));
536203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
537200171Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
538200171Smav		cts.type = CTS_TYPE_USER_SETTINGS;
539200171Smav		xpt_action((union ccb *)&cts);
540200171Smav		if (path->device->transport == XPORT_ATA) {
541200171Smav			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_BYTECOUNT)
542200171Smav				bytecount = cts.xport_specific.ata.bytecount;
543200171Smav		} else {
544200171Smav			if (cts.xport_specific.sata.valid & CTS_SATA_VALID_BYTECOUNT)
545200171Smav				bytecount = cts.xport_specific.sata.bytecount;
546200171Smav		}
547200171Smav		/* Honor device capabilities. */
548200171Smav		sectors = max(1, min(ident_buf->sectors_intr & 0xff,
549200171Smav		    bytecount / ata_logical_sector_size(ident_buf)));
550198708Smav		/* Report bytecount to SIM. */
551198708Smav		bzero(&cts, sizeof(cts));
552203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
553198708Smav		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
554198708Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
555198708Smav		if (path->device->transport == XPORT_ATA) {
556198897Smav			cts.xport_specific.ata.bytecount = sectors *
557198897Smav			    ata_logical_sector_size(ident_buf);
558198708Smav			cts.xport_specific.ata.valid = CTS_ATA_VALID_BYTECOUNT;
559198708Smav		} else {
560198897Smav			cts.xport_specific.sata.bytecount = sectors *
561198897Smav			    ata_logical_sector_size(ident_buf);
562198708Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_BYTECOUNT;
563198708Smav		}
564198708Smav		xpt_action((union ccb *)&cts);
565200171Smav		/* Fetch current bytecount from SIM. */
566200171Smav		bzero(&cts, sizeof(cts));
567203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
568200171Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
569200171Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
570200171Smav		xpt_action((union ccb *)&cts);
571200171Smav		if (path->device->transport == XPORT_ATA) {
572200171Smav			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_BYTECOUNT)
573200171Smav				bytecount = cts.xport_specific.ata.bytecount;
574200171Smav		} else {
575200171Smav			if (cts.xport_specific.sata.valid & CTS_SATA_VALID_BYTECOUNT)
576200171Smav				bytecount = cts.xport_specific.sata.bytecount;
577200171Smav		}
578200171Smav		sectors = bytecount / ata_logical_sector_size(ident_buf);
579198708Smav
580198708Smav		cam_fill_ataio(ataio,
581198708Smav		    1,
582198708Smav		    probedone,
583198708Smav		    CAM_DIR_NONE,
584198708Smav		    0,
585198708Smav		    NULL,
586198708Smav		    0,
587198708Smav		    30*1000);
588198708Smav		ata_28bit_cmd(ataio, ATA_SET_MULTI, 0, 0, sectors);
589198708Smav		break;
590195534Sscottl	}
591195534Sscottl	case PROBE_INQUIRY:
592200171Smav	{
593200171Smav		u_int bytecount;
594200171Smav
595200171Smav		bytecount = 8192;	/* SATA maximum */
596200171Smav		/* Fetch user bytecount from SIM. */
597200171Smav		bzero(&cts, sizeof(cts));
598203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
599200171Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
600200171Smav		cts.type = CTS_TYPE_USER_SETTINGS;
601200171Smav		xpt_action((union ccb *)&cts);
602200171Smav		if (path->device->transport == XPORT_ATA) {
603200171Smav			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_BYTECOUNT)
604200171Smav				bytecount = cts.xport_specific.ata.bytecount;
605200171Smav		} else {
606200171Smav			if (cts.xport_specific.sata.valid & CTS_SATA_VALID_BYTECOUNT)
607200171Smav				bytecount = cts.xport_specific.sata.bytecount;
608200171Smav		}
609200171Smav		/* Honor device capabilities. */
610200171Smav		bytecount &= ~1;
611200171Smav		bytecount = max(2, min(65534, bytecount));
612200171Smav		if (ident_buf->satacapabilities != 0x0000 &&
613200171Smav		    ident_buf->satacapabilities != 0xffff) {
614200171Smav			bytecount = min(8192, bytecount);
615200171Smav		}
616200171Smav		/* Report bytecount to SIM. */
617200171Smav		bzero(&cts, sizeof(cts));
618203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
619200171Smav		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
620200171Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
621200171Smav		if (path->device->transport == XPORT_ATA) {
622200171Smav			cts.xport_specific.ata.bytecount = bytecount;
623200171Smav			cts.xport_specific.ata.valid = CTS_ATA_VALID_BYTECOUNT;
624200171Smav		} else {
625200171Smav			cts.xport_specific.sata.bytecount = bytecount;
626200171Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_BYTECOUNT;
627200171Smav		}
628200171Smav		xpt_action((union ccb *)&cts);
629200171Smav		/* FALLTHROUGH */
630200171Smav	}
631195534Sscottl	case PROBE_FULL_INQUIRY:
632195534Sscottl	{
633195534Sscottl		u_int inquiry_len;
634195534Sscottl		struct scsi_inquiry_data *inq_buf =
635350805Smav		    &path->device->inq_data;
636195534Sscottl
637195534Sscottl		if (softc->action == PROBE_INQUIRY)
638195534Sscottl			inquiry_len = SHORT_INQUIRY_LENGTH;
639195534Sscottl		else
640195534Sscottl			inquiry_len = SID_ADDITIONAL_LENGTH(inq_buf);
641195534Sscottl		/*
642195534Sscottl		 * Some parallel SCSI devices fail to send an
643195534Sscottl		 * ignore wide residue message when dealing with
644195534Sscottl		 * odd length inquiry requests.  Round up to be
645195534Sscottl		 * safe.
646195534Sscottl		 */
647195534Sscottl		inquiry_len = roundup2(inquiry_len, 2);
648195534Sscottl		scsi_inquiry(csio,
649195534Sscottl			     /*retries*/1,
650195534Sscottl			     probedone,
651195534Sscottl			     MSG_SIMPLE_Q_TAG,
652195534Sscottl			     (u_int8_t *)inq_buf,
653195534Sscottl			     inquiry_len,
654195534Sscottl			     /*evpd*/FALSE,
655195534Sscottl			     /*page_code*/0,
656195534Sscottl			     SSD_MIN_SIZE,
657195534Sscottl			     /*timeout*/60 * 1000);
658195534Sscottl		break;
659195534Sscottl	}
660195534Sscottl	case PROBE_PM_PID:
661195534Sscottl		cam_fill_ataio(ataio,
662195534Sscottl		      1,
663195534Sscottl		      probedone,
664195534Sscottl		      /*flags*/CAM_DIR_NONE,
665198389Smav		      0,
666195534Sscottl		      /*data_ptr*/NULL,
667195534Sscottl		      /*dxfer_len*/0,
668195534Sscottl		      10 * 1000);
669195534Sscottl		ata_pm_read_cmd(ataio, 0, 15);
670195534Sscottl		break;
671195534Sscottl	case PROBE_PM_PRV:
672195534Sscottl		cam_fill_ataio(ataio,
673195534Sscottl		      1,
674195534Sscottl		      probedone,
675195534Sscottl		      /*flags*/CAM_DIR_NONE,
676198389Smav		      0,
677195534Sscottl		      /*data_ptr*/NULL,
678195534Sscottl		      /*dxfer_len*/0,
679195534Sscottl		      10 * 1000);
680195534Sscottl		ata_pm_read_cmd(ataio, 1, 15);
681195534Sscottl		break;
682235897Smav	case PROBE_IDENTIFY_SES:
683235897Smav		cam_fill_ataio(ataio,
684235897Smav		      1,
685235897Smav		      probedone,
686235897Smav		      /*flags*/CAM_DIR_IN,
687235897Smav		      0,
688235897Smav		      /*data_ptr*/(u_int8_t *)&softc->ident_data,
689235897Smav		      /*dxfer_len*/sizeof(softc->ident_data),
690235897Smav		      30 * 1000);
691235897Smav		ata_28bit_cmd(ataio, ATA_SEP_ATTN, 0xEC, 0x02,
692235897Smav		    sizeof(softc->ident_data) / 4);
693235897Smav		break;
694235897Smav	case PROBE_IDENTIFY_SAFTE:
695235897Smav		cam_fill_ataio(ataio,
696235897Smav		      1,
697235897Smav		      probedone,
698235897Smav		      /*flags*/CAM_DIR_IN,
699235897Smav		      0,
700235897Smav		      /*data_ptr*/(u_int8_t *)&softc->ident_data,
701235897Smav		      /*dxfer_len*/sizeof(softc->ident_data),
702235897Smav		      30 * 1000);
703235897Smav		ata_28bit_cmd(ataio, ATA_SEP_ATTN, 0xEC, 0x00,
704235897Smav		    sizeof(softc->ident_data) / 4);
705235897Smav		break;
706195534Sscottl	default:
707236613Smav		panic("probestart: invalid action state 0x%x\n", softc->action);
708195534Sscottl	}
709249466Smav	start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
710195534Sscottl	xpt_action(start_ccb);
711195534Sscottl}
712236437Smav
713195534Sscottlstatic void
714195534Sscottlproberequestdefaultnegotiation(struct cam_periph *periph)
715195534Sscottl{
716195534Sscottl	struct ccb_trans_settings cts;
717195534Sscottl
718203108Smav	xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NONE);
719195534Sscottl	cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
720195534Sscottl	cts.type = CTS_TYPE_USER_SETTINGS;
721195534Sscottl	xpt_action((union ccb *)&cts);
722236437Smav	if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
723195534Sscottl		return;
724236437Smav	cts.xport_specific.valid = 0;
725195534Sscottl	cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
726195534Sscottl	cts.type = CTS_TYPE_CURRENT_SETTINGS;
727195534Sscottl	xpt_action((union ccb *)&cts);
728195534Sscottl}
729195534Sscottl
730195534Sscottlstatic void
731195534Sscottlprobedone(struct cam_periph *periph, union ccb *done_ccb)
732195534Sscottl{
733199747Smav	struct ccb_trans_settings cts;
734195534Sscottl	struct ata_params *ident_buf;
735235897Smav	struct scsi_inquiry_data *inq_buf;
736195534Sscottl	probe_softc *softc;
737195534Sscottl	struct cam_path *path;
738217444Smav	cam_status status;
739195534Sscottl	u_int32_t  priority;
740350805Smav	u_int caps, oif;
741350805Smav	int changed, found = 1;
742235897Smav	static const uint8_t fake_device_id_hdr[8] =
743235897Smav	    {0, SVPD_DEVICE_ID, 0, 12,
744235897Smav	     SVPD_ID_CODESET_BINARY, SVPD_ID_TYPE_NAA, 0, 8};
745195534Sscottl
746195534Sscottl	CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probedone\n"));
747195534Sscottl
748195534Sscottl	softc = (probe_softc *)periph->softc;
749195534Sscottl	path = done_ccb->ccb_h.path;
750195534Sscottl	priority = done_ccb->ccb_h.pinfo.priority;
751195534Sscottl	ident_buf = &path->device->ident_data;
752235897Smav	inq_buf = &path->device->inq_data;
753195534Sscottl
754198708Smav	if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
755236814Smav		if (cam_periph_error(done_ccb,
756236814Smav		    0, softc->restart ? (SF_NO_RECOVERY | SF_NO_RETRY) : 0,
757249466Smav		    NULL) == ERESTART) {
758249466Smavout:
759249466Smav			/* Drop freeze taken due to CAM_DEV_QFREEZE flag set. */
760249466Smav			cam_release_devq(path, 0, 0, 0, FALSE);
761195534Sscottl			return;
762249466Smav		}
763209744Smav		if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
764195534Sscottl			/* Don't wedge the queue */
765249466Smav			xpt_release_devq(path, /*count*/1, /*run_queue*/TRUE);
766195534Sscottl		}
767217444Smav		status = done_ccb->ccb_h.status & CAM_STATUS_MASK;
768209744Smav		if (softc->restart) {
769209744Smav			softc->faults++;
770209744Smav			if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) ==
771209744Smav			    CAM_CMD_TIMEOUT)
772209744Smav				softc->faults += 4;
773209744Smav			if (softc->faults < 10)
774209744Smav				goto done;
775209744Smav			else
776209744Smav				softc->restart = 0;
777217444Smav
778198708Smav		/* Old PIO2 devices may not support mode setting. */
779217444Smav		} else if (softc->action == PROBE_SETMODE &&
780217444Smav		    status == CAM_ATA_STATUS_ERROR &&
781198708Smav		    ata_max_pmode(ident_buf) <= ATA_PIO2 &&
782217444Smav		    (ident_buf->capabilities1 & ATA_SUPPORT_IORDY) == 0) {
783198708Smav			goto noerror;
784217444Smav
785198708Smav		/*
786217444Smav		 * Some old WD SATA disks report supported and enabled
787217444Smav		 * device-initiated interface power management, but return
788217444Smav		 * ABORT on attempt to disable it.
789217444Smav		 */
790217444Smav		} else if (softc->action == PROBE_SETPM &&
791217444Smav		    status == CAM_ATA_STATUS_ERROR) {
792217444Smav			goto noerror;
793217875Smav
794217875Smav		/*
795323736Savg		 * Some old WD SATA disks have broken SPINUP handling.
796323736Savg		 * If we really fail to spin up the disk, then there will be
797323736Savg		 * some media access errors later on, but at least we will
798323736Savg		 * have a device to interact with for recovery attempts.
799323736Savg		 */
800323736Savg		} else if (softc->action == PROBE_SPINUP &&
801323736Savg		    status == CAM_ATA_STATUS_ERROR) {
802323736Savg			goto noerror;
803323736Savg
804323736Savg		/*
805217875Smav		 * Some HP SATA disks report supported DMA Auto-Activation,
806217875Smav		 * but return ABORT on attempt to enable it.
807217875Smav		 */
808217875Smav		} else if (softc->action == PROBE_SETDMAAA &&
809217875Smav		    status == CAM_ATA_STATUS_ERROR) {
810217875Smav			goto noerror;
811235897Smav
812235897Smav		/*
813235897Smav		 * SES and SAF-TE SEPs have different IDENTIFY commands,
814235897Smav		 * but SATA specification doesn't tell how to identify them.
815235897Smav		 * Until better way found, just try another if first fail.
816235897Smav		 */
817235897Smav		} else if (softc->action == PROBE_IDENTIFY_SES &&
818235897Smav		    status == CAM_ATA_STATUS_ERROR) {
819235897Smav			PROBE_SET_ACTION(softc, PROBE_IDENTIFY_SAFTE);
820235897Smav			xpt_release_ccb(done_ccb);
821235897Smav			xpt_schedule(periph, priority);
822249466Smav			goto out;
823217444Smav		}
824217444Smav
825217444Smav		/*
826198708Smav		 * If we get to this point, we got an error status back
827198708Smav		 * from the inquiry and the error status doesn't require
828198708Smav		 * automatically retrying the command.  Therefore, the
829198708Smav		 * inquiry failed.  If we had inquiry information before
830198708Smav		 * for this device, but this latest inquiry command failed,
831198708Smav		 * the device has probably gone away.  If this device isn't
832198708Smav		 * already marked unconfigured, notify the peripheral
833198708Smav		 * drivers that this device is no more.
834198708Smav		 */
835209744Smavdevice_fail:	if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0)
836198708Smav			xpt_async(AC_LOST_DEVICE, path, NULL);
837236613Smav		PROBE_SET_ACTION(softc, PROBE_INVALID);
838198708Smav		found = 0;
839198708Smav		goto done;
840198708Smav	}
841198708Smavnoerror:
842203385Smav	if (softc->restart)
843203385Smav		goto done;
844198708Smav	switch (softc->action) {
845198708Smav	case PROBE_RESET:
846195534Sscottl	{
847198708Smav		int sign = (done_ccb->ataio.res.lba_high << 8) +
848198708Smav		    done_ccb->ataio.res.lba_mid;
849236613Smav		CAM_DEBUG(path, CAM_DEBUG_PROBE,
850236613Smav		    ("SIGNATURE: %04x\n", sign));
851198708Smav		if (sign == 0x0000 &&
852198708Smav		    done_ccb->ccb_h.target_id != 15) {
853198708Smav			path->device->protocol = PROTO_ATA;
854198708Smav			PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
855198708Smav		} else if (sign == 0x9669 &&
856198708Smav		    done_ccb->ccb_h.target_id == 15) {
857199747Smav			/* Report SIM that PM is present. */
858198708Smav			bzero(&cts, sizeof(cts));
859203108Smav			xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
860198708Smav			cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
861198708Smav			cts.type = CTS_TYPE_CURRENT_SETTINGS;
862198708Smav			cts.xport_specific.sata.pm_present = 1;
863198708Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_PM;
864198708Smav			xpt_action((union ccb *)&cts);
865198708Smav			path->device->protocol = PROTO_SATAPM;
866198708Smav			PROBE_SET_ACTION(softc, PROBE_PM_PID);
867235897Smav		} else if (sign == 0xc33c &&
868235897Smav		    done_ccb->ccb_h.target_id != 15) {
869235897Smav			path->device->protocol = PROTO_SEMB;
870235897Smav			PROBE_SET_ACTION(softc, PROBE_IDENTIFY_SES);
871198708Smav		} else if (sign == 0xeb14 &&
872198708Smav		    done_ccb->ccb_h.target_id != 15) {
873198708Smav			path->device->protocol = PROTO_SCSI;
874198708Smav			PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
875198708Smav		} else {
876198708Smav			if (done_ccb->ccb_h.target_id != 15) {
877198708Smav				xpt_print(path,
878198708Smav				    "Unexpected signature 0x%04x\n", sign);
879195534Sscottl			}
880198708Smav			goto device_fail;
881198708Smav		}
882198708Smav		xpt_release_ccb(done_ccb);
883198708Smav		xpt_schedule(periph, priority);
884249466Smav		goto out;
885198708Smav	}
886198708Smav	case PROBE_IDENTIFY:
887198708Smav	{
888207222Smav		struct ccb_pathinq cpi;
889198708Smav		int16_t *ptr;
890307606Ssephe		int veto = 0;
891195534Sscottl
892350794Smav		/*
893350794Smav		 * Convert to host byte order, and fix the strings.
894350794Smav		 */
895203385Smav		ident_buf = &softc->ident_data;
896198708Smav		for (ptr = (int16_t *)ident_buf;
897198708Smav		     ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) {
898198708Smav			*ptr = le16toh(*ptr);
899198708Smav		}
900198708Smav		if (strncmp(ident_buf->model, "FX", 2) &&
901198708Smav		    strncmp(ident_buf->model, "NEC", 3) &&
902198708Smav		    strncmp(ident_buf->model, "Pioneer", 7) &&
903198708Smav		    strncmp(ident_buf->model, "SHARP", 5)) {
904198708Smav			ata_bswap(ident_buf->model, sizeof(ident_buf->model));
905198708Smav			ata_bswap(ident_buf->revision, sizeof(ident_buf->revision));
906198708Smav			ata_bswap(ident_buf->serial, sizeof(ident_buf->serial));
907198708Smav		}
908198708Smav		ata_btrim(ident_buf->model, sizeof(ident_buf->model));
909198708Smav		ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model));
910198708Smav		ata_btrim(ident_buf->revision, sizeof(ident_buf->revision));
911198708Smav		ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision));
912198708Smav		ata_btrim(ident_buf->serial, sizeof(ident_buf->serial));
913198708Smav		ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial));
914350794Smav
915350794Smav		/*
916350794Smav		 * Allow others to veto this ATA disk attachment.  This
917350794Smav		 * is mainly used by VMs, whose disk controllers may
918350794Smav		 * share the disks with the simulated ATA controllers.
919350794Smav		 */
920350794Smav		EVENTHANDLER_INVOKE(ada_probe_veto, path, ident_buf, &veto);
921350794Smav		if (veto) {
922350794Smav			goto device_fail;
923350794Smav		}
924350794Smav
925203421Smav		/* Device may need spin-up before IDENTIFY become valid. */
926204354Smav		if ((ident_buf->specconf == 0x37c8 ||
927204354Smav		     ident_buf->specconf == 0x738c) &&
928204354Smav		    ((ident_buf->config & ATA_RESP_INCOMPLETE) ||
929204354Smav		     softc->spinup == 0)) {
930203421Smav			PROBE_SET_ACTION(softc, PROBE_SPINUP);
931203421Smav			xpt_release_ccb(done_ccb);
932203421Smav			xpt_schedule(periph, priority);
933249466Smav			goto out;
934203421Smav		}
935203385Smav		ident_buf = &path->device->ident_data;
936350805Smav
937350805Smav		/* Check that it is the same device as we know. */
938198708Smav		if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) {
939203385Smav			if (bcmp(softc->ident_data.model, ident_buf->model,
940203385Smav			     sizeof(ident_buf->model)) ||
941203385Smav			    bcmp(softc->ident_data.serial, ident_buf->serial,
942203385Smav			     sizeof(ident_buf->serial))) {
943350805Smav				/* The device was replaced. */
944350805Smav				changed = 2;
945198708Smav				xpt_async(AC_LOST_DEVICE, path, NULL);
946350805Smav			} else if (bcmp(&softc->ident_data, ident_buf,
947350805Smav			     sizeof(*ident_buf))) {
948350805Smav				/* The device is the same, but has changed. */
949350805Smav				changed = 1;
950207282Smav			} else {
951350805Smav				/* Nothing has changed. */
952207282Smav				changed = 0;
953207282Smav			}
954350805Smav		} else {
955350805Smav			/* This is a new device. */
956350805Smav			changed = 2;
957207282Smav		}
958350805Smav
959350805Smav		if (changed != 0)
960203385Smav			bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params));
961350805Smav		if (changed == 2) {
962195534Sscottl			/* Clean up from previous instance of this device */
963195534Sscottl			if (path->device->serial_num != NULL) {
964195534Sscottl				free(path->device->serial_num, M_CAMXPT);
965195534Sscottl				path->device->serial_num = NULL;
966195534Sscottl				path->device->serial_num_len = 0;
967195534Sscottl			}
968235897Smav			if (path->device->device_id != NULL) {
969235897Smav				free(path->device->device_id, M_CAMXPT);
970235897Smav				path->device->device_id = NULL;
971235897Smav				path->device->device_id_len = 0;
972235897Smav			}
973195534Sscottl			path->device->serial_num =
974195534Sscottl				(u_int8_t *)malloc((sizeof(ident_buf->serial) + 1),
975198708Smav					   M_CAMXPT, M_NOWAIT);
976195534Sscottl			if (path->device->serial_num != NULL) {
977195534Sscottl				bcopy(ident_buf->serial,
978195534Sscottl				      path->device->serial_num,
979195534Sscottl				      sizeof(ident_buf->serial));
980195534Sscottl				path->device->serial_num[sizeof(ident_buf->serial)]
981195534Sscottl				    = '\0';
982195534Sscottl				path->device->serial_num_len =
983195534Sscottl				    strlen(path->device->serial_num);
984195534Sscottl			}
985235897Smav			if (ident_buf->enabled.extension &
986235897Smav			    ATA_SUPPORT_64BITWWN) {
987235897Smav				path->device->device_id =
988235897Smav				    malloc(16, M_CAMXPT, M_NOWAIT);
989235897Smav				if (path->device->device_id != NULL) {
990235897Smav					path->device->device_id_len = 16;
991235897Smav					bcopy(&fake_device_id_hdr,
992235897Smav					    path->device->device_id, 8);
993250301Smav					bcopy(ident_buf->wwn,
994250301Smav					    path->device->device_id + 8, 8);
995250301Smav					ata_bswap(path->device->device_id + 8, 8);
996235897Smav				}
997235897Smav			}
998198331Smav			path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID;
999350805Smav		}
1000350805Smav		if (changed == 1)
1001236393Smav			xpt_async(AC_GETDEV_CHANGED, path, NULL);
1002199178Smav		if (ident_buf->satacapabilities & ATA_SUPPORT_NCQ) {
1003236234Smav			path->device->mintags = 2;
1004236234Smav			path->device->maxtags =
1005199178Smav			    ATA_QUEUE_LEN(ident_buf->queue) + 1;
1006199178Smav		}
1007199178Smav		ata_find_quirk(path->device);
1008199263Smav		if (path->device->mintags != 0 &&
1009199263Smav		    path->bus->sim->max_tagged_dev_openings != 0) {
1010207222Smav			/* Check if the SIM does not want queued commands. */
1011350804Smav			xpt_path_inq(&cpi, path);
1012207222Smav			if (cpi.ccb_h.status == CAM_REQ_CMP &&
1013207222Smav			    (cpi.hba_inquiry & PI_TAG_ABLE)) {
1014207222Smav				/* Report SIM which tags are allowed. */
1015207222Smav				bzero(&cts, sizeof(cts));
1016207222Smav				xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
1017207222Smav				cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
1018207222Smav				cts.type = CTS_TYPE_CURRENT_SETTINGS;
1019207222Smav				cts.xport_specific.sata.tags = path->device->maxtags;
1020207222Smav				cts.xport_specific.sata.valid = CTS_SATA_VALID_TAGS;
1021207222Smav				xpt_action((union ccb *)&cts);
1022207222Smav			}
1023199178Smav		}
1024236666Smav		ata_device_transport(path);
1025350805Smav		if (changed == 2)
1026236437Smav			proberequestdefaultnegotiation(periph);
1027198708Smav		PROBE_SET_ACTION(softc, PROBE_SETMODE);
1028195534Sscottl		xpt_release_ccb(done_ccb);
1029198708Smav		xpt_schedule(periph, priority);
1030249466Smav		goto out;
1031195534Sscottl	}
1032203421Smav	case PROBE_SPINUP:
1033203421Smav		if (bootverbose)
1034203421Smav			xpt_print(path, "Spin-up done\n");
1035203421Smav		softc->spinup = 1;
1036203421Smav		PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
1037203421Smav		xpt_release_ccb(done_ccb);
1038203421Smav		xpt_schedule(periph, priority);
1039249466Smav		goto out;
1040195534Sscottl	case PROBE_SETMODE:
1041207499Smav		/* Set supported bits. */
1042207499Smav		bzero(&cts, sizeof(cts));
1043207499Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
1044207499Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
1045207499Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
1046207499Smav		xpt_action((union ccb *)&cts);
1047249199Smarius		if (path->device->transport == XPORT_SATA &&
1048249199Smarius		    cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS)
1049207499Smav			caps = cts.xport_specific.sata.caps & CTS_SATA_CAPS_H;
1050249199Smarius		else if (path->device->transport == XPORT_ATA &&
1051249199Smarius		    cts.xport_specific.ata.valid & CTS_ATA_VALID_CAPS)
1052249199Smarius			caps = cts.xport_specific.ata.caps & CTS_ATA_CAPS_H;
1053207499Smav		else
1054207499Smav			caps = 0;
1055249199Smarius		if (path->device->transport == XPORT_SATA &&
1056249199Smarius		    ident_buf->satacapabilities != 0xffff) {
1057207499Smav			if (ident_buf->satacapabilities & ATA_SUPPORT_IFPWRMNGTRCV)
1058207499Smav				caps |= CTS_SATA_CAPS_D_PMREQ;
1059207499Smav			if (ident_buf->satacapabilities & ATA_SUPPORT_HAPST)
1060207499Smav				caps |= CTS_SATA_CAPS_D_APST;
1061207499Smav		}
1062207499Smav		/* Mask unwanted bits. */
1063207499Smav		bzero(&cts, sizeof(cts));
1064207499Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
1065207499Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
1066207499Smav		cts.type = CTS_TYPE_USER_SETTINGS;
1067207499Smav		xpt_action((union ccb *)&cts);
1068249199Smarius		if (path->device->transport == XPORT_SATA &&
1069249199Smarius		    cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS)
1070207499Smav			caps &= cts.xport_specific.sata.caps;
1071249199Smarius		else if (path->device->transport == XPORT_ATA &&
1072249199Smarius		    cts.xport_specific.ata.valid & CTS_ATA_VALID_CAPS)
1073249199Smarius			caps &= cts.xport_specific.ata.caps;
1074215454Smav		else
1075215454Smav			caps = 0;
1076249199Smarius		/*
1077249199Smarius		 * Remember what transport thinks about 48-bit DMA.  If
1078249199Smarius		 * capability information is not provided or transport is
1079249199Smarius		 * SATA, we take support for granted.
1080249199Smarius		 */
1081350805Smav		oif = path->device->inq_flags;
1082249199Smarius		if (!(path->device->inq_flags & SID_DMA) ||
1083249199Smarius		    (path->device->transport == XPORT_ATA &&
1084249199Smarius		    (cts.xport_specific.ata.valid & CTS_ATA_VALID_CAPS) &&
1085249199Smarius		    !(caps & CTS_ATA_CAPS_H_DMA48)))
1086249199Smarius			path->device->inq_flags &= ~SID_DMA48;
1087249199Smarius		else
1088249199Smarius			path->device->inq_flags |= SID_DMA48;
1089350805Smav		if (path->device->inq_flags != oif)
1090350805Smav			xpt_async(AC_GETDEV_CHANGED, path, NULL);
1091207499Smav		/* Store result to SIM. */
1092207499Smav		bzero(&cts, sizeof(cts));
1093207499Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
1094207499Smav		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
1095207499Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
1096249199Smarius		if (path->device->transport == XPORT_SATA) {
1097249199Smarius			cts.xport_specific.sata.caps = caps;
1098249199Smarius			cts.xport_specific.sata.valid = CTS_SATA_VALID_CAPS;
1099249199Smarius		} else {
1100249199Smarius			cts.xport_specific.ata.caps = caps;
1101249199Smarius			cts.xport_specific.ata.valid = CTS_ATA_VALID_CAPS;
1102249199Smarius		}
1103207499Smav		xpt_action((union ccb *)&cts);
1104207499Smav		softc->caps = caps;
1105249199Smarius		if (path->device->transport != XPORT_SATA)
1106249199Smarius			goto notsata;
1107217874Smav		if ((ident_buf->satasupport & ATA_SUPPORT_IFPWRMNGT) &&
1108217874Smav		    (!(softc->caps & CTS_SATA_CAPS_H_PMREQ)) !=
1109217874Smav		    (!(ident_buf->sataenabled & ATA_SUPPORT_IFPWRMNGT))) {
1110207499Smav			PROBE_SET_ACTION(softc, PROBE_SETPM);
1111207499Smav			xpt_release_ccb(done_ccb);
1112207499Smav			xpt_schedule(periph, priority);
1113249466Smav			goto out;
1114207499Smav		}
1115207499Smav		/* FALLTHROUGH */
1116207499Smav	case PROBE_SETPM:
1117207499Smav		if (ident_buf->satacapabilities != 0xffff &&
1118217874Smav		    (ident_buf->satacapabilities & ATA_SUPPORT_DAPST) &&
1119217874Smav		    (!(softc->caps & CTS_SATA_CAPS_H_APST)) !=
1120217874Smav		    (!(ident_buf->sataenabled & ATA_ENABLED_DAPST))) {
1121207499Smav			PROBE_SET_ACTION(softc, PROBE_SETAPST);
1122207499Smav			xpt_release_ccb(done_ccb);
1123207499Smav			xpt_schedule(periph, priority);
1124249466Smav			goto out;
1125207499Smav		}
1126207499Smav		/* FALLTHROUGH */
1127207499Smav	case PROBE_SETAPST:
1128217874Smav		if ((ident_buf->satasupport & ATA_SUPPORT_AUTOACTIVATE) &&
1129217874Smav		    (!(softc->caps & CTS_SATA_CAPS_H_DMAAA)) !=
1130217874Smav		    (!(ident_buf->sataenabled & ATA_SUPPORT_AUTOACTIVATE))) {
1131207499Smav			PROBE_SET_ACTION(softc, PROBE_SETDMAAA);
1132207499Smav			xpt_release_ccb(done_ccb);
1133207499Smav			xpt_schedule(periph, priority);
1134249466Smav			goto out;
1135207499Smav		}
1136207499Smav		/* FALLTHROUGH */
1137207499Smav	case PROBE_SETDMAAA:
1138270327Simp		if (path->device->protocol != PROTO_ATA &&
1139270327Simp		    (ident_buf->satasupport & ATA_SUPPORT_ASYNCNOTIF) &&
1140220602Smav		    (!(softc->caps & CTS_SATA_CAPS_H_AN)) !=
1141220602Smav		    (!(ident_buf->sataenabled & ATA_SUPPORT_ASYNCNOTIF))) {
1142220602Smav			PROBE_SET_ACTION(softc, PROBE_SETAN);
1143220602Smav			xpt_release_ccb(done_ccb);
1144220602Smav			xpt_schedule(periph, priority);
1145249466Smav			goto out;
1146220602Smav		}
1147220602Smav		/* FALLTHROUGH */
1148220602Smav	case PROBE_SETAN:
1149207499Smavnotsata:
1150198708Smav		if (path->device->protocol == PROTO_ATA) {
1151198708Smav			PROBE_SET_ACTION(softc, PROBE_SET_MULTI);
1152198708Smav		} else {
1153198708Smav			PROBE_SET_ACTION(softc, PROBE_INQUIRY);
1154195534Sscottl		}
1155198708Smav		xpt_release_ccb(done_ccb);
1156198708Smav		xpt_schedule(periph, priority);
1157249466Smav		goto out;
1158198708Smav	case PROBE_SET_MULTI:
1159198708Smav		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
1160198708Smav			path->device->flags &= ~CAM_DEV_UNCONFIGURED;
1161198748Smav			xpt_acquire_device(path->device);
1162198708Smav			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
1163198708Smav			xpt_action(done_ccb);
1164249466Smav			xpt_async(AC_FOUND_DEVICE, path, done_ccb);
1165198708Smav		}
1166236613Smav		PROBE_SET_ACTION(softc, PROBE_DONE);
1167198708Smav		break;
1168195534Sscottl	case PROBE_INQUIRY:
1169195534Sscottl	case PROBE_FULL_INQUIRY:
1170195534Sscottl	{
1171198708Smav		u_int8_t periph_qual, len;
1172195534Sscottl
1173198708Smav		path->device->flags |= CAM_DEV_INQUIRY_DATA_VALID;
1174195534Sscottl
1175198708Smav		periph_qual = SID_QUAL(inq_buf);
1176195534Sscottl
1177287289Smav		if (periph_qual != SID_QUAL_LU_CONNECTED &&
1178287289Smav		    periph_qual != SID_QUAL_LU_OFFLINE)
1179198708Smav			break;
1180195534Sscottl
1181198708Smav		/*
1182198708Smav		 * We conservatively request only
1183198708Smav		 * SHORT_INQUIRY_LEN bytes of inquiry
1184198708Smav		 * information during our first try
1185198708Smav		 * at sending an INQUIRY. If the device
1186198708Smav		 * has more information to give,
1187198708Smav		 * perform a second request specifying
1188198708Smav		 * the amount of information the device
1189198708Smav		 * is willing to give.
1190198708Smav		 */
1191198708Smav		len = inq_buf->additional_length
1192198708Smav		    + offsetof(struct scsi_inquiry_data, additional_length) + 1;
1193198708Smav		if (softc->action == PROBE_INQUIRY
1194198708Smav		    && len > SHORT_INQUIRY_LENGTH) {
1195198708Smav			PROBE_SET_ACTION(softc, PROBE_FULL_INQUIRY);
1196198708Smav			xpt_release_ccb(done_ccb);
1197198708Smav			xpt_schedule(periph, priority);
1198249466Smav			goto out;
1199195534Sscottl		}
1200198708Smav
1201198708Smav		ata_device_transport(path);
1202198708Smav		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
1203198708Smav			path->device->flags &= ~CAM_DEV_UNCONFIGURED;
1204198748Smav			xpt_acquire_device(path->device);
1205198708Smav			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
1206198708Smav			xpt_action(done_ccb);
1207249466Smav			xpt_async(AC_FOUND_DEVICE, path, done_ccb);
1208198708Smav		}
1209236613Smav		PROBE_SET_ACTION(softc, PROBE_DONE);
1210198708Smav		break;
1211195534Sscottl	}
1212195534Sscottl	case PROBE_PM_PID:
1213198708Smav		if ((path->device->flags & CAM_DEV_IDENTIFY_DATA_VALID) == 0)
1214198708Smav			bzero(ident_buf, sizeof(*ident_buf));
1215198708Smav		softc->pm_pid = (done_ccb->ataio.res.lba_high << 24) +
1216198708Smav		    (done_ccb->ataio.res.lba_mid << 16) +
1217198708Smav		    (done_ccb->ataio.res.lba_low << 8) +
1218198708Smav		    done_ccb->ataio.res.sector_count;
1219198708Smav		((uint32_t *)ident_buf)[0] = softc->pm_pid;
1220198708Smav		snprintf(ident_buf->model, sizeof(ident_buf->model),
1221198708Smav		    "Port Multiplier %08x", softc->pm_pid);
1222198708Smav		PROBE_SET_ACTION(softc, PROBE_PM_PRV);
1223198708Smav		xpt_release_ccb(done_ccb);
1224198708Smav		xpt_schedule(periph, priority);
1225249466Smav		goto out;
1226195534Sscottl	case PROBE_PM_PRV:
1227198708Smav		softc->pm_prv = (done_ccb->ataio.res.lba_high << 24) +
1228198708Smav		    (done_ccb->ataio.res.lba_mid << 16) +
1229198708Smav		    (done_ccb->ataio.res.lba_low << 8) +
1230198708Smav		    done_ccb->ataio.res.sector_count;
1231198708Smav		((uint32_t *)ident_buf)[1] = softc->pm_prv;
1232198708Smav		snprintf(ident_buf->revision, sizeof(ident_buf->revision),
1233198708Smav		    "%04x", softc->pm_prv);
1234198708Smav		path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID;
1235236666Smav		ata_device_transport(path);
1236236666Smav		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED)
1237236666Smav			proberequestdefaultnegotiation(periph);
1238207499Smav		/* Set supported bits. */
1239207499Smav		bzero(&cts, sizeof(cts));
1240207499Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
1241207499Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
1242207499Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
1243207499Smav		xpt_action((union ccb *)&cts);
1244207499Smav		if (cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS)
1245207499Smav			caps = cts.xport_specific.sata.caps & CTS_SATA_CAPS_H;
1246207499Smav		else
1247207499Smav			caps = 0;
1248207499Smav		/* All PMPs must support PM requests. */
1249207499Smav		caps |= CTS_SATA_CAPS_D_PMREQ;
1250207499Smav		/* Mask unwanted bits. */
1251207499Smav		bzero(&cts, sizeof(cts));
1252207499Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
1253207499Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
1254207499Smav		cts.type = CTS_TYPE_USER_SETTINGS;
1255207499Smav		xpt_action((union ccb *)&cts);
1256207499Smav		if (cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS)
1257207499Smav			caps &= cts.xport_specific.sata.caps;
1258215454Smav		else
1259215454Smav			caps = 0;
1260249199Smarius		/* Remember what transport thinks about AEN. */
1261350805Smav		oif = path->device->inq_flags;
1262270327Simp		if ((caps & CTS_SATA_CAPS_H_AN) && path->device->protocol != PROTO_ATA)
1263249199Smarius			path->device->inq_flags |= SID_AEN;
1264249199Smarius		else
1265249199Smarius			path->device->inq_flags &= ~SID_AEN;
1266207499Smav		/* Store result to SIM. */
1267207499Smav		bzero(&cts, sizeof(cts));
1268207499Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
1269207499Smav		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
1270207499Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
1271207499Smav		cts.xport_specific.sata.caps = caps;
1272207499Smav		cts.xport_specific.sata.valid = CTS_SATA_VALID_CAPS;
1273207499Smav		xpt_action((union ccb *)&cts);
1274207499Smav		softc->caps = caps;
1275198708Smav		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
1276198708Smav			path->device->flags &= ~CAM_DEV_UNCONFIGURED;
1277198748Smav			xpt_acquire_device(path->device);
1278198708Smav			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
1279198708Smav			xpt_action(done_ccb);
1280249466Smav			xpt_async(AC_FOUND_DEVICE, path, done_ccb);
1281198708Smav		} else {
1282350805Smav			if (path->device->inq_flags != oif)
1283350805Smav				xpt_async(AC_GETDEV_CHANGED, path, NULL);
1284198708Smav			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
1285198708Smav			xpt_action(done_ccb);
1286249466Smav			xpt_async(AC_SCSI_AEN, path, done_ccb);
1287195534Sscottl		}
1288236613Smav		PROBE_SET_ACTION(softc, PROBE_DONE);
1289198708Smav		break;
1290235897Smav	case PROBE_IDENTIFY_SES:
1291235897Smav	case PROBE_IDENTIFY_SAFTE:
1292235897Smav		if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) {
1293235897Smav			/* Check that it is the same device. */
1294235897Smav			if (bcmp(&softc->ident_data, ident_buf, 53)) {
1295235897Smav				/* Device changed. */
1296350805Smav				changed = 2;
1297235897Smav				xpt_async(AC_LOST_DEVICE, path, NULL);
1298235897Smav			} else {
1299235897Smav				bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params));
1300235897Smav				changed = 0;
1301235897Smav			}
1302350805Smav		} else
1303350805Smav			changed = 2;
1304235897Smav		if (changed) {
1305235897Smav			bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params));
1306235897Smav			/* Clean up from previous instance of this device */
1307235897Smav			if (path->device->device_id != NULL) {
1308235897Smav				free(path->device->device_id, M_CAMXPT);
1309235897Smav				path->device->device_id = NULL;
1310235897Smav				path->device->device_id_len = 0;
1311235897Smav			}
1312235897Smav			path->device->device_id =
1313235897Smav			    malloc(16, M_CAMXPT, M_NOWAIT);
1314235897Smav			if (path->device->device_id != NULL) {
1315235897Smav				path->device->device_id_len = 16;
1316235897Smav				bcopy(&fake_device_id_hdr,
1317235897Smav				    path->device->device_id, 8);
1318235897Smav				bcopy(((uint8_t*)ident_buf) + 2,
1319235897Smav				    path->device->device_id + 8, 8);
1320235897Smav			}
1321235897Smav
1322235897Smav			path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID;
1323235897Smav		}
1324236666Smav		ata_device_transport(path);
1325236666Smav		if (changed)
1326236666Smav			proberequestdefaultnegotiation(periph);
1327235897Smav
1328235897Smav		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
1329235897Smav			path->device->flags &= ~CAM_DEV_UNCONFIGURED;
1330235897Smav			xpt_acquire_device(path->device);
1331235897Smav			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
1332235897Smav			xpt_action(done_ccb);
1333249466Smav			xpt_async(AC_FOUND_DEVICE, path, done_ccb);
1334235897Smav		}
1335236613Smav		PROBE_SET_ACTION(softc, PROBE_DONE);
1336235897Smav		break;
1337195534Sscottl	default:
1338236613Smav		panic("probedone: invalid action state 0x%x\n", softc->action);
1339195534Sscottl	}
1340198708Smavdone:
1341203108Smav	if (softc->restart) {
1342203108Smav		softc->restart = 0;
1343203108Smav		xpt_release_ccb(done_ccb);
1344195534Sscottl		probeschedule(periph);
1345249466Smav		goto out;
1346195534Sscottl	}
1347203108Smav	xpt_release_ccb(done_ccb);
1348236613Smav	CAM_DEBUG(periph->path, CAM_DEBUG_PROBE, ("Probe completed\n"));
1349203108Smav	while ((done_ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs))) {
1350203108Smav		TAILQ_REMOVE(&softc->request_ccbs,
1351203108Smav		    &done_ccb->ccb_h, periph_links.tqe);
1352203108Smav		done_ccb->ccb_h.status = found ? CAM_REQ_CMP : CAM_REQ_CMP_ERR;
1353203108Smav		xpt_done(done_ccb);
1354203108Smav	}
1355249466Smav	/* Drop freeze taken due to CAM_DEV_QFREEZE flag set. */
1356249466Smav	cam_release_devq(path, 0, 0, 0, FALSE);
1357236228Smav	cam_periph_invalidate(periph);
1358203108Smav	cam_periph_release_locked(periph);
1359195534Sscottl}
1360195534Sscottl
1361195534Sscottlstatic void
1362195534Sscottlprobecleanup(struct cam_periph *periph)
1363195534Sscottl{
1364195534Sscottl	free(periph->softc, M_CAMXPT);
1365195534Sscottl}
1366195534Sscottl
1367195534Sscottlstatic void
1368199178Smavata_find_quirk(struct cam_ed *device)
1369195534Sscottl{
1370199178Smav	struct ata_quirk_entry *quirk;
1371195534Sscottl	caddr_t	match;
1372195534Sscottl
1373199178Smav	match = cam_quirkmatch((caddr_t)&device->ident_data,
1374199178Smav			       (caddr_t)ata_quirk_table,
1375298411Spfg			       nitems(ata_quirk_table),
1376199178Smav			       sizeof(*ata_quirk_table), ata_identify_match);
1377195534Sscottl
1378195534Sscottl	if (match == NULL)
1379195534Sscottl		panic("xpt_find_quirk: device didn't match wildcard entry!!");
1380195534Sscottl
1381199178Smav	quirk = (struct ata_quirk_entry *)match;
1382195534Sscottl	device->quirk = quirk;
1383236234Smav	if (quirk->quirks & CAM_QUIRK_MAXTAGS) {
1384236234Smav		device->mintags = quirk->mintags;
1385236234Smav		device->maxtags = quirk->maxtags;
1386236234Smav	}
1387195534Sscottl}
1388195534Sscottl
1389195534Sscottltypedef struct {
1390195534Sscottl	union	ccb *request_ccb;
1391195534Sscottl	struct 	ccb_pathinq *cpi;
1392195534Sscottl	int	counter;
1393195534Sscottl} ata_scan_bus_info;
1394195534Sscottl
1395195534Sscottl/*
1396195534Sscottl * To start a scan, request_ccb is an XPT_SCAN_BUS ccb.
1397195534Sscottl * As the scan progresses, xpt_scan_bus is used as the
1398195534Sscottl * callback on completion function.
1399195534Sscottl */
1400195534Sscottlstatic void
1401195534Sscottlata_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
1402195534Sscottl{
1403195534Sscottl	struct	cam_path *path;
1404195534Sscottl	ata_scan_bus_info *scan_info;
1405203108Smav	union	ccb *work_ccb, *reset_ccb;
1406256843Smav	struct mtx *mtx;
1407195534Sscottl	cam_status status;
1408195534Sscottl
1409195534Sscottl	CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE,
1410195534Sscottl		  ("xpt_scan_bus\n"));
1411195534Sscottl	switch (request_ccb->ccb_h.func_code) {
1412195534Sscottl	case XPT_SCAN_BUS:
1413208582Smjacob	case XPT_SCAN_TGT:
1414195534Sscottl		/* Find out the characteristics of the bus */
1415195534Sscottl		work_ccb = xpt_alloc_ccb_nowait();
1416195534Sscottl		if (work_ccb == NULL) {
1417195534Sscottl			request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1418195534Sscottl			xpt_done(request_ccb);
1419195534Sscottl			return;
1420195534Sscottl		}
1421350804Smav		xpt_path_inq(&work_ccb->cpi, request_ccb->ccb_h.path);
1422195534Sscottl		if (work_ccb->ccb_h.status != CAM_REQ_CMP) {
1423195534Sscottl			request_ccb->ccb_h.status = work_ccb->ccb_h.status;
1424195534Sscottl			xpt_free_ccb(work_ccb);
1425195534Sscottl			xpt_done(request_ccb);
1426195534Sscottl			return;
1427195534Sscottl		}
1428195534Sscottl
1429203108Smav		/* We may need to reset bus first, if we haven't done it yet. */
1430203108Smav		if ((work_ccb->cpi.hba_inquiry &
1431203108Smav		    (PI_WIDE_32|PI_WIDE_16|PI_SDTR_ABLE)) &&
1432203108Smav		    !(work_ccb->cpi.hba_misc & PIM_NOBUSRESET) &&
1433203108Smav		    !timevalisset(&request_ccb->ccb_h.path->bus->last_reset)) {
1434203108Smav			reset_ccb = xpt_alloc_ccb_nowait();
1435208823Smav			if (reset_ccb == NULL) {
1436208823Smav				request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1437208823Smav				xpt_free_ccb(work_ccb);
1438208823Smav				xpt_done(request_ccb);
1439208823Smav				return;
1440208823Smav			}
1441203108Smav			xpt_setup_ccb(&reset_ccb->ccb_h, request_ccb->ccb_h.path,
1442203108Smav			      CAM_PRIORITY_NONE);
1443203108Smav			reset_ccb->ccb_h.func_code = XPT_RESET_BUS;
1444203108Smav			xpt_action(reset_ccb);
1445203108Smav			if (reset_ccb->ccb_h.status != CAM_REQ_CMP) {
1446203108Smav				request_ccb->ccb_h.status = reset_ccb->ccb_h.status;
1447203108Smav				xpt_free_ccb(reset_ccb);
1448203108Smav				xpt_free_ccb(work_ccb);
1449203108Smav				xpt_done(request_ccb);
1450203108Smav				return;
1451203108Smav			}
1452203108Smav			xpt_free_ccb(reset_ccb);
1453203108Smav		}
1454203108Smav
1455195534Sscottl		/* Save some state for use while we probe for devices */
1456195534Sscottl		scan_info = (ata_scan_bus_info *)
1457195534Sscottl		    malloc(sizeof(ata_scan_bus_info), M_CAMXPT, M_NOWAIT);
1458195534Sscottl		if (scan_info == NULL) {
1459195534Sscottl			request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1460208823Smav			xpt_free_ccb(work_ccb);
1461195534Sscottl			xpt_done(request_ccb);
1462195534Sscottl			return;
1463195534Sscottl		}
1464195534Sscottl		scan_info->request_ccb = request_ccb;
1465195534Sscottl		scan_info->cpi = &work_ccb->cpi;
1466195534Sscottl		/* If PM supported, probe it first. */
1467195534Sscottl		if (scan_info->cpi->hba_inquiry & PI_SATAPM)
1468201990Smav			scan_info->counter = scan_info->cpi->max_target;
1469201990Smav		else
1470201990Smav			scan_info->counter = 0;
1471195534Sscottl
1472195534Sscottl		work_ccb = xpt_alloc_ccb_nowait();
1473195534Sscottl		if (work_ccb == NULL) {
1474195534Sscottl			free(scan_info, M_CAMXPT);
1475195534Sscottl			request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1476195534Sscottl			xpt_done(request_ccb);
1477195534Sscottl			break;
1478195534Sscottl		}
1479256843Smav		mtx = xpt_path_mtx(scan_info->request_ccb->ccb_h.path);
1480195534Sscottl		goto scan_next;
1481195534Sscottl	case XPT_SCAN_LUN:
1482195534Sscottl		work_ccb = request_ccb;
1483195534Sscottl		/* Reuse the same CCB to query if a device was really found */
1484195534Sscottl		scan_info = (ata_scan_bus_info *)work_ccb->ccb_h.ppriv_ptr0;
1485256843Smav		mtx = xpt_path_mtx(scan_info->request_ccb->ccb_h.path);
1486256843Smav		mtx_lock(mtx);
1487198389Smav		/* If there is PMP... */
1488201990Smav		if ((scan_info->cpi->hba_inquiry & PI_SATAPM) &&
1489201990Smav		    (scan_info->counter == scan_info->cpi->max_target)) {
1490203108Smav			if (work_ccb->ccb_h.status == CAM_REQ_CMP) {
1491207428Smav				/* everything else will be probed by it */
1492207428Smav				/* Free the current request path- we're done with it. */
1493207428Smav				xpt_free_path(work_ccb->ccb_h.path);
1494201990Smav				goto done;
1495195534Sscottl			} else {
1496195534Sscottl				struct ccb_trans_settings cts;
1497195534Sscottl
1498195534Sscottl				/* Report SIM that PM is absent. */
1499195534Sscottl				bzero(&cts, sizeof(cts));
1500195534Sscottl				xpt_setup_ccb(&cts.ccb_h,
1501207428Smav				    work_ccb->ccb_h.path, CAM_PRIORITY_NONE);
1502195534Sscottl				cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
1503195534Sscottl				cts.type = CTS_TYPE_CURRENT_SETTINGS;
1504195665Smav				cts.xport_specific.sata.pm_present = 0;
1505195534Sscottl				cts.xport_specific.sata.valid = CTS_SATA_VALID_PM;
1506195534Sscottl				xpt_action((union ccb *)&cts);
1507195534Sscottl			}
1508195534Sscottl		}
1509207428Smav		/* Free the current request path- we're done with it. */
1510207428Smav		xpt_free_path(work_ccb->ccb_h.path);
1511201990Smav		if (scan_info->counter ==
1512201990Smav		    ((scan_info->cpi->hba_inquiry & PI_SATAPM) ?
1513201990Smav		    0 : scan_info->cpi->max_target)) {
1514201990Smavdone:
1515256843Smav			mtx_unlock(mtx);
1516195534Sscottl			xpt_free_ccb(work_ccb);
1517195534Sscottl			xpt_free_ccb((union ccb *)scan_info->cpi);
1518195534Sscottl			request_ccb = scan_info->request_ccb;
1519195534Sscottl			free(scan_info, M_CAMXPT);
1520195534Sscottl			request_ccb->ccb_h.status = CAM_REQ_CMP;
1521195534Sscottl			xpt_done(request_ccb);
1522195534Sscottl			break;
1523195534Sscottl		}
1524201990Smav		/* Take next device. Wrap from max (PMP) to 0. */
1525201990Smav		scan_info->counter = (scan_info->counter + 1 ) %
1526201990Smav		    (scan_info->cpi->max_target + 1);
1527195534Sscottlscan_next:
1528249468Smav		status = xpt_create_path(&path, NULL,
1529195534Sscottl		    scan_info->request_ccb->ccb_h.path_id,
1530195534Sscottl		    scan_info->counter, 0);
1531195534Sscottl		if (status != CAM_REQ_CMP) {
1532256843Smav			if (request_ccb->ccb_h.func_code == XPT_SCAN_LUN)
1533256843Smav				mtx_unlock(mtx);
1534195534Sscottl			printf("xpt_scan_bus: xpt_create_path failed"
1535195534Sscottl			    " with status %#x, bus scan halted\n",
1536195534Sscottl			    status);
1537195534Sscottl			xpt_free_ccb(work_ccb);
1538195534Sscottl			xpt_free_ccb((union ccb *)scan_info->cpi);
1539195534Sscottl			request_ccb = scan_info->request_ccb;
1540195534Sscottl			free(scan_info, M_CAMXPT);
1541195534Sscottl			request_ccb->ccb_h.status = status;
1542195534Sscottl			xpt_done(request_ccb);
1543195534Sscottl			break;
1544195534Sscottl		}
1545195534Sscottl		xpt_setup_ccb(&work_ccb->ccb_h, path,
1546195534Sscottl		    scan_info->request_ccb->ccb_h.pinfo.priority);
1547195534Sscottl		work_ccb->ccb_h.func_code = XPT_SCAN_LUN;
1548195534Sscottl		work_ccb->ccb_h.cbfcnp = ata_scan_bus;
1549256843Smav		work_ccb->ccb_h.flags |= CAM_UNLOCKED;
1550195534Sscottl		work_ccb->ccb_h.ppriv_ptr0 = scan_info;
1551195534Sscottl		work_ccb->crcn.flags = scan_info->request_ccb->crcn.flags;
1552256843Smav		mtx_unlock(mtx);
1553256843Smav		if (request_ccb->ccb_h.func_code == XPT_SCAN_LUN)
1554256843Smav			mtx = NULL;
1555195534Sscottl		xpt_action(work_ccb);
1556256843Smav		if (mtx != NULL)
1557256843Smav			mtx_lock(mtx);
1558195534Sscottl		break;
1559195534Sscottl	default:
1560195534Sscottl		break;
1561195534Sscottl	}
1562195534Sscottl}
1563195534Sscottl
1564195534Sscottlstatic void
1565195534Sscottlata_scan_lun(struct cam_periph *periph, struct cam_path *path,
1566195534Sscottl	     cam_flags flags, union ccb *request_ccb)
1567195534Sscottl{
1568195534Sscottl	struct ccb_pathinq cpi;
1569195534Sscottl	cam_status status;
1570195534Sscottl	struct cam_path *new_path;
1571195534Sscottl	struct cam_periph *old_periph;
1572256843Smav	int lock;
1573195534Sscottl
1574203108Smav	CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_scan_lun\n"));
1575195534Sscottl
1576350804Smav	xpt_path_inq(&cpi, path);
1577195534Sscottl	if (cpi.ccb_h.status != CAM_REQ_CMP) {
1578195534Sscottl		if (request_ccb != NULL) {
1579195534Sscottl			request_ccb->ccb_h.status = cpi.ccb_h.status;
1580195534Sscottl			xpt_done(request_ccb);
1581195534Sscottl		}
1582195534Sscottl		return;
1583195534Sscottl	}
1584195534Sscottl
1585195534Sscottl	if (request_ccb == NULL) {
1586241455Smav		request_ccb = xpt_alloc_ccb_nowait();
1587195534Sscottl		if (request_ccb == NULL) {
1588195534Sscottl			xpt_print(path, "xpt_scan_lun: can't allocate CCB, "
1589195534Sscottl			    "can't continue\n");
1590195534Sscottl			return;
1591195534Sscottl		}
1592249468Smav		status = xpt_create_path(&new_path, NULL,
1593195534Sscottl					  path->bus->path_id,
1594195534Sscottl					  path->target->target_id,
1595195534Sscottl					  path->device->lun_id);
1596195534Sscottl		if (status != CAM_REQ_CMP) {
1597241455Smav			xpt_print(path, "xpt_scan_lun: can't create path, "
1598195534Sscottl			    "can't continue\n");
1599241455Smav			xpt_free_ccb(request_ccb);
1600195534Sscottl			return;
1601195534Sscottl		}
1602203108Smav		xpt_setup_ccb(&request_ccb->ccb_h, new_path, CAM_PRIORITY_XPT);
1603195534Sscottl		request_ccb->ccb_h.cbfcnp = xptscandone;
1604256843Smav		request_ccb->ccb_h.flags |= CAM_UNLOCKED;
1605195534Sscottl		request_ccb->ccb_h.func_code = XPT_SCAN_LUN;
1606195534Sscottl		request_ccb->crcn.flags = flags;
1607195534Sscottl	}
1608195534Sscottl
1609256843Smav	lock = (xpt_path_owned(path) == 0);
1610256843Smav	if (lock)
1611256843Smav		xpt_path_lock(path);
1612195653Smav	if ((old_periph = cam_periph_find(path, "aprobe")) != NULL) {
1613236228Smav		if ((old_periph->flags & CAM_PERIPH_INVALID) == 0) {
1614236228Smav			probe_softc *softc;
1615195534Sscottl
1616236228Smav			softc = (probe_softc *)old_periph->softc;
1617236228Smav			TAILQ_INSERT_TAIL(&softc->request_ccbs,
1618236228Smav				&request_ccb->ccb_h, periph_links.tqe);
1619236228Smav			softc->restart = 1;
1620236228Smav		} else {
1621236228Smav			request_ccb->ccb_h.status = CAM_REQ_CMP_ERR;
1622236228Smav			xpt_done(request_ccb);
1623236228Smav		}
1624195534Sscottl	} else {
1625195534Sscottl		status = cam_periph_alloc(proberegister, NULL, probecleanup,
1626195653Smav					  probestart, "aprobe",
1627195534Sscottl					  CAM_PERIPH_BIO,
1628195534Sscottl					  request_ccb->ccb_h.path, NULL, 0,
1629195534Sscottl					  request_ccb);
1630195534Sscottl
1631195534Sscottl		if (status != CAM_REQ_CMP) {
1632195534Sscottl			xpt_print(path, "xpt_scan_lun: cam_alloc_periph "
1633195534Sscottl			    "returned an error, can't continue probe\n");
1634195534Sscottl			request_ccb->ccb_h.status = status;
1635195534Sscottl			xpt_done(request_ccb);
1636195534Sscottl		}
1637195534Sscottl	}
1638256843Smav	if (lock)
1639256843Smav		xpt_path_unlock(path);
1640195534Sscottl}
1641195534Sscottl
1642195534Sscottlstatic void
1643195534Sscottlxptscandone(struct cam_periph *periph, union ccb *done_ccb)
1644195534Sscottl{
1645241455Smav
1646241455Smav	xpt_free_path(done_ccb->ccb_h.path);
1647241455Smav	xpt_free_ccb(done_ccb);
1648195534Sscottl}
1649195534Sscottl
1650195534Sscottlstatic struct cam_ed *
1651195534Sscottlata_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id)
1652195534Sscottl{
1653199178Smav	struct ata_quirk_entry *quirk;
1654195534Sscottl	struct cam_ed *device;
1655195534Sscottl
1656195534Sscottl	device = xpt_alloc_device(bus, target, lun_id);
1657195534Sscottl	if (device == NULL)
1658195534Sscottl		return (NULL);
1659195534Sscottl
1660195534Sscottl	/*
1661195534Sscottl	 * Take the default quirk entry until we have inquiry
1662195534Sscottl	 * data and can determine a better quirk to use.
1663195534Sscottl	 */
1664298411Spfg	quirk = &ata_quirk_table[nitems(ata_quirk_table) - 1];
1665195534Sscottl	device->quirk = (void *)quirk;
1666199178Smav	device->mintags = 0;
1667199178Smav	device->maxtags = 0;
1668195534Sscottl	bzero(&device->inq_data, sizeof(device->inq_data));
1669195534Sscottl	device->inq_flags = 0;
1670195534Sscottl	device->queue_flags = 0;
1671195534Sscottl	device->serial_num = NULL;
1672195534Sscottl	device->serial_num_len = 0;
1673195534Sscottl	return (device);
1674195534Sscottl}
1675195534Sscottl
1676195534Sscottlstatic void
1677195534Sscottlata_device_transport(struct cam_path *path)
1678195534Sscottl{
1679195534Sscottl	struct ccb_pathinq cpi;
1680198331Smav	struct ccb_trans_settings cts;
1681198331Smav	struct scsi_inquiry_data *inq_buf = NULL;
1682198331Smav	struct ata_params *ident_buf = NULL;
1683195534Sscottl
1684195534Sscottl	/* Get transport information from the SIM */
1685350804Smav	xpt_path_inq(&cpi, path);
1686195534Sscottl
1687195534Sscottl	path->device->transport = cpi.transport;
1688198331Smav	if ((path->device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0)
1689198331Smav		inq_buf = &path->device->inq_data;
1690198331Smav	if ((path->device->flags & CAM_DEV_IDENTIFY_DATA_VALID) != 0)
1691198331Smav		ident_buf = &path->device->ident_data;
1692198331Smav	if (path->device->protocol == PROTO_ATA) {
1693198331Smav		path->device->protocol_version = ident_buf ?
1694198331Smav		    ata_version(ident_buf->version_major) : cpi.protocol_version;
1695198331Smav	} else if (path->device->protocol == PROTO_SCSI) {
1696198331Smav		path->device->protocol_version = inq_buf ?
1697198331Smav		    SID_ANSI_REV(inq_buf) : cpi.protocol_version;
1698195534Sscottl	}
1699198331Smav	path->device->transport_version = ident_buf ?
1700198331Smav	    ata_version(ident_buf->version_major) : cpi.transport_version;
1701195534Sscottl
1702195534Sscottl	/* Tell the controller what we think */
1703203108Smav	xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
1704195534Sscottl	cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
1705195534Sscottl	cts.type = CTS_TYPE_CURRENT_SETTINGS;
1706195534Sscottl	cts.transport = path->device->transport;
1707195534Sscottl	cts.transport_version = path->device->transport_version;
1708195534Sscottl	cts.protocol = path->device->protocol;
1709195534Sscottl	cts.protocol_version = path->device->protocol_version;
1710195534Sscottl	cts.proto_specific.valid = 0;
1711203376Smav	if (ident_buf) {
1712203376Smav		if (path->device->transport == XPORT_ATA) {
1713223019Smav			cts.xport_specific.ata.atapi =
1714223019Smav			    (ident_buf->config == ATA_PROTO_CFA) ? 0 :
1715203376Smav			    ((ident_buf->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_16) ? 16 :
1716203376Smav			    ((ident_buf->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12) ? 12 : 0;
1717203376Smav			cts.xport_specific.ata.valid = CTS_ATA_VALID_ATAPI;
1718203376Smav		} else {
1719223019Smav			cts.xport_specific.sata.atapi =
1720223019Smav			    (ident_buf->config == ATA_PROTO_CFA) ? 0 :
1721203376Smav			    ((ident_buf->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_16) ? 16 :
1722203376Smav			    ((ident_buf->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12) ? 12 : 0;
1723203376Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_ATAPI;
1724203376Smav		}
1725203376Smav	} else
1726203376Smav		cts.xport_specific.valid = 0;
1727195534Sscottl	xpt_action((union ccb *)&cts);
1728195534Sscottl}
1729195534Sscottl
1730195534Sscottlstatic void
1731223443Swillata_dev_advinfo(union ccb *start_ccb)
1732223443Swill{
1733223443Swill	struct cam_ed *device;
1734223443Swill	struct ccb_dev_advinfo *cdai;
1735351754Smav	off_t amt;
1736223443Swill
1737351754Smav	xpt_path_assert(start_ccb->ccb_h.path, MA_OWNED);
1738223443Swill	start_ccb->ccb_h.status = CAM_REQ_INVALID;
1739223443Swill	device = start_ccb->ccb_h.path->device;
1740223443Swill	cdai = &start_ccb->cdai;
1741223443Swill	switch(cdai->buftype) {
1742235897Smav	case CDAI_TYPE_SCSI_DEVID:
1743235897Smav		if (cdai->flags & CDAI_FLAG_STORE)
1744235897Smav			return;
1745235897Smav		cdai->provsiz = device->device_id_len;
1746235897Smav		if (device->device_id_len == 0)
1747235897Smav			break;
1748235897Smav		amt = device->device_id_len;
1749235897Smav		if (cdai->provsiz > cdai->bufsiz)
1750235897Smav			amt = cdai->bufsiz;
1751235897Smav		memcpy(cdai->buf, device->device_id, amt);
1752235897Smav		break;
1753223443Swill	case CDAI_TYPE_SERIAL_NUM:
1754223443Swill		if (cdai->flags & CDAI_FLAG_STORE)
1755235897Smav			return;
1756223443Swill		cdai->provsiz = device->serial_num_len;
1757223443Swill		if (device->serial_num_len == 0)
1758223443Swill			break;
1759223443Swill		amt = device->serial_num_len;
1760223443Swill		if (cdai->provsiz > cdai->bufsiz)
1761223443Swill			amt = cdai->bufsiz;
1762223443Swill		memcpy(cdai->buf, device->serial_num, amt);
1763223443Swill		break;
1764235897Smav	case CDAI_TYPE_PHYS_PATH:
1765235897Smav		if (cdai->flags & CDAI_FLAG_STORE) {
1766235897Smav			if (device->physpath != NULL)
1767235897Smav				free(device->physpath, M_CAMXPT);
1768235897Smav			device->physpath_len = cdai->bufsiz;
1769235897Smav			/* Clear existing buffer if zero length */
1770235897Smav			if (cdai->bufsiz == 0)
1771235897Smav				break;
1772235897Smav			device->physpath = malloc(cdai->bufsiz, M_CAMXPT, M_NOWAIT);
1773235897Smav			if (device->physpath == NULL) {
1774235897Smav				start_ccb->ccb_h.status = CAM_REQ_ABORTED;
1775235897Smav				return;
1776235897Smav			}
1777235897Smav			memcpy(device->physpath, cdai->buf, cdai->bufsiz);
1778235897Smav		} else {
1779235897Smav			cdai->provsiz = device->physpath_len;
1780235897Smav			if (device->physpath_len == 0)
1781235897Smav				break;
1782235897Smav			amt = device->physpath_len;
1783235897Smav			if (cdai->provsiz > cdai->bufsiz)
1784235897Smav				amt = cdai->bufsiz;
1785235897Smav			memcpy(cdai->buf, device->physpath, amt);
1786235897Smav		}
1787235897Smav		break;
1788223443Swill	default:
1789235897Smav		return;
1790223443Swill	}
1791235897Smav	start_ccb->ccb_h.status = CAM_REQ_CMP;
1792235897Smav
1793235897Smav	if (cdai->flags & CDAI_FLAG_STORE) {
1794235897Smav		xpt_async(AC_ADVINFO_CHANGED, start_ccb->ccb_h.path,
1795235897Smav			  (void *)(uintptr_t)cdai->buftype);
1796235897Smav	}
1797223443Swill}
1798223443Swill
1799223443Swillstatic void
1800195534Sscottlata_action(union ccb *start_ccb)
1801195534Sscottl{
1802195534Sscottl
1803195534Sscottl	switch (start_ccb->ccb_h.func_code) {
1804195534Sscottl	case XPT_SET_TRAN_SETTINGS:
1805195534Sscottl	{
1806199178Smav		ata_set_transfer_settings(&start_ccb->cts,
1807256843Smav					   start_ccb->ccb_h.path,
1808195534Sscottl					   /*async_update*/FALSE);
1809195534Sscottl		break;
1810195534Sscottl	}
1811195534Sscottl	case XPT_SCAN_BUS:
1812208582Smjacob	case XPT_SCAN_TGT:
1813195534Sscottl		ata_scan_bus(start_ccb->ccb_h.path->periph, start_ccb);
1814195534Sscottl		break;
1815195534Sscottl	case XPT_SCAN_LUN:
1816195534Sscottl		ata_scan_lun(start_ccb->ccb_h.path->periph,
1817195534Sscottl			      start_ccb->ccb_h.path, start_ccb->crcn.flags,
1818195534Sscottl			      start_ccb);
1819195534Sscottl		break;
1820195534Sscottl	case XPT_GET_TRAN_SETTINGS:
1821195534Sscottl	{
1822236437Smav		ata_get_transfer_settings(&start_ccb->cts);
1823195534Sscottl		break;
1824195534Sscottl	}
1825203376Smav	case XPT_SCSI_IO:
1826203376Smav	{
1827203376Smav		struct cam_ed *device;
1828203376Smav		u_int	maxlen = 0;
1829203376Smav
1830203376Smav		device = start_ccb->ccb_h.path->device;
1831203376Smav		if (device->protocol == PROTO_SCSI &&
1832203376Smav		    (device->flags & CAM_DEV_IDENTIFY_DATA_VALID)) {
1833203376Smav			uint16_t p =
1834203376Smav			    device->ident_data.config & ATA_PROTO_MASK;
1835203376Smav
1836223019Smav			maxlen =
1837223019Smav			    (device->ident_data.config == ATA_PROTO_CFA) ? 0 :
1838223019Smav			    (p == ATA_PROTO_ATAPI_16) ? 16 :
1839203376Smav			    (p == ATA_PROTO_ATAPI_12) ? 12 : 0;
1840203376Smav		}
1841203376Smav		if (start_ccb->csio.cdb_len > maxlen) {
1842203376Smav			start_ccb->ccb_h.status = CAM_REQ_INVALID;
1843203376Smav			xpt_done(start_ccb);
1844203376Smav			break;
1845203376Smav		}
1846223475Smav		xpt_action_default(start_ccb);
1847223475Smav		break;
1848203376Smav	}
1849223443Swill	case XPT_DEV_ADVINFO:
1850223443Swill	{
1851223443Swill		ata_dev_advinfo(start_ccb);
1852223443Swill		break;
1853223443Swill	}
1854195534Sscottl	default:
1855195534Sscottl		xpt_action_default(start_ccb);
1856195534Sscottl		break;
1857195534Sscottl	}
1858195534Sscottl}
1859195534Sscottl
1860195534Sscottlstatic void
1861236437Smavata_get_transfer_settings(struct ccb_trans_settings *cts)
1862236437Smav{
1863236437Smav	struct	ccb_trans_settings_ata *ata;
1864236437Smav	struct	ccb_trans_settings_scsi *scsi;
1865236437Smav	struct	cam_ed *device;
1866236437Smav
1867236437Smav	device = cts->ccb_h.path->device;
1868256843Smav	xpt_action_default((union ccb *)cts);
1869236437Smav
1870236666Smav	if (cts->protocol == PROTO_UNKNOWN ||
1871236666Smav	    cts->protocol == PROTO_UNSPECIFIED) {
1872236666Smav		cts->protocol = device->protocol;
1873236666Smav		cts->protocol_version = device->protocol_version;
1874236666Smav	}
1875236666Smav
1876236437Smav	if (cts->protocol == PROTO_ATA) {
1877236437Smav		ata = &cts->proto_specific.ata;
1878236437Smav		if ((ata->valid & CTS_ATA_VALID_TQ) == 0) {
1879236437Smav			ata->valid |= CTS_ATA_VALID_TQ;
1880236437Smav			if (cts->type == CTS_TYPE_USER_SETTINGS ||
1881236437Smav			    (device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 ||
1882236437Smav			    (device->inq_flags & SID_CmdQue) != 0)
1883236437Smav				ata->flags |= CTS_ATA_FLAGS_TAG_ENB;
1884236437Smav		}
1885236437Smav	}
1886236437Smav	if (cts->protocol == PROTO_SCSI) {
1887236437Smav		scsi = &cts->proto_specific.scsi;
1888236437Smav		if ((scsi->valid & CTS_SCSI_VALID_TQ) == 0) {
1889236437Smav			scsi->valid |= CTS_SCSI_VALID_TQ;
1890236437Smav			if (cts->type == CTS_TYPE_USER_SETTINGS ||
1891236437Smav			    (device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 ||
1892236437Smav			    (device->inq_flags & SID_CmdQue) != 0)
1893236437Smav				scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
1894236437Smav		}
1895236437Smav	}
1896236666Smav
1897236666Smav	if (cts->transport == XPORT_UNKNOWN ||
1898236666Smav	    cts->transport == XPORT_UNSPECIFIED) {
1899236666Smav		cts->transport = device->transport;
1900236666Smav		cts->transport_version = device->transport_version;
1901236666Smav	}
1902236437Smav}
1903236437Smav
1904236437Smavstatic void
1905256843Smavata_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_path *path,
1906195534Sscottl			   int async_update)
1907195534Sscottl{
1908195534Sscottl	struct	ccb_pathinq cpi;
1909236437Smav	struct	ccb_trans_settings_ata *ata;
1910195534Sscottl	struct	ccb_trans_settings_scsi *scsi;
1911236437Smav	struct	ata_params *ident_data;
1912195534Sscottl	struct	scsi_inquiry_data *inq_data;
1913256843Smav	struct	cam_ed *device;
1914195534Sscottl
1915256843Smav	if (path == NULL || (device = path->device) == NULL) {
1916195534Sscottl		cts->ccb_h.status = CAM_PATH_INVALID;
1917195534Sscottl		xpt_done((union ccb *)cts);
1918195534Sscottl		return;
1919195534Sscottl	}
1920195534Sscottl
1921195534Sscottl	if (cts->protocol == PROTO_UNKNOWN
1922195534Sscottl	 || cts->protocol == PROTO_UNSPECIFIED) {
1923195534Sscottl		cts->protocol = device->protocol;
1924195534Sscottl		cts->protocol_version = device->protocol_version;
1925195534Sscottl	}
1926195534Sscottl
1927195534Sscottl	if (cts->protocol_version == PROTO_VERSION_UNKNOWN
1928195534Sscottl	 || cts->protocol_version == PROTO_VERSION_UNSPECIFIED)
1929195534Sscottl		cts->protocol_version = device->protocol_version;
1930195534Sscottl
1931195534Sscottl	if (cts->protocol != device->protocol) {
1932256843Smav		xpt_print(path, "Uninitialized Protocol %x:%x?\n",
1933195534Sscottl		       cts->protocol, device->protocol);
1934195534Sscottl		cts->protocol = device->protocol;
1935195534Sscottl	}
1936195534Sscottl
1937195534Sscottl	if (cts->protocol_version > device->protocol_version) {
1938195534Sscottl		if (bootverbose) {
1939256843Smav			xpt_print(path, "Down reving Protocol "
1940195534Sscottl			    "Version from %d to %d?\n", cts->protocol_version,
1941195534Sscottl			    device->protocol_version);
1942195534Sscottl		}
1943195534Sscottl		cts->protocol_version = device->protocol_version;
1944195534Sscottl	}
1945195534Sscottl
1946195534Sscottl	if (cts->transport == XPORT_UNKNOWN
1947195534Sscottl	 || cts->transport == XPORT_UNSPECIFIED) {
1948195534Sscottl		cts->transport = device->transport;
1949195534Sscottl		cts->transport_version = device->transport_version;
1950195534Sscottl	}
1951195534Sscottl
1952195534Sscottl	if (cts->transport_version == XPORT_VERSION_UNKNOWN
1953195534Sscottl	 || cts->transport_version == XPORT_VERSION_UNSPECIFIED)
1954195534Sscottl		cts->transport_version = device->transport_version;
1955195534Sscottl
1956195534Sscottl	if (cts->transport != device->transport) {
1957256843Smav		xpt_print(path, "Uninitialized Transport %x:%x?\n",
1958195534Sscottl		    cts->transport, device->transport);
1959195534Sscottl		cts->transport = device->transport;
1960195534Sscottl	}
1961195534Sscottl
1962195534Sscottl	if (cts->transport_version > device->transport_version) {
1963195534Sscottl		if (bootverbose) {
1964256843Smav			xpt_print(path, "Down reving Transport "
1965195534Sscottl			    "Version from %d to %d?\n", cts->transport_version,
1966195534Sscottl			    device->transport_version);
1967195534Sscottl		}
1968195534Sscottl		cts->transport_version = device->transport_version;
1969195534Sscottl	}
1970195534Sscottl
1971236437Smav	ident_data = &device->ident_data;
1972195534Sscottl	inq_data = &device->inq_data;
1973236437Smav	if (cts->protocol == PROTO_ATA)
1974236437Smav		ata = &cts->proto_specific.ata;
1975236437Smav	else
1976236437Smav		ata = NULL;
1977236437Smav	if (cts->protocol == PROTO_SCSI)
1978236437Smav		scsi = &cts->proto_specific.scsi;
1979236437Smav	else
1980236437Smav		scsi = NULL;
1981350804Smav	xpt_path_inq(&cpi, path);
1982195534Sscottl
1983236437Smav	/* Sanity checking */
1984195534Sscottl	if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0
1985236437Smav	 || (ata && (ident_data->satacapabilities & ATA_SUPPORT_NCQ) == 0)
1986236437Smav	 || (scsi && (INQ_DATA_TQ_ENABLED(inq_data)) == 0)
1987195534Sscottl	 || (device->queue_flags & SCP_QUEUE_DQUE) != 0
1988195534Sscottl	 || (device->mintags == 0)) {
1989195534Sscottl		/*
1990195534Sscottl		 * Can't tag on hardware that doesn't support tags,
1991195534Sscottl		 * doesn't have it enabled, or has broken tag support.
1992195534Sscottl		 */
1993236437Smav		if (ata)
1994236437Smav			ata->flags &= ~CTS_ATA_FLAGS_TAG_ENB;
1995236437Smav		if (scsi)
1996195534Sscottl			scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
1997195534Sscottl	}
1998195534Sscottl
1999236437Smav	/* Start/stop tags use. */
2000236437Smav	if (cts->type == CTS_TYPE_CURRENT_SETTINGS &&
2001236437Smav	    ((ata && (ata->valid & CTS_ATA_VALID_TQ) != 0) ||
2002236437Smav	     (scsi && (scsi->valid & CTS_SCSI_VALID_TQ) != 0))) {
2003236437Smav		int nowt, newt = 0;
2004195534Sscottl
2005236437Smav		nowt = ((device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 ||
2006236437Smav			(device->inq_flags & SID_CmdQue) != 0);
2007236437Smav		if (ata)
2008236437Smav			newt = (ata->flags & CTS_ATA_FLAGS_TAG_ENB) != 0;
2009236437Smav		if (scsi)
2010236437Smav			newt = (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0;
2011195534Sscottl
2012236437Smav		if (newt && !nowt) {
2013236437Smav			/*
2014236437Smav			 * Delay change to use tags until after a
2015236437Smav			 * few commands have gone to this device so
2016236437Smav			 * the controller has time to perform transfer
2017236437Smav			 * negotiations without tagged messages getting
2018236437Smav			 * in the way.
2019236437Smav			 */
2020236437Smav			device->tag_delay_count = CAM_TAG_DELAY_COUNT;
2021236437Smav			device->flags |= CAM_DEV_TAG_AFTER_COUNT;
2022236437Smav		} else if (nowt && !newt)
2023256843Smav			xpt_stop_tags(path);
2024236437Smav	}
2025195534Sscottl
2026195534Sscottl	if (async_update == FALSE)
2027256843Smav		xpt_action_default((union ccb *)cts);
2028195534Sscottl}
2029195534Sscottl
2030195534Sscottl/*
2031195534Sscottl * Handle any per-device event notifications that require action by the XPT.
2032195534Sscottl */
2033195534Sscottlstatic void
2034195534Sscottlata_dev_async(u_int32_t async_code, struct cam_eb *bus, struct cam_et *target,
2035195534Sscottl	      struct cam_ed *device, void *async_arg)
2036195534Sscottl{
2037195534Sscottl	cam_status status;
2038195534Sscottl	struct cam_path newpath;
2039195534Sscottl
2040195534Sscottl	/*
2041195534Sscottl	 * We only need to handle events for real devices.
2042195534Sscottl	 */
2043195534Sscottl	if (target->target_id == CAM_TARGET_WILDCARD
2044195534Sscottl	 || device->lun_id == CAM_LUN_WILDCARD)
2045195534Sscottl		return;
2046195534Sscottl
2047195534Sscottl	/*
2048195534Sscottl	 * We need our own path with wildcards expanded to
2049195534Sscottl	 * handle certain types of events.
2050195534Sscottl	 */
2051195534Sscottl	if ((async_code == AC_SENT_BDR)
2052195534Sscottl	 || (async_code == AC_BUS_RESET)
2053195534Sscottl	 || (async_code == AC_INQ_CHANGED))
2054195534Sscottl		status = xpt_compile_path(&newpath, NULL,
2055195534Sscottl					  bus->path_id,
2056195534Sscottl					  target->target_id,
2057195534Sscottl					  device->lun_id);
2058195534Sscottl	else
2059195534Sscottl		status = CAM_REQ_CMP_ERR;
2060195534Sscottl
2061195534Sscottl	if (status == CAM_REQ_CMP) {
2062195534Sscottl		if (async_code == AC_INQ_CHANGED) {
2063195534Sscottl			/*
2064195534Sscottl			 * We've sent a start unit command, or
2065195534Sscottl			 * something similar to a device that
2066195534Sscottl			 * may have caused its inquiry data to
2067195534Sscottl			 * change. So we re-scan the device to
2068195534Sscottl			 * refresh the inquiry data for it.
2069195534Sscottl			 */
2070195534Sscottl			ata_scan_lun(newpath.periph, &newpath,
2071195534Sscottl				     CAM_EXPECT_INQ_CHANGE, NULL);
2072203108Smav		} else {
2073203108Smav			/* We need to reinitialize device after reset. */
2074203108Smav			ata_scan_lun(newpath.periph, &newpath,
2075203108Smav				     0, NULL);
2076195534Sscottl		}
2077195534Sscottl		xpt_release_path(&newpath);
2078198748Smav	} else if (async_code == AC_LOST_DEVICE &&
2079198748Smav	    (device->flags & CAM_DEV_UNCONFIGURED) == 0) {
2080195534Sscottl		device->flags |= CAM_DEV_UNCONFIGURED;
2081198748Smav		xpt_release_device(device);
2082195534Sscottl	} else if (async_code == AC_TRANSFER_NEG) {
2083195534Sscottl		struct ccb_trans_settings *settings;
2084256843Smav		struct cam_path path;
2085195534Sscottl
2086195534Sscottl		settings = (struct ccb_trans_settings *)async_arg;
2087256843Smav		xpt_compile_path(&path, NULL, bus->path_id, target->target_id,
2088256843Smav				 device->lun_id);
2089256843Smav		ata_set_transfer_settings(settings, &path,
2090195534Sscottl					  /*async_update*/TRUE);
2091256843Smav		xpt_release_path(&path);
2092195534Sscottl	}
2093195534Sscottl}
2094195534Sscottl
2095204220Smavstatic void
2096204220Smavata_announce_periph(struct cam_periph *periph)
2097204220Smav{
2098204220Smav	struct	ccb_pathinq cpi;
2099204220Smav	struct	ccb_trans_settings cts;
2100204220Smav	struct	cam_path *path = periph->path;
2101204220Smav	u_int	speed;
2102204220Smav	u_int	mb;
2103204220Smav
2104256843Smav	cam_periph_assert(periph, MA_OWNED);
2105204220Smav
2106204220Smav	xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
2107204220Smav	cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
2108204220Smav	cts.type = CTS_TYPE_CURRENT_SETTINGS;
2109204220Smav	xpt_action((union ccb*)&cts);
2110204220Smav	if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
2111204220Smav		return;
2112204220Smav	/* Ask the SIM for its base transfer speed */
2113350804Smav	xpt_path_inq(&cpi, path);
2114204220Smav	/* Report connection speed */
2115204220Smav	speed = cpi.base_transfer_speed;
2116204220Smav	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_ATA) {
2117236437Smav		struct	ccb_trans_settings_pata *pata =
2118204220Smav		    &cts.xport_specific.ata;
2119204220Smav
2120236437Smav		if (pata->valid & CTS_ATA_VALID_MODE)
2121236437Smav			speed = ata_mode2speed(pata->mode);
2122204220Smav	}
2123204220Smav	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SATA) {
2124204220Smav		struct	ccb_trans_settings_sata *sata =
2125204220Smav		    &cts.xport_specific.sata;
2126204220Smav
2127204220Smav		if (sata->valid & CTS_SATA_VALID_REVISION)
2128204220Smav			speed = ata_revision2speed(sata->revision);
2129204220Smav	}
2130204220Smav	mb = speed / 1000;
2131204220Smav	if (mb > 0)
2132204220Smav		printf("%s%d: %d.%03dMB/s transfers",
2133204220Smav		       periph->periph_name, periph->unit_number,
2134204220Smav		       mb, speed % 1000);
2135204220Smav	else
2136204220Smav		printf("%s%d: %dKB/s transfers", periph->periph_name,
2137204220Smav		       periph->unit_number, speed);
2138204220Smav	/* Report additional information about connection */
2139204220Smav	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_ATA) {
2140236437Smav		struct ccb_trans_settings_pata *pata =
2141204220Smav		    &cts.xport_specific.ata;
2142204220Smav
2143204220Smav		printf(" (");
2144236437Smav		if (pata->valid & CTS_ATA_VALID_MODE)
2145236437Smav			printf("%s, ", ata_mode2string(pata->mode));
2146236437Smav		if ((pata->valid & CTS_ATA_VALID_ATAPI) && pata->atapi != 0)
2147236437Smav			printf("ATAPI %dbytes, ", pata->atapi);
2148236437Smav		if (pata->valid & CTS_ATA_VALID_BYTECOUNT)
2149236437Smav			printf("PIO %dbytes", pata->bytecount);
2150204220Smav		printf(")");
2151204220Smav	}
2152204220Smav	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SATA) {
2153204220Smav		struct ccb_trans_settings_sata *sata =
2154204220Smav		    &cts.xport_specific.sata;
2155204220Smav
2156204220Smav		printf(" (");
2157204220Smav		if (sata->valid & CTS_SATA_VALID_REVISION)
2158204220Smav			printf("SATA %d.x, ", sata->revision);
2159204220Smav		else
2160204220Smav			printf("SATA, ");
2161204220Smav		if (sata->valid & CTS_SATA_VALID_MODE)
2162204220Smav			printf("%s, ", ata_mode2string(sata->mode));
2163204220Smav		if ((sata->valid & CTS_ATA_VALID_ATAPI) && sata->atapi != 0)
2164204220Smav			printf("ATAPI %dbytes, ", sata->atapi);
2165204220Smav		if (sata->valid & CTS_SATA_VALID_BYTECOUNT)
2166204220Smav			printf("PIO %dbytes", sata->bytecount);
2167204220Smav		printf(")");
2168204220Smav	}
2169204220Smav	printf("\n");
2170204220Smav}
2171328820Smav
2172328820Smavstatic void
2173328820Smavata_proto_announce(struct cam_ed *device)
2174328820Smav{
2175328820Smav	ata_print_ident(&device->ident_data);
2176328820Smav}
2177328820Smav
2178328820Smavstatic void
2179328820Smavata_proto_denounce(struct cam_ed *device)
2180328820Smav{
2181328820Smav	ata_print_ident_short(&device->ident_data);
2182328820Smav}
2183328820Smav
2184328820Smavstatic void
2185328820Smavsemb_proto_announce(struct cam_ed *device)
2186328820Smav{
2187328820Smav	semb_print_ident((struct sep_identify_data *)&device->ident_data);
2188328820Smav}
2189328820Smav
2190328820Smavstatic void
2191328820Smavsemb_proto_denounce(struct cam_ed *device)
2192328820Smav{
2193328820Smav	semb_print_ident_short((struct sep_identify_data *)&device->ident_data);
2194328820Smav}
2195328820Smav
2196328820Smavstatic void
2197328820Smavata_proto_debug_out(union ccb *ccb)
2198328820Smav{
2199328820Smav	char cdb_str[(sizeof(struct ata_cmd) * 3) + 1];
2200328820Smav
2201328820Smav	if (ccb->ccb_h.func_code != XPT_ATA_IO)
2202328820Smav		return;
2203328820Smav
2204328820Smav	CAM_DEBUG(ccb->ccb_h.path,
2205328820Smav	    CAM_DEBUG_CDB,("%s. ACB: %s\n", ata_op_string(&ccb->ataio.cmd),
2206328820Smav		ata_cmd_string(&ccb->ataio.cmd, cdb_str, sizeof(cdb_str))));
2207328820Smav}
2208