ata_xpt.c revision 235897
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: head/sys/cam/ata/ata_xpt.c 235897 2012-05-24 11:07:39Z 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/interrupt.h>
41195534Sscottl#include <sys/sbuf.h>
42195534Sscottl
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
68195534Sscottl	u_int maxtags;
69195534Sscottl};
70195534Sscottl
71195534Sscottlstatic periph_init_t probe_periph_init;
72195534Sscottl
73195534Sscottlstatic struct periph_driver probe_driver =
74195534Sscottl{
75195653Smav	probe_periph_init, "aprobe",
76198708Smav	TAILQ_HEAD_INITIALIZER(probe_driver.units), /* generation */ 0,
77198708Smav	CAM_PERIPH_DRV_EARLY
78195534Sscottl};
79195534Sscottl
80195653SmavPERIPHDRIVER_DECLARE(aprobe, probe_driver);
81195534Sscottl
82195534Sscottltypedef enum {
83195534Sscottl	PROBE_RESET,
84195534Sscottl	PROBE_IDENTIFY,
85203421Smav	PROBE_SPINUP,
86195534Sscottl	PROBE_SETMODE,
87207499Smav	PROBE_SETPM,
88207499Smav	PROBE_SETAPST,
89207499Smav	PROBE_SETDMAAA,
90220602Smav	PROBE_SETAN,
91198708Smav	PROBE_SET_MULTI,
92195534Sscottl	PROBE_INQUIRY,
93195534Sscottl	PROBE_FULL_INQUIRY,
94195534Sscottl	PROBE_PM_PID,
95195534Sscottl	PROBE_PM_PRV,
96235897Smav	PROBE_IDENTIFY_SES,
97235897Smav	PROBE_IDENTIFY_SAFTE,
98195534Sscottl	PROBE_INVALID
99195534Sscottl} probe_action;
100195534Sscottl
101195534Sscottlstatic char *probe_action_text[] = {
102195534Sscottl	"PROBE_RESET",
103195534Sscottl	"PROBE_IDENTIFY",
104203421Smav	"PROBE_SPINUP",
105195534Sscottl	"PROBE_SETMODE",
106207499Smav	"PROBE_SETPM",
107207499Smav	"PROBE_SETAPST",
108207499Smav	"PROBE_SETDMAAA",
109220602Smav	"PROBE_SETAN",
110198708Smav	"PROBE_SET_MULTI",
111195534Sscottl	"PROBE_INQUIRY",
112195534Sscottl	"PROBE_FULL_INQUIRY",
113195534Sscottl	"PROBE_PM_PID",
114195534Sscottl	"PROBE_PM_PRV",
115235897Smav	"PROBE_IDENTIFY_SES",
116235897Smav	"PROBE_IDENTIFY_SAFTE",
117195534Sscottl	"PROBE_INVALID"
118195534Sscottl};
119195534Sscottl
120195534Sscottl#define PROBE_SET_ACTION(softc, newaction)	\
121195534Sscottldo {									\
122195534Sscottl	char **text;							\
123195534Sscottl	text = probe_action_text;					\
124195534Sscottl	CAM_DEBUG((softc)->periph->path, CAM_DEBUG_INFO,		\
125195534Sscottl	    ("Probe %s to %s\n", text[(softc)->action],			\
126195534Sscottl	    text[(newaction)]));					\
127195534Sscottl	(softc)->action = (newaction);					\
128195534Sscottl} while(0)
129195534Sscottl
130195534Sscottltypedef enum {
131195534Sscottl	PROBE_NO_ANNOUNCE	= 0x04
132195534Sscottl} probe_flags;
133195534Sscottl
134195534Sscottltypedef struct {
135195534Sscottl	TAILQ_HEAD(, ccb_hdr) request_ccbs;
136203385Smav	struct ata_params	ident_data;
137195534Sscottl	probe_action	action;
138195534Sscottl	probe_flags	flags;
139195534Sscottl	uint32_t	pm_pid;
140195534Sscottl	uint32_t	pm_prv;
141203108Smav	int		restart;
142203421Smav	int		spinup;
143209744Smav	int		faults;
144207499Smav	u_int		caps;
145195534Sscottl	struct cam_periph *periph;
146195534Sscottl} probe_softc;
147195534Sscottl
148199178Smavstatic struct ata_quirk_entry ata_quirk_table[] =
149195534Sscottl{
150195534Sscottl	{
151195534Sscottl		/* Default tagged queuing parameters for all devices */
152195534Sscottl		{
153195534Sscottl		  T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED,
154195534Sscottl		  /*vendor*/"*", /*product*/"*", /*revision*/"*"
155195534Sscottl		},
156199178Smav		/*quirks*/0, /*maxtags*/0
157195534Sscottl	},
158195534Sscottl};
159195534Sscottl
160199178Smavstatic const int ata_quirk_table_size =
161199178Smav	sizeof(ata_quirk_table) / sizeof(*ata_quirk_table);
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);
167195534Sscottl//static void	 proberequestdefaultnegotiation(struct cam_periph *periph);
168195534Sscottl//static int       proberequestbackoff(struct cam_periph *periph,
169195534Sscottl//				     struct cam_ed *device);
170195534Sscottlstatic void	 probedone(struct cam_periph *periph, union ccb *done_ccb);
171195534Sscottlstatic void	 probecleanup(struct cam_periph *periph);
172199178Smavstatic void	 ata_find_quirk(struct cam_ed *device);
173195534Sscottlstatic void	 ata_scan_bus(struct cam_periph *periph, union ccb *ccb);
174195534Sscottlstatic void	 ata_scan_lun(struct cam_periph *periph,
175195534Sscottl			       struct cam_path *path, cam_flags flags,
176195534Sscottl			       union ccb *ccb);
177195534Sscottlstatic void	 xptscandone(struct cam_periph *periph, union ccb *done_ccb);
178195534Sscottlstatic struct cam_ed *
179195534Sscottl		 ata_alloc_device(struct cam_eb *bus, struct cam_et *target,
180195534Sscottl				   lun_id_t lun_id);
181195534Sscottlstatic void	 ata_device_transport(struct cam_path *path);
182199178Smavstatic void	 ata_set_transfer_settings(struct ccb_trans_settings *cts,
183195534Sscottl					    struct cam_ed *device,
184195534Sscottl					    int async_update);
185195534Sscottlstatic void	 ata_dev_async(u_int32_t async_code,
186195534Sscottl				struct cam_eb *bus,
187195534Sscottl				struct cam_et *target,
188195534Sscottl				struct cam_ed *device,
189195534Sscottl				void *async_arg);
190195534Sscottlstatic void	 ata_action(union ccb *start_ccb);
191204220Smavstatic void	 ata_announce_periph(struct cam_periph *periph);
192195534Sscottl
193230912Smavstatic int ata_dma = 1;
194230912Smavstatic int atapi_dma = 1;
195230912Smav
196230912SmavTUNABLE_INT("hw.ata.ata_dma", &ata_dma);
197230912SmavTUNABLE_INT("hw.ata.atapi_dma", &atapi_dma);
198230912Smav
199195534Sscottlstatic struct xpt_xport ata_xport = {
200195534Sscottl	.alloc_device = ata_alloc_device,
201195534Sscottl	.action = ata_action,
202195534Sscottl	.async = ata_dev_async,
203204220Smav	.announce = ata_announce_periph,
204195534Sscottl};
205195534Sscottl
206195534Sscottlstruct xpt_xport *
207195534Sscottlata_get_xport(void)
208195534Sscottl{
209195534Sscottl	return (&ata_xport);
210195534Sscottl}
211195534Sscottl
212195534Sscottlstatic void
213195534Sscottlprobe_periph_init()
214195534Sscottl{
215195534Sscottl}
216195534Sscottl
217195534Sscottlstatic cam_status
218195534Sscottlproberegister(struct cam_periph *periph, void *arg)
219195534Sscottl{
220195534Sscottl	union ccb *request_ccb;	/* CCB representing the probe request */
221195534Sscottl	cam_status status;
222195534Sscottl	probe_softc *softc;
223195534Sscottl
224195534Sscottl	request_ccb = (union ccb *)arg;
225195534Sscottl	if (periph == NULL) {
226195534Sscottl		printf("proberegister: periph was NULL!!\n");
227195534Sscottl		return(CAM_REQ_CMP_ERR);
228195534Sscottl	}
229195534Sscottl
230195534Sscottl	if (request_ccb == NULL) {
231195534Sscottl		printf("proberegister: no probe CCB, "
232195534Sscottl		       "can't register device\n");
233195534Sscottl		return(CAM_REQ_CMP_ERR);
234195534Sscottl	}
235195534Sscottl
236203421Smav	softc = (probe_softc *)malloc(sizeof(*softc), M_CAMXPT, M_ZERO | M_NOWAIT);
237195534Sscottl
238195534Sscottl	if (softc == NULL) {
239195534Sscottl		printf("proberegister: Unable to probe new device. "
240195534Sscottl		       "Unable to allocate softc\n");
241195534Sscottl		return(CAM_REQ_CMP_ERR);
242195534Sscottl	}
243195534Sscottl	TAILQ_INIT(&softc->request_ccbs);
244195534Sscottl	TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h,
245195534Sscottl			  periph_links.tqe);
246195534Sscottl	softc->flags = 0;
247195534Sscottl	periph->softc = softc;
248195534Sscottl	softc->periph = periph;
249195534Sscottl	softc->action = PROBE_INVALID;
250195534Sscottl	status = cam_periph_acquire(periph);
251195534Sscottl	if (status != CAM_REQ_CMP) {
252195534Sscottl		return (status);
253195534Sscottl	}
254195534Sscottl	/*
255203108Smav	 * Ensure nobody slip in until probe finish.
256195534Sscottl	 */
257203108Smav	cam_freeze_devq_arg(periph->path,
258203108Smav	    RELSIM_RELEASE_RUNLEVEL, CAM_RL_XPT + 1);
259195534Sscottl	probeschedule(periph);
260195534Sscottl	return(CAM_REQ_CMP);
261195534Sscottl}
262195534Sscottl
263195534Sscottlstatic void
264195534Sscottlprobeschedule(struct cam_periph *periph)
265195534Sscottl{
266195534Sscottl	union ccb *ccb;
267195534Sscottl	probe_softc *softc;
268195534Sscottl
269195534Sscottl	softc = (probe_softc *)periph->softc;
270195534Sscottl	ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs);
271195534Sscottl
272198389Smav	if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) ||
273235897Smav	    periph->path->device->protocol == PROTO_SATAPM ||
274235897Smav	    periph->path->device->protocol == PROTO_SEMB)
275195534Sscottl		PROBE_SET_ACTION(softc, PROBE_RESET);
276195534Sscottl	else
277195534Sscottl		PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
278195534Sscottl
279195534Sscottl	if (ccb->crcn.flags & CAM_EXPECT_INQ_CHANGE)
280195534Sscottl		softc->flags |= PROBE_NO_ANNOUNCE;
281195534Sscottl	else
282195534Sscottl		softc->flags &= ~PROBE_NO_ANNOUNCE;
283195534Sscottl
284203108Smav	xpt_schedule(periph, CAM_PRIORITY_XPT);
285195534Sscottl}
286195534Sscottl
287195534Sscottlstatic void
288195534Sscottlprobestart(struct cam_periph *periph, union ccb *start_ccb)
289195534Sscottl{
290199747Smav	struct ccb_trans_settings cts;
291195534Sscottl	struct ccb_ataio *ataio;
292195534Sscottl	struct ccb_scsiio *csio;
293195534Sscottl	probe_softc *softc;
294198708Smav	struct cam_path *path;
295198708Smav	struct ata_params *ident_buf;
296195534Sscottl
297195534Sscottl	CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probestart\n"));
298195534Sscottl
299195534Sscottl	softc = (probe_softc *)periph->softc;
300198708Smav	path = start_ccb->ccb_h.path;
301195534Sscottl	ataio = &start_ccb->ataio;
302195534Sscottl	csio = &start_ccb->csio;
303198708Smav	ident_buf = &periph->path->device->ident_data;
304195534Sscottl
305203108Smav	if (softc->restart) {
306203108Smav		softc->restart = 0;
307203108Smav		if ((path->device->flags & CAM_DEV_UNCONFIGURED) ||
308235897Smav		    path->device->protocol == PROTO_SATAPM ||
309235897Smav		    path->device->protocol == PROTO_SEMB)
310203108Smav			softc->action = PROBE_RESET;
311203108Smav		else
312203108Smav			softc->action = PROBE_IDENTIFY;
313203108Smav	}
314195534Sscottl	switch (softc->action) {
315195534Sscottl	case PROBE_RESET:
316195534Sscottl		cam_fill_ataio(ataio,
317195534Sscottl		      0,
318195534Sscottl		      probedone,
319195534Sscottl		      /*flags*/CAM_DIR_NONE,
320198389Smav		      0,
321195534Sscottl		      /*data_ptr*/NULL,
322195534Sscottl		      /*dxfer_len*/0,
323203108Smav		      15 * 1000);
324195534Sscottl		ata_reset_cmd(ataio);
325195534Sscottl		break;
326195534Sscottl	case PROBE_IDENTIFY:
327195534Sscottl		cam_fill_ataio(ataio,
328195534Sscottl		      1,
329195534Sscottl		      probedone,
330195534Sscottl		      /*flags*/CAM_DIR_IN,
331198389Smav		      0,
332203385Smav		      /*data_ptr*/(u_int8_t *)&softc->ident_data,
333203385Smav		      /*dxfer_len*/sizeof(softc->ident_data),
334195534Sscottl		      30 * 1000);
335195534Sscottl		if (periph->path->device->protocol == PROTO_ATA)
336196659Smav			ata_28bit_cmd(ataio, ATA_ATA_IDENTIFY, 0, 0, 0);
337195534Sscottl		else
338196659Smav			ata_28bit_cmd(ataio, ATA_ATAPI_IDENTIFY, 0, 0, 0);
339195534Sscottl		break;
340203421Smav	case PROBE_SPINUP:
341203421Smav		if (bootverbose)
342203421Smav			xpt_print(path, "Spinning up device\n");
343203421Smav		cam_fill_ataio(ataio,
344203421Smav		      1,
345203421Smav		      probedone,
346203421Smav		      /*flags*/CAM_DIR_NONE | CAM_HIGH_POWER,
347203421Smav		      0,
348203421Smav		      /*data_ptr*/NULL,
349203421Smav		      /*dxfer_len*/0,
350203421Smav		      30 * 1000);
351203421Smav		ata_28bit_cmd(ataio, ATA_SETFEATURES, ATA_SF_PUIS_SPINUP, 0, 0);
352203421Smav		break;
353195534Sscottl	case PROBE_SETMODE:
354199747Smav	{
355199747Smav		int mode, wantmode;
356199747Smav
357199747Smav		mode = 0;
358199747Smav		/* Fetch user modes from SIM. */
359199747Smav		bzero(&cts, sizeof(cts));
360203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
361199747Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
362199747Smav		cts.type = CTS_TYPE_USER_SETTINGS;
363199747Smav		xpt_action((union ccb *)&cts);
364199747Smav		if (path->device->transport == XPORT_ATA) {
365199747Smav			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_MODE)
366199747Smav				mode = cts.xport_specific.ata.mode;
367199747Smav		} else {
368199799Smav			if (cts.xport_specific.sata.valid & CTS_SATA_VALID_MODE)
369199747Smav				mode = cts.xport_specific.sata.mode;
370199747Smav		}
371230912Smav		if (periph->path->device->protocol == PROTO_ATA) {
372230912Smav			if (ata_dma == 0 && (mode == 0 || mode > ATA_PIO_MAX))
373230912Smav				mode = ATA_PIO_MAX;
374230912Smav		} else {
375230912Smav			if (atapi_dma == 0 && (mode == 0 || mode > ATA_PIO_MAX))
376230912Smav				mode = ATA_PIO_MAX;
377230912Smav		}
378199747Smavnegotiate:
379199747Smav		/* Honor device capabilities. */
380199747Smav		wantmode = mode = ata_max_mode(ident_buf, mode);
381199747Smav		/* Report modes to SIM. */
382199747Smav		bzero(&cts, sizeof(cts));
383203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
384199747Smav		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
385199747Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
386199747Smav		if (path->device->transport == XPORT_ATA) {
387199747Smav			cts.xport_specific.ata.mode = mode;
388199747Smav			cts.xport_specific.ata.valid = CTS_ATA_VALID_MODE;
389199747Smav		} else {
390199747Smav			cts.xport_specific.sata.mode = mode;
391199747Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_MODE;
392199747Smav		}
393199747Smav		xpt_action((union ccb *)&cts);
394200171Smav		/* Fetch current modes from SIM. */
395199747Smav		bzero(&cts, sizeof(cts));
396203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
397199747Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
398199747Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
399199747Smav		xpt_action((union ccb *)&cts);
400199747Smav		if (path->device->transport == XPORT_ATA) {
401199747Smav			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_MODE)
402199747Smav				mode = cts.xport_specific.ata.mode;
403199747Smav		} else {
404199747Smav			if (cts.xport_specific.ata.valid & CTS_SATA_VALID_MODE)
405199747Smav				mode = cts.xport_specific.sata.mode;
406199747Smav		}
407199747Smav		/* If SIM disagree - renegotiate. */
408199747Smav		if (mode != wantmode)
409199747Smav			goto negotiate;
410220886Smav		/* Remember what transport thinks about DMA. */
411220886Smav		if (mode < ATA_DMA)
412220886Smav			path->device->inq_flags &= ~SID_DMA;
413220886Smav		else
414220886Smav			path->device->inq_flags |= SID_DMA;
415195534Sscottl		cam_fill_ataio(ataio,
416195534Sscottl		      1,
417195534Sscottl		      probedone,
418196353Smav		      /*flags*/CAM_DIR_NONE,
419196353Smav		      0,
420196353Smav		      /*data_ptr*/NULL,
421196353Smav		      /*dxfer_len*/0,
422195534Sscottl		      30 * 1000);
423199747Smav		ata_28bit_cmd(ataio, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
424195534Sscottl		break;
425199747Smav	}
426207499Smav	case PROBE_SETPM:
427207499Smav		cam_fill_ataio(ataio,
428207499Smav		    1,
429207499Smav		    probedone,
430207499Smav		    CAM_DIR_NONE,
431207499Smav		    0,
432207499Smav		    NULL,
433207499Smav		    0,
434207499Smav		    30*1000);
435207499Smav		ata_28bit_cmd(ataio, ATA_SETFEATURES,
436207499Smav		    (softc->caps & CTS_SATA_CAPS_H_PMREQ) ? 0x10 : 0x90,
437207499Smav		    0, 0x03);
438207499Smav		break;
439207499Smav	case PROBE_SETAPST:
440207499Smav		cam_fill_ataio(ataio,
441207499Smav		    1,
442207499Smav		    probedone,
443207499Smav		    CAM_DIR_NONE,
444207499Smav		    0,
445207499Smav		    NULL,
446207499Smav		    0,
447207499Smav		    30*1000);
448207499Smav		ata_28bit_cmd(ataio, ATA_SETFEATURES,
449207499Smav		    (softc->caps & CTS_SATA_CAPS_H_APST) ? 0x10 : 0x90,
450207499Smav		    0, 0x07);
451207499Smav		break;
452207499Smav	case PROBE_SETDMAAA:
453207499Smav		cam_fill_ataio(ataio,
454207499Smav		    1,
455207499Smav		    probedone,
456207499Smav		    CAM_DIR_NONE,
457207499Smav		    0,
458207499Smav		    NULL,
459207499Smav		    0,
460207499Smav		    30*1000);
461207499Smav		ata_28bit_cmd(ataio, ATA_SETFEATURES,
462207499Smav		    (softc->caps & CTS_SATA_CAPS_H_DMAAA) ? 0x10 : 0x90,
463207499Smav		    0, 0x02);
464207499Smav		break;
465220602Smav	case PROBE_SETAN:
466220602Smav		cam_fill_ataio(ataio,
467220602Smav		    1,
468220602Smav		    probedone,
469220602Smav		    CAM_DIR_NONE,
470220602Smav		    0,
471220602Smav		    NULL,
472220602Smav		    0,
473220602Smav		    30*1000);
474220602Smav		ata_28bit_cmd(ataio, ATA_SETFEATURES,
475220602Smav		    (softc->caps & CTS_SATA_CAPS_H_AN) ? 0x10 : 0x90,
476220602Smav		    0, 0x05);
477220602Smav		break;
478198708Smav	case PROBE_SET_MULTI:
479198708Smav	{
480200171Smav		u_int sectors, bytecount;
481198708Smav
482200171Smav		bytecount = 8192;	/* SATA maximum */
483200171Smav		/* Fetch user bytecount from SIM. */
484200171Smav		bzero(&cts, sizeof(cts));
485203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
486200171Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
487200171Smav		cts.type = CTS_TYPE_USER_SETTINGS;
488200171Smav		xpt_action((union ccb *)&cts);
489200171Smav		if (path->device->transport == XPORT_ATA) {
490200171Smav			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_BYTECOUNT)
491200171Smav				bytecount = cts.xport_specific.ata.bytecount;
492200171Smav		} else {
493200171Smav			if (cts.xport_specific.sata.valid & CTS_SATA_VALID_BYTECOUNT)
494200171Smav				bytecount = cts.xport_specific.sata.bytecount;
495200171Smav		}
496200171Smav		/* Honor device capabilities. */
497200171Smav		sectors = max(1, min(ident_buf->sectors_intr & 0xff,
498200171Smav		    bytecount / ata_logical_sector_size(ident_buf)));
499198708Smav		/* Report bytecount to SIM. */
500198708Smav		bzero(&cts, sizeof(cts));
501203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
502198708Smav		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
503198708Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
504198708Smav		if (path->device->transport == XPORT_ATA) {
505198897Smav			cts.xport_specific.ata.bytecount = sectors *
506198897Smav			    ata_logical_sector_size(ident_buf);
507198708Smav			cts.xport_specific.ata.valid = CTS_ATA_VALID_BYTECOUNT;
508198708Smav		} else {
509198897Smav			cts.xport_specific.sata.bytecount = sectors *
510198897Smav			    ata_logical_sector_size(ident_buf);
511198708Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_BYTECOUNT;
512198708Smav		}
513198708Smav		xpt_action((union ccb *)&cts);
514200171Smav		/* Fetch current bytecount from SIM. */
515200171Smav		bzero(&cts, sizeof(cts));
516203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
517200171Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
518200171Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
519200171Smav		xpt_action((union ccb *)&cts);
520200171Smav		if (path->device->transport == XPORT_ATA) {
521200171Smav			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_BYTECOUNT)
522200171Smav				bytecount = cts.xport_specific.ata.bytecount;
523200171Smav		} else {
524200171Smav			if (cts.xport_specific.sata.valid & CTS_SATA_VALID_BYTECOUNT)
525200171Smav				bytecount = cts.xport_specific.sata.bytecount;
526200171Smav		}
527200171Smav		sectors = bytecount / ata_logical_sector_size(ident_buf);
528198708Smav
529198708Smav		cam_fill_ataio(ataio,
530198708Smav		    1,
531198708Smav		    probedone,
532198708Smav		    CAM_DIR_NONE,
533198708Smav		    0,
534198708Smav		    NULL,
535198708Smav		    0,
536198708Smav		    30*1000);
537198708Smav		ata_28bit_cmd(ataio, ATA_SET_MULTI, 0, 0, sectors);
538198708Smav		break;
539195534Sscottl	}
540195534Sscottl	case PROBE_INQUIRY:
541200171Smav	{
542200171Smav		u_int bytecount;
543200171Smav
544200171Smav		bytecount = 8192;	/* SATA maximum */
545200171Smav		/* Fetch user bytecount from SIM. */
546200171Smav		bzero(&cts, sizeof(cts));
547203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
548200171Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
549200171Smav		cts.type = CTS_TYPE_USER_SETTINGS;
550200171Smav		xpt_action((union ccb *)&cts);
551200171Smav		if (path->device->transport == XPORT_ATA) {
552200171Smav			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_BYTECOUNT)
553200171Smav				bytecount = cts.xport_specific.ata.bytecount;
554200171Smav		} else {
555200171Smav			if (cts.xport_specific.sata.valid & CTS_SATA_VALID_BYTECOUNT)
556200171Smav				bytecount = cts.xport_specific.sata.bytecount;
557200171Smav		}
558200171Smav		/* Honor device capabilities. */
559200171Smav		bytecount &= ~1;
560200171Smav		bytecount = max(2, min(65534, bytecount));
561200171Smav		if (ident_buf->satacapabilities != 0x0000 &&
562200171Smav		    ident_buf->satacapabilities != 0xffff) {
563200171Smav			bytecount = min(8192, bytecount);
564200171Smav		}
565200171Smav		/* Report bytecount to SIM. */
566200171Smav		bzero(&cts, sizeof(cts));
567203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
568200171Smav		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
569200171Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
570200171Smav		if (path->device->transport == XPORT_ATA) {
571200171Smav			cts.xport_specific.ata.bytecount = bytecount;
572200171Smav			cts.xport_specific.ata.valid = CTS_ATA_VALID_BYTECOUNT;
573200171Smav		} else {
574200171Smav			cts.xport_specific.sata.bytecount = bytecount;
575200171Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_BYTECOUNT;
576200171Smav		}
577200171Smav		xpt_action((union ccb *)&cts);
578200171Smav		/* FALLTHROUGH */
579200171Smav	}
580195534Sscottl	case PROBE_FULL_INQUIRY:
581195534Sscottl	{
582195534Sscottl		u_int inquiry_len;
583195534Sscottl		struct scsi_inquiry_data *inq_buf =
584195534Sscottl		    &periph->path->device->inq_data;
585195534Sscottl
586195534Sscottl		if (softc->action == PROBE_INQUIRY)
587195534Sscottl			inquiry_len = SHORT_INQUIRY_LENGTH;
588195534Sscottl		else
589195534Sscottl			inquiry_len = SID_ADDITIONAL_LENGTH(inq_buf);
590195534Sscottl		/*
591195534Sscottl		 * Some parallel SCSI devices fail to send an
592195534Sscottl		 * ignore wide residue message when dealing with
593195534Sscottl		 * odd length inquiry requests.  Round up to be
594195534Sscottl		 * safe.
595195534Sscottl		 */
596195534Sscottl		inquiry_len = roundup2(inquiry_len, 2);
597195534Sscottl		scsi_inquiry(csio,
598195534Sscottl			     /*retries*/1,
599195534Sscottl			     probedone,
600195534Sscottl			     MSG_SIMPLE_Q_TAG,
601195534Sscottl			     (u_int8_t *)inq_buf,
602195534Sscottl			     inquiry_len,
603195534Sscottl			     /*evpd*/FALSE,
604195534Sscottl			     /*page_code*/0,
605195534Sscottl			     SSD_MIN_SIZE,
606195534Sscottl			     /*timeout*/60 * 1000);
607195534Sscottl		break;
608195534Sscottl	}
609195534Sscottl	case PROBE_PM_PID:
610195534Sscottl		cam_fill_ataio(ataio,
611195534Sscottl		      1,
612195534Sscottl		      probedone,
613195534Sscottl		      /*flags*/CAM_DIR_NONE,
614198389Smav		      0,
615195534Sscottl		      /*data_ptr*/NULL,
616195534Sscottl		      /*dxfer_len*/0,
617195534Sscottl		      10 * 1000);
618195534Sscottl		ata_pm_read_cmd(ataio, 0, 15);
619195534Sscottl		break;
620195534Sscottl	case PROBE_PM_PRV:
621195534Sscottl		cam_fill_ataio(ataio,
622195534Sscottl		      1,
623195534Sscottl		      probedone,
624195534Sscottl		      /*flags*/CAM_DIR_NONE,
625198389Smav		      0,
626195534Sscottl		      /*data_ptr*/NULL,
627195534Sscottl		      /*dxfer_len*/0,
628195534Sscottl		      10 * 1000);
629195534Sscottl		ata_pm_read_cmd(ataio, 1, 15);
630195534Sscottl		break;
631235897Smav	case PROBE_IDENTIFY_SES:
632235897Smav		cam_fill_ataio(ataio,
633235897Smav		      1,
634235897Smav		      probedone,
635235897Smav		      /*flags*/CAM_DIR_IN,
636235897Smav		      0,
637235897Smav		      /*data_ptr*/(u_int8_t *)&softc->ident_data,
638235897Smav		      /*dxfer_len*/sizeof(softc->ident_data),
639235897Smav		      30 * 1000);
640235897Smav		ata_28bit_cmd(ataio, ATA_SEP_ATTN, 0xEC, 0x02,
641235897Smav		    sizeof(softc->ident_data) / 4);
642235897Smav		break;
643235897Smav	case PROBE_IDENTIFY_SAFTE:
644235897Smav		cam_fill_ataio(ataio,
645235897Smav		      1,
646235897Smav		      probedone,
647235897Smav		      /*flags*/CAM_DIR_IN,
648235897Smav		      0,
649235897Smav		      /*data_ptr*/(u_int8_t *)&softc->ident_data,
650235897Smav		      /*dxfer_len*/sizeof(softc->ident_data),
651235897Smav		      30 * 1000);
652235897Smav		ata_28bit_cmd(ataio, ATA_SEP_ATTN, 0xEC, 0x00,
653235897Smav		    sizeof(softc->ident_data) / 4);
654235897Smav		break;
655195534Sscottl	case PROBE_INVALID:
656198708Smav		CAM_DEBUG(path, CAM_DEBUG_INFO,
657195534Sscottl		    ("probestart: invalid action state\n"));
658195534Sscottl	default:
659195534Sscottl		break;
660195534Sscottl	}
661195534Sscottl	xpt_action(start_ccb);
662195534Sscottl}
663195534Sscottl#if 0
664195534Sscottlstatic void
665195534Sscottlproberequestdefaultnegotiation(struct cam_periph *periph)
666195534Sscottl{
667195534Sscottl	struct ccb_trans_settings cts;
668195534Sscottl
669203108Smav	xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NONE);
670195534Sscottl	cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
671195534Sscottl	cts.type = CTS_TYPE_USER_SETTINGS;
672195534Sscottl	xpt_action((union ccb *)&cts);
673195534Sscottl	if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
674195534Sscottl		return;
675195534Sscottl	}
676195534Sscottl	cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
677195534Sscottl	cts.type = CTS_TYPE_CURRENT_SETTINGS;
678195534Sscottl	xpt_action((union ccb *)&cts);
679195534Sscottl}
680195534Sscottl
681195534Sscottl/*
682195534Sscottl * Backoff Negotiation Code- only pertinent for SPI devices.
683195534Sscottl */
684195534Sscottlstatic int
685195534Sscottlproberequestbackoff(struct cam_periph *periph, struct cam_ed *device)
686195534Sscottl{
687195534Sscottl	struct ccb_trans_settings cts;
688195534Sscottl	struct ccb_trans_settings_spi *spi;
689195534Sscottl
690195534Sscottl	memset(&cts, 0, sizeof (cts));
691203108Smav	xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NONE);
692195534Sscottl	cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
693195534Sscottl	cts.type = CTS_TYPE_CURRENT_SETTINGS;
694195534Sscottl	xpt_action((union ccb *)&cts);
695195534Sscottl	if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
696195534Sscottl		if (bootverbose) {
697195534Sscottl			xpt_print(periph->path,
698195534Sscottl			    "failed to get current device settings\n");
699195534Sscottl		}
700195534Sscottl		return (0);
701195534Sscottl	}
702195534Sscottl	if (cts.transport != XPORT_SPI) {
703195534Sscottl		if (bootverbose) {
704195534Sscottl			xpt_print(periph->path, "not SPI transport\n");
705195534Sscottl		}
706195534Sscottl		return (0);
707195534Sscottl	}
708195534Sscottl	spi = &cts.xport_specific.spi;
709195534Sscottl
710195534Sscottl	/*
711195534Sscottl	 * We cannot renegotiate sync rate if we don't have one.
712195534Sscottl	 */
713195534Sscottl	if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) {
714195534Sscottl		if (bootverbose) {
715195534Sscottl			xpt_print(periph->path, "no sync rate known\n");
716195534Sscottl		}
717195534Sscottl		return (0);
718195534Sscottl	}
719195534Sscottl
720195534Sscottl	/*
721195534Sscottl	 * We'll assert that we don't have to touch PPR options- the
722195534Sscottl	 * SIM will see what we do with period and offset and adjust
723195534Sscottl	 * the PPR options as appropriate.
724195534Sscottl	 */
725195534Sscottl
726195534Sscottl	/*
727195534Sscottl	 * A sync rate with unknown or zero offset is nonsensical.
728195534Sscottl	 * A sync period of zero means Async.
729195534Sscottl	 */
730195534Sscottl	if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0
731195534Sscottl	 || spi->sync_offset == 0 || spi->sync_period == 0) {
732195534Sscottl		if (bootverbose) {
733195534Sscottl			xpt_print(periph->path, "no sync rate available\n");
734195534Sscottl		}
735195534Sscottl		return (0);
736195534Sscottl	}
737195534Sscottl
738195534Sscottl	if (device->flags & CAM_DEV_DV_HIT_BOTTOM) {
739195534Sscottl		CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
740195534Sscottl		    ("hit async: giving up on DV\n"));
741195534Sscottl		return (0);
742195534Sscottl	}
743195534Sscottl
744195534Sscottl
745195534Sscottl	/*
746195534Sscottl	 * Jump sync_period up by one, but stop at 5MHz and fall back to Async.
747195534Sscottl	 * We don't try to remember 'last' settings to see if the SIM actually
748195534Sscottl	 * gets into the speed we want to set. We check on the SIM telling
749195534Sscottl	 * us that a requested speed is bad, but otherwise don't try and
750195534Sscottl	 * check the speed due to the asynchronous and handshake nature
751195534Sscottl	 * of speed setting.
752195534Sscottl	 */
753195534Sscottl	spi->valid = CTS_SPI_VALID_SYNC_RATE | CTS_SPI_VALID_SYNC_OFFSET;
754195534Sscottl	for (;;) {
755195534Sscottl		spi->sync_period++;
756195534Sscottl		if (spi->sync_period >= 0xf) {
757195534Sscottl			spi->sync_period = 0;
758195534Sscottl			spi->sync_offset = 0;
759195534Sscottl			CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
760195534Sscottl			    ("setting to async for DV\n"));
761195534Sscottl			/*
762195534Sscottl			 * Once we hit async, we don't want to try
763195534Sscottl			 * any more settings.
764195534Sscottl			 */
765195534Sscottl			device->flags |= CAM_DEV_DV_HIT_BOTTOM;
766195534Sscottl		} else if (bootverbose) {
767195534Sscottl			CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
768195534Sscottl			    ("DV: period 0x%x\n", spi->sync_period));
769195534Sscottl			printf("setting period to 0x%x\n", spi->sync_period);
770195534Sscottl		}
771195534Sscottl		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
772195534Sscottl		cts.type = CTS_TYPE_CURRENT_SETTINGS;
773195534Sscottl		xpt_action((union ccb *)&cts);
774195534Sscottl		if ((cts.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
775195534Sscottl			break;
776195534Sscottl		}
777195534Sscottl		CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
778195534Sscottl		    ("DV: failed to set period 0x%x\n", spi->sync_period));
779195534Sscottl		if (spi->sync_period == 0) {
780195534Sscottl			return (0);
781195534Sscottl		}
782195534Sscottl	}
783195534Sscottl	return (1);
784195534Sscottl}
785195534Sscottl#endif
786195534Sscottlstatic void
787195534Sscottlprobedone(struct cam_periph *periph, union ccb *done_ccb)
788195534Sscottl{
789199747Smav	struct ccb_trans_settings cts;
790195534Sscottl	struct ata_params *ident_buf;
791235897Smav	struct scsi_inquiry_data *inq_buf;
792195534Sscottl	probe_softc *softc;
793195534Sscottl	struct cam_path *path;
794217444Smav	cam_status status;
795195534Sscottl	u_int32_t  priority;
796207499Smav	u_int caps;
797235897Smav	int changed = 1, found = 1;
798235897Smav	static const uint8_t fake_device_id_hdr[8] =
799235897Smav	    {0, SVPD_DEVICE_ID, 0, 12,
800235897Smav	     SVPD_ID_CODESET_BINARY, SVPD_ID_TYPE_NAA, 0, 8};
801195534Sscottl
802195534Sscottl	CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probedone\n"));
803195534Sscottl
804195534Sscottl	softc = (probe_softc *)periph->softc;
805195534Sscottl	path = done_ccb->ccb_h.path;
806195534Sscottl	priority = done_ccb->ccb_h.pinfo.priority;
807195534Sscottl	ident_buf = &path->device->ident_data;
808235897Smav	inq_buf = &path->device->inq_data;
809195534Sscottl
810198708Smav	if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
811209744Smav		if (softc->restart) {
812209744Smav			if (bootverbose) {
813209744Smav				cam_error_print(done_ccb,
814209744Smav				    CAM_ESF_ALL, CAM_EPF_ALL);
815209744Smav			}
816209744Smav		} else if (cam_periph_error(done_ccb, 0, 0, NULL) == ERESTART)
817195534Sscottl			return;
818209744Smav		if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
819195534Sscottl			/* Don't wedge the queue */
820195534Sscottl			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
821195534Sscottl					 /*run_queue*/TRUE);
822195534Sscottl		}
823217444Smav		status = done_ccb->ccb_h.status & CAM_STATUS_MASK;
824209744Smav		if (softc->restart) {
825209744Smav			softc->faults++;
826209744Smav			if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) ==
827209744Smav			    CAM_CMD_TIMEOUT)
828209744Smav				softc->faults += 4;
829209744Smav			if (softc->faults < 10)
830209744Smav				goto done;
831209744Smav			else
832209744Smav				softc->restart = 0;
833217444Smav
834198708Smav		/* Old PIO2 devices may not support mode setting. */
835217444Smav		} else if (softc->action == PROBE_SETMODE &&
836217444Smav		    status == CAM_ATA_STATUS_ERROR &&
837198708Smav		    ata_max_pmode(ident_buf) <= ATA_PIO2 &&
838217444Smav		    (ident_buf->capabilities1 & ATA_SUPPORT_IORDY) == 0) {
839198708Smav			goto noerror;
840217444Smav
841198708Smav		/*
842217444Smav		 * Some old WD SATA disks report supported and enabled
843217444Smav		 * device-initiated interface power management, but return
844217444Smav		 * ABORT on attempt to disable it.
845217444Smav		 */
846217444Smav		} else if (softc->action == PROBE_SETPM &&
847217444Smav		    status == CAM_ATA_STATUS_ERROR) {
848217444Smav			goto noerror;
849217875Smav
850217875Smav		/*
851217875Smav		 * Some HP SATA disks report supported DMA Auto-Activation,
852217875Smav		 * but return ABORT on attempt to enable it.
853217875Smav		 */
854217875Smav		} else if (softc->action == PROBE_SETDMAAA &&
855217875Smav		    status == CAM_ATA_STATUS_ERROR) {
856217875Smav			goto noerror;
857235897Smav
858235897Smav		/*
859235897Smav		 * SES and SAF-TE SEPs have different IDENTIFY commands,
860235897Smav		 * but SATA specification doesn't tell how to identify them.
861235897Smav		 * Until better way found, just try another if first fail.
862235897Smav		 */
863235897Smav		} else if (softc->action == PROBE_IDENTIFY_SES &&
864235897Smav		    status == CAM_ATA_STATUS_ERROR) {
865235897Smav			PROBE_SET_ACTION(softc, PROBE_IDENTIFY_SAFTE);
866235897Smav			xpt_release_ccb(done_ccb);
867235897Smav			xpt_schedule(periph, priority);
868235897Smav			return;
869217444Smav		}
870217444Smav
871217444Smav		/*
872198708Smav		 * If we get to this point, we got an error status back
873198708Smav		 * from the inquiry and the error status doesn't require
874198708Smav		 * automatically retrying the command.  Therefore, the
875198708Smav		 * inquiry failed.  If we had inquiry information before
876198708Smav		 * for this device, but this latest inquiry command failed,
877198708Smav		 * the device has probably gone away.  If this device isn't
878198708Smav		 * already marked unconfigured, notify the peripheral
879198708Smav		 * drivers that this device is no more.
880198708Smav		 */
881209744Smavdevice_fail:	if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0)
882198708Smav			xpt_async(AC_LOST_DEVICE, path, NULL);
883198708Smav		found = 0;
884198708Smav		goto done;
885198708Smav	}
886198708Smavnoerror:
887203385Smav	if (softc->restart)
888203385Smav		goto done;
889198708Smav	switch (softc->action) {
890198708Smav	case PROBE_RESET:
891195534Sscottl	{
892198708Smav		int sign = (done_ccb->ataio.res.lba_high << 8) +
893198708Smav		    done_ccb->ataio.res.lba_mid;
894200218Smav		if (bootverbose)
895200218Smav			xpt_print(path, "SIGNATURE: %04x\n", sign);
896198708Smav		if (sign == 0x0000 &&
897198708Smav		    done_ccb->ccb_h.target_id != 15) {
898198708Smav			path->device->protocol = PROTO_ATA;
899198708Smav			PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
900198708Smav		} else if (sign == 0x9669 &&
901198708Smav		    done_ccb->ccb_h.target_id == 15) {
902199747Smav			/* Report SIM that PM is present. */
903198708Smav			bzero(&cts, sizeof(cts));
904203108Smav			xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
905198708Smav			cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
906198708Smav			cts.type = CTS_TYPE_CURRENT_SETTINGS;
907198708Smav			cts.xport_specific.sata.pm_present = 1;
908198708Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_PM;
909198708Smav			xpt_action((union ccb *)&cts);
910198708Smav			path->device->protocol = PROTO_SATAPM;
911198708Smav			PROBE_SET_ACTION(softc, PROBE_PM_PID);
912235897Smav		} else if (sign == 0xc33c &&
913235897Smav		    done_ccb->ccb_h.target_id != 15) {
914235897Smav			path->device->protocol = PROTO_SEMB;
915235897Smav			PROBE_SET_ACTION(softc, PROBE_IDENTIFY_SES);
916198708Smav		} else if (sign == 0xeb14 &&
917198708Smav		    done_ccb->ccb_h.target_id != 15) {
918198708Smav			path->device->protocol = PROTO_SCSI;
919198708Smav			PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
920198708Smav		} else {
921198708Smav			if (done_ccb->ccb_h.target_id != 15) {
922198708Smav				xpt_print(path,
923198708Smav				    "Unexpected signature 0x%04x\n", sign);
924195534Sscottl			}
925198708Smav			goto device_fail;
926198708Smav		}
927198708Smav		xpt_release_ccb(done_ccb);
928198708Smav		xpt_schedule(periph, priority);
929198708Smav		return;
930198708Smav	}
931198708Smav	case PROBE_IDENTIFY:
932198708Smav	{
933207222Smav		struct ccb_pathinq cpi;
934198708Smav		int16_t *ptr;
935195534Sscottl
936203385Smav		ident_buf = &softc->ident_data;
937198708Smav		for (ptr = (int16_t *)ident_buf;
938198708Smav		     ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) {
939198708Smav			*ptr = le16toh(*ptr);
940198708Smav		}
941198708Smav		if (strncmp(ident_buf->model, "FX", 2) &&
942198708Smav		    strncmp(ident_buf->model, "NEC", 3) &&
943198708Smav		    strncmp(ident_buf->model, "Pioneer", 7) &&
944198708Smav		    strncmp(ident_buf->model, "SHARP", 5)) {
945198708Smav			ata_bswap(ident_buf->model, sizeof(ident_buf->model));
946198708Smav			ata_bswap(ident_buf->revision, sizeof(ident_buf->revision));
947198708Smav			ata_bswap(ident_buf->serial, sizeof(ident_buf->serial));
948198708Smav		}
949198708Smav		ata_btrim(ident_buf->model, sizeof(ident_buf->model));
950198708Smav		ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model));
951198708Smav		ata_btrim(ident_buf->revision, sizeof(ident_buf->revision));
952198708Smav		ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision));
953198708Smav		ata_btrim(ident_buf->serial, sizeof(ident_buf->serial));
954198708Smav		ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial));
955203421Smav		/* Device may need spin-up before IDENTIFY become valid. */
956204354Smav		if ((ident_buf->specconf == 0x37c8 ||
957204354Smav		     ident_buf->specconf == 0x738c) &&
958204354Smav		    ((ident_buf->config & ATA_RESP_INCOMPLETE) ||
959204354Smav		     softc->spinup == 0)) {
960203421Smav			PROBE_SET_ACTION(softc, PROBE_SPINUP);
961203421Smav			xpt_release_ccb(done_ccb);
962203421Smav			xpt_schedule(periph, priority);
963203421Smav			return;
964203421Smav		}
965203385Smav		ident_buf = &path->device->ident_data;
966198708Smav		if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) {
967198708Smav			/* Check that it is the same device. */
968203385Smav			if (bcmp(softc->ident_data.model, ident_buf->model,
969203385Smav			     sizeof(ident_buf->model)) ||
970203385Smav			    bcmp(softc->ident_data.revision, ident_buf->revision,
971203385Smav			     sizeof(ident_buf->revision)) ||
972203385Smav			    bcmp(softc->ident_data.serial, ident_buf->serial,
973203385Smav			     sizeof(ident_buf->serial))) {
974198708Smav				/* Device changed. */
975198708Smav				xpt_async(AC_LOST_DEVICE, path, NULL);
976207282Smav			} else {
977203385Smav				bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params));
978207282Smav				changed = 0;
979207282Smav			}
980207282Smav		}
981207282Smav		if (changed) {
982203385Smav			bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params));
983195534Sscottl			/* Clean up from previous instance of this device */
984195534Sscottl			if (path->device->serial_num != NULL) {
985195534Sscottl				free(path->device->serial_num, M_CAMXPT);
986195534Sscottl				path->device->serial_num = NULL;
987195534Sscottl				path->device->serial_num_len = 0;
988195534Sscottl			}
989235897Smav			if (path->device->device_id != NULL) {
990235897Smav				free(path->device->device_id, M_CAMXPT);
991235897Smav				path->device->device_id = NULL;
992235897Smav				path->device->device_id_len = 0;
993235897Smav			}
994195534Sscottl			path->device->serial_num =
995195534Sscottl				(u_int8_t *)malloc((sizeof(ident_buf->serial) + 1),
996198708Smav					   M_CAMXPT, M_NOWAIT);
997195534Sscottl			if (path->device->serial_num != NULL) {
998195534Sscottl				bcopy(ident_buf->serial,
999195534Sscottl				      path->device->serial_num,
1000195534Sscottl				      sizeof(ident_buf->serial));
1001195534Sscottl				path->device->serial_num[sizeof(ident_buf->serial)]
1002195534Sscottl				    = '\0';
1003195534Sscottl				path->device->serial_num_len =
1004195534Sscottl				    strlen(path->device->serial_num);
1005195534Sscottl			}
1006235897Smav			if (ident_buf->enabled.extension &
1007235897Smav			    ATA_SUPPORT_64BITWWN) {
1008235897Smav				path->device->device_id =
1009235897Smav				    malloc(16, M_CAMXPT, M_NOWAIT);
1010235897Smav				if (path->device->device_id != NULL) {
1011235897Smav					path->device->device_id_len = 16;
1012235897Smav					bcopy(&fake_device_id_hdr,
1013235897Smav					    path->device->device_id, 8);
1014235897Smav					bcopy(ident_buf->wwn,
1015235897Smav					    path->device->device_id + 8, 8);
1016235897Smav				}
1017235897Smav			}
1018195534Sscottl
1019198331Smav			path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID;
1020195534Sscottl		}
1021199178Smav		if (ident_buf->satacapabilities & ATA_SUPPORT_NCQ) {
1022199178Smav			path->device->mintags = path->device->maxtags =
1023199178Smav			    ATA_QUEUE_LEN(ident_buf->queue) + 1;
1024199178Smav		}
1025199178Smav		ata_find_quirk(path->device);
1026199263Smav		if (path->device->mintags != 0 &&
1027199263Smav		    path->bus->sim->max_tagged_dev_openings != 0) {
1028207222Smav			/* Check if the SIM does not want queued commands. */
1029207222Smav			bzero(&cpi, sizeof(cpi));
1030207222Smav			xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE);
1031207222Smav			cpi.ccb_h.func_code = XPT_PATH_INQ;
1032207222Smav			xpt_action((union ccb *)&cpi);
1033207222Smav			if (cpi.ccb_h.status == CAM_REQ_CMP &&
1034207222Smav			    (cpi.hba_inquiry & PI_TAG_ABLE)) {
1035207222Smav				/* Report SIM which tags are allowed. */
1036207222Smav				bzero(&cts, sizeof(cts));
1037207222Smav				xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
1038207222Smav				cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
1039207222Smav				cts.type = CTS_TYPE_CURRENT_SETTINGS;
1040207222Smav				cts.xport_specific.sata.tags = path->device->maxtags;
1041207222Smav				cts.xport_specific.sata.valid = CTS_SATA_VALID_TAGS;
1042207222Smav				xpt_action((union ccb *)&cts);
1043207222Smav				/* Reconfigure queues for tagged queueing. */
1044207222Smav				xpt_start_tags(path);
1045207222Smav			}
1046199178Smav		}
1047198708Smav		ata_device_transport(path);
1048198708Smav		PROBE_SET_ACTION(softc, PROBE_SETMODE);
1049195534Sscottl		xpt_release_ccb(done_ccb);
1050198708Smav		xpt_schedule(periph, priority);
1051198708Smav		return;
1052195534Sscottl	}
1053203421Smav	case PROBE_SPINUP:
1054203421Smav		if (bootverbose)
1055203421Smav			xpt_print(path, "Spin-up done\n");
1056203421Smav		softc->spinup = 1;
1057203421Smav		PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
1058203421Smav		xpt_release_ccb(done_ccb);
1059203421Smav		xpt_schedule(periph, priority);
1060203421Smav		return;
1061195534Sscottl	case PROBE_SETMODE:
1062207499Smav		if (path->device->transport != XPORT_SATA)
1063207499Smav			goto notsata;
1064207499Smav		/* Set supported bits. */
1065207499Smav		bzero(&cts, sizeof(cts));
1066207499Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
1067207499Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
1068207499Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
1069207499Smav		xpt_action((union ccb *)&cts);
1070207499Smav		if (cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS)
1071207499Smav			caps = cts.xport_specific.sata.caps & CTS_SATA_CAPS_H;
1072207499Smav		else
1073207499Smav			caps = 0;
1074207499Smav		if (ident_buf->satacapabilities != 0xffff) {
1075207499Smav			if (ident_buf->satacapabilities & ATA_SUPPORT_IFPWRMNGTRCV)
1076207499Smav				caps |= CTS_SATA_CAPS_D_PMREQ;
1077207499Smav			if (ident_buf->satacapabilities & ATA_SUPPORT_HAPST)
1078207499Smav				caps |= CTS_SATA_CAPS_D_APST;
1079207499Smav		}
1080207499Smav		/* Mask unwanted bits. */
1081207499Smav		bzero(&cts, sizeof(cts));
1082207499Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
1083207499Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
1084207499Smav		cts.type = CTS_TYPE_USER_SETTINGS;
1085207499Smav		xpt_action((union ccb *)&cts);
1086207499Smav		if (cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS)
1087207499Smav			caps &= cts.xport_specific.sata.caps;
1088215454Smav		else
1089215454Smav			caps = 0;
1090207499Smav		/* Store result to SIM. */
1091207499Smav		bzero(&cts, sizeof(cts));
1092207499Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
1093207499Smav		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
1094207499Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
1095207499Smav		cts.xport_specific.sata.caps = caps;
1096207499Smav		cts.xport_specific.sata.valid = CTS_SATA_VALID_CAPS;
1097207499Smav		xpt_action((union ccb *)&cts);
1098207499Smav		softc->caps = caps;
1099217874Smav		if ((ident_buf->satasupport & ATA_SUPPORT_IFPWRMNGT) &&
1100217874Smav		    (!(softc->caps & CTS_SATA_CAPS_H_PMREQ)) !=
1101217874Smav		    (!(ident_buf->sataenabled & ATA_SUPPORT_IFPWRMNGT))) {
1102207499Smav			PROBE_SET_ACTION(softc, PROBE_SETPM);
1103207499Smav			xpt_release_ccb(done_ccb);
1104207499Smav			xpt_schedule(periph, priority);
1105207499Smav			return;
1106207499Smav		}
1107207499Smav		/* FALLTHROUGH */
1108207499Smav	case PROBE_SETPM:
1109207499Smav		if (ident_buf->satacapabilities != 0xffff &&
1110217874Smav		    (ident_buf->satacapabilities & ATA_SUPPORT_DAPST) &&
1111217874Smav		    (!(softc->caps & CTS_SATA_CAPS_H_APST)) !=
1112217874Smav		    (!(ident_buf->sataenabled & ATA_ENABLED_DAPST))) {
1113207499Smav			PROBE_SET_ACTION(softc, PROBE_SETAPST);
1114207499Smav			xpt_release_ccb(done_ccb);
1115207499Smav			xpt_schedule(periph, priority);
1116207499Smav			return;
1117207499Smav		}
1118207499Smav		/* FALLTHROUGH */
1119207499Smav	case PROBE_SETAPST:
1120217874Smav		if ((ident_buf->satasupport & ATA_SUPPORT_AUTOACTIVATE) &&
1121217874Smav		    (!(softc->caps & CTS_SATA_CAPS_H_DMAAA)) !=
1122217874Smav		    (!(ident_buf->sataenabled & ATA_SUPPORT_AUTOACTIVATE))) {
1123207499Smav			PROBE_SET_ACTION(softc, PROBE_SETDMAAA);
1124207499Smav			xpt_release_ccb(done_ccb);
1125207499Smav			xpt_schedule(periph, priority);
1126207499Smav			return;
1127207499Smav		}
1128207499Smav		/* FALLTHROUGH */
1129207499Smav	case PROBE_SETDMAAA:
1130220602Smav		if ((ident_buf->satasupport & ATA_SUPPORT_ASYNCNOTIF) &&
1131220602Smav		    (!(softc->caps & CTS_SATA_CAPS_H_AN)) !=
1132220602Smav		    (!(ident_buf->sataenabled & ATA_SUPPORT_ASYNCNOTIF))) {
1133220602Smav			PROBE_SET_ACTION(softc, PROBE_SETAN);
1134220602Smav			xpt_release_ccb(done_ccb);
1135220602Smav			xpt_schedule(periph, priority);
1136220602Smav			return;
1137220602Smav		}
1138220602Smav		/* FALLTHROUGH */
1139220602Smav	case PROBE_SETAN:
1140207499Smavnotsata:
1141198708Smav		if (path->device->protocol == PROTO_ATA) {
1142198708Smav			PROBE_SET_ACTION(softc, PROBE_SET_MULTI);
1143198708Smav		} else {
1144198708Smav			PROBE_SET_ACTION(softc, PROBE_INQUIRY);
1145195534Sscottl		}
1146198708Smav		xpt_release_ccb(done_ccb);
1147198708Smav		xpt_schedule(periph, priority);
1148198708Smav		return;
1149198708Smav	case PROBE_SET_MULTI:
1150198708Smav		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
1151198708Smav			path->device->flags &= ~CAM_DEV_UNCONFIGURED;
1152198748Smav			xpt_acquire_device(path->device);
1153198708Smav			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
1154198708Smav			xpt_action(done_ccb);
1155198708Smav			xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path,
1156198708Smav			    done_ccb);
1157198708Smav		}
1158198708Smav		break;
1159195534Sscottl	case PROBE_INQUIRY:
1160195534Sscottl	case PROBE_FULL_INQUIRY:
1161195534Sscottl	{
1162198708Smav		u_int8_t periph_qual, len;
1163195534Sscottl
1164198708Smav		path->device->flags |= CAM_DEV_INQUIRY_DATA_VALID;
1165195534Sscottl
1166198708Smav		periph_qual = SID_QUAL(inq_buf);
1167195534Sscottl
1168198708Smav		if (periph_qual != SID_QUAL_LU_CONNECTED)
1169198708Smav			break;
1170195534Sscottl
1171198708Smav		/*
1172198708Smav		 * We conservatively request only
1173198708Smav		 * SHORT_INQUIRY_LEN bytes of inquiry
1174198708Smav		 * information during our first try
1175198708Smav		 * at sending an INQUIRY. If the device
1176198708Smav		 * has more information to give,
1177198708Smav		 * perform a second request specifying
1178198708Smav		 * the amount of information the device
1179198708Smav		 * is willing to give.
1180198708Smav		 */
1181198708Smav		len = inq_buf->additional_length
1182198708Smav		    + offsetof(struct scsi_inquiry_data, additional_length) + 1;
1183198708Smav		if (softc->action == PROBE_INQUIRY
1184198708Smav		    && len > SHORT_INQUIRY_LENGTH) {
1185198708Smav			PROBE_SET_ACTION(softc, PROBE_FULL_INQUIRY);
1186198708Smav			xpt_release_ccb(done_ccb);
1187198708Smav			xpt_schedule(periph, priority);
1188195534Sscottl			return;
1189195534Sscottl		}
1190198708Smav
1191198708Smav		ata_device_transport(path);
1192198708Smav		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
1193198708Smav			path->device->flags &= ~CAM_DEV_UNCONFIGURED;
1194198748Smav			xpt_acquire_device(path->device);
1195198708Smav			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
1196198708Smav			xpt_action(done_ccb);
1197198708Smav			xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, done_ccb);
1198198708Smav		}
1199198708Smav		break;
1200195534Sscottl	}
1201195534Sscottl	case PROBE_PM_PID:
1202198708Smav		if ((path->device->flags & CAM_DEV_IDENTIFY_DATA_VALID) == 0)
1203198708Smav			bzero(ident_buf, sizeof(*ident_buf));
1204198708Smav		softc->pm_pid = (done_ccb->ataio.res.lba_high << 24) +
1205198708Smav		    (done_ccb->ataio.res.lba_mid << 16) +
1206198708Smav		    (done_ccb->ataio.res.lba_low << 8) +
1207198708Smav		    done_ccb->ataio.res.sector_count;
1208198708Smav		((uint32_t *)ident_buf)[0] = softc->pm_pid;
1209198708Smav		snprintf(ident_buf->model, sizeof(ident_buf->model),
1210198708Smav		    "Port Multiplier %08x", softc->pm_pid);
1211198708Smav		PROBE_SET_ACTION(softc, PROBE_PM_PRV);
1212198708Smav		xpt_release_ccb(done_ccb);
1213198708Smav		xpt_schedule(periph, priority);
1214198708Smav		return;
1215195534Sscottl	case PROBE_PM_PRV:
1216198708Smav		softc->pm_prv = (done_ccb->ataio.res.lba_high << 24) +
1217198708Smav		    (done_ccb->ataio.res.lba_mid << 16) +
1218198708Smav		    (done_ccb->ataio.res.lba_low << 8) +
1219198708Smav		    done_ccb->ataio.res.sector_count;
1220198708Smav		((uint32_t *)ident_buf)[1] = softc->pm_prv;
1221198708Smav		snprintf(ident_buf->revision, sizeof(ident_buf->revision),
1222198708Smav		    "%04x", softc->pm_prv);
1223198708Smav		path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID;
1224207499Smav		/* Set supported bits. */
1225207499Smav		bzero(&cts, sizeof(cts));
1226207499Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
1227207499Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
1228207499Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
1229207499Smav		xpt_action((union ccb *)&cts);
1230207499Smav		if (cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS)
1231207499Smav			caps = cts.xport_specific.sata.caps & CTS_SATA_CAPS_H;
1232207499Smav		else
1233207499Smav			caps = 0;
1234207499Smav		/* All PMPs must support PM requests. */
1235207499Smav		caps |= CTS_SATA_CAPS_D_PMREQ;
1236207499Smav		/* Mask unwanted bits. */
1237207499Smav		bzero(&cts, sizeof(cts));
1238207499Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
1239207499Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
1240207499Smav		cts.type = CTS_TYPE_USER_SETTINGS;
1241207499Smav		xpt_action((union ccb *)&cts);
1242207499Smav		if (cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS)
1243207499Smav			caps &= cts.xport_specific.sata.caps;
1244215454Smav		else
1245215454Smav			caps = 0;
1246207499Smav		/* Store result to SIM. */
1247207499Smav		bzero(&cts, sizeof(cts));
1248207499Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
1249207499Smav		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
1250207499Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
1251207499Smav		cts.xport_specific.sata.caps = caps;
1252207499Smav		cts.xport_specific.sata.valid = CTS_SATA_VALID_CAPS;
1253207499Smav		xpt_action((union ccb *)&cts);
1254207499Smav		softc->caps = caps;
1255198708Smav		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
1256198708Smav			path->device->flags &= ~CAM_DEV_UNCONFIGURED;
1257198748Smav			xpt_acquire_device(path->device);
1258198708Smav			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
1259198708Smav			xpt_action(done_ccb);
1260198708Smav			xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path,
1261198708Smav			    done_ccb);
1262198708Smav		} else {
1263198708Smav			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
1264198708Smav			xpt_action(done_ccb);
1265198708Smav			xpt_async(AC_SCSI_AEN, done_ccb->ccb_h.path, done_ccb);
1266195534Sscottl		}
1267198708Smav		break;
1268235897Smav	case PROBE_IDENTIFY_SES:
1269235897Smav	case PROBE_IDENTIFY_SAFTE:
1270235897Smav		if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) {
1271235897Smav			/* Check that it is the same device. */
1272235897Smav			if (bcmp(&softc->ident_data, ident_buf, 53)) {
1273235897Smav				/* Device changed. */
1274235897Smav				xpt_async(AC_LOST_DEVICE, path, NULL);
1275235897Smav			} else {
1276235897Smav				bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params));
1277235897Smav				changed = 0;
1278235897Smav			}
1279235897Smav		}
1280235897Smav		if (changed) {
1281235897Smav			bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params));
1282235897Smav			/* Clean up from previous instance of this device */
1283235897Smav			if (path->device->device_id != NULL) {
1284235897Smav				free(path->device->device_id, M_CAMXPT);
1285235897Smav				path->device->device_id = NULL;
1286235897Smav				path->device->device_id_len = 0;
1287235897Smav			}
1288235897Smav			path->device->device_id =
1289235897Smav			    malloc(16, M_CAMXPT, M_NOWAIT);
1290235897Smav			if (path->device->device_id != NULL) {
1291235897Smav				path->device->device_id_len = 16;
1292235897Smav				bcopy(&fake_device_id_hdr,
1293235897Smav				    path->device->device_id, 8);
1294235897Smav				bcopy(((uint8_t*)ident_buf) + 2,
1295235897Smav				    path->device->device_id + 8, 8);
1296235897Smav			}
1297235897Smav
1298235897Smav			path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID;
1299235897Smav		}
1300235897Smav
1301235897Smav		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
1302235897Smav			path->device->flags &= ~CAM_DEV_UNCONFIGURED;
1303235897Smav			xpt_acquire_device(path->device);
1304235897Smav			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
1305235897Smav			xpt_action(done_ccb);
1306235897Smav			xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path,
1307235897Smav			    done_ccb);
1308235897Smav		}
1309235897Smav		break;
1310195534Sscottl	case PROBE_INVALID:
1311195534Sscottl		CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_INFO,
1312195534Sscottl		    ("probedone: invalid action state\n"));
1313195534Sscottl	default:
1314195534Sscottl		break;
1315195534Sscottl	}
1316198708Smavdone:
1317203108Smav	if (softc->restart) {
1318203108Smav		softc->restart = 0;
1319203108Smav		xpt_release_ccb(done_ccb);
1320195534Sscottl		probeschedule(periph);
1321203108Smav		return;
1322195534Sscottl	}
1323203108Smav	xpt_release_ccb(done_ccb);
1324203108Smav	while ((done_ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs))) {
1325203108Smav		TAILQ_REMOVE(&softc->request_ccbs,
1326203108Smav		    &done_ccb->ccb_h, periph_links.tqe);
1327203108Smav		done_ccb->ccb_h.status = found ? CAM_REQ_CMP : CAM_REQ_CMP_ERR;
1328203108Smav		xpt_done(done_ccb);
1329203108Smav	}
1330203108Smav	cam_release_devq(periph->path,
1331203108Smav	    RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_XPT + 1, FALSE);
1332203108Smav	cam_periph_invalidate(periph);
1333203108Smav	cam_periph_release_locked(periph);
1334195534Sscottl}
1335195534Sscottl
1336195534Sscottlstatic void
1337195534Sscottlprobecleanup(struct cam_periph *periph)
1338195534Sscottl{
1339195534Sscottl	free(periph->softc, M_CAMXPT);
1340195534Sscottl}
1341195534Sscottl
1342195534Sscottlstatic void
1343199178Smavata_find_quirk(struct cam_ed *device)
1344195534Sscottl{
1345199178Smav	struct ata_quirk_entry *quirk;
1346195534Sscottl	caddr_t	match;
1347195534Sscottl
1348199178Smav	match = cam_quirkmatch((caddr_t)&device->ident_data,
1349199178Smav			       (caddr_t)ata_quirk_table,
1350199178Smav			       ata_quirk_table_size,
1351199178Smav			       sizeof(*ata_quirk_table), ata_identify_match);
1352195534Sscottl
1353195534Sscottl	if (match == NULL)
1354195534Sscottl		panic("xpt_find_quirk: device didn't match wildcard entry!!");
1355195534Sscottl
1356199178Smav	quirk = (struct ata_quirk_entry *)match;
1357195534Sscottl	device->quirk = quirk;
1358199178Smav	if (quirk->quirks & CAM_QUIRK_MAXTAGS)
1359199178Smav		device->mintags = device->maxtags = quirk->maxtags;
1360195534Sscottl}
1361195534Sscottl
1362195534Sscottltypedef struct {
1363195534Sscottl	union	ccb *request_ccb;
1364195534Sscottl	struct 	ccb_pathinq *cpi;
1365195534Sscottl	int	counter;
1366195534Sscottl} ata_scan_bus_info;
1367195534Sscottl
1368195534Sscottl/*
1369195534Sscottl * To start a scan, request_ccb is an XPT_SCAN_BUS ccb.
1370195534Sscottl * As the scan progresses, xpt_scan_bus is used as the
1371195534Sscottl * callback on completion function.
1372195534Sscottl */
1373195534Sscottlstatic void
1374195534Sscottlata_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
1375195534Sscottl{
1376195534Sscottl	struct	cam_path *path;
1377195534Sscottl	ata_scan_bus_info *scan_info;
1378203108Smav	union	ccb *work_ccb, *reset_ccb;
1379195534Sscottl	cam_status status;
1380195534Sscottl
1381195534Sscottl	CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE,
1382195534Sscottl		  ("xpt_scan_bus\n"));
1383195534Sscottl	switch (request_ccb->ccb_h.func_code) {
1384195534Sscottl	case XPT_SCAN_BUS:
1385208582Smjacob	case XPT_SCAN_TGT:
1386195534Sscottl		/* Find out the characteristics of the bus */
1387195534Sscottl		work_ccb = xpt_alloc_ccb_nowait();
1388195534Sscottl		if (work_ccb == NULL) {
1389195534Sscottl			request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1390195534Sscottl			xpt_done(request_ccb);
1391195534Sscottl			return;
1392195534Sscottl		}
1393195534Sscottl		xpt_setup_ccb(&work_ccb->ccb_h, request_ccb->ccb_h.path,
1394195534Sscottl			      request_ccb->ccb_h.pinfo.priority);
1395195534Sscottl		work_ccb->ccb_h.func_code = XPT_PATH_INQ;
1396195534Sscottl		xpt_action(work_ccb);
1397195534Sscottl		if (work_ccb->ccb_h.status != CAM_REQ_CMP) {
1398195534Sscottl			request_ccb->ccb_h.status = work_ccb->ccb_h.status;
1399195534Sscottl			xpt_free_ccb(work_ccb);
1400195534Sscottl			xpt_done(request_ccb);
1401195534Sscottl			return;
1402195534Sscottl		}
1403195534Sscottl
1404203108Smav		/* We may need to reset bus first, if we haven't done it yet. */
1405203108Smav		if ((work_ccb->cpi.hba_inquiry &
1406203108Smav		    (PI_WIDE_32|PI_WIDE_16|PI_SDTR_ABLE)) &&
1407203108Smav		    !(work_ccb->cpi.hba_misc & PIM_NOBUSRESET) &&
1408203108Smav		    !timevalisset(&request_ccb->ccb_h.path->bus->last_reset)) {
1409203108Smav			reset_ccb = xpt_alloc_ccb_nowait();
1410208823Smav			if (reset_ccb == NULL) {
1411208823Smav				request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1412208823Smav				xpt_free_ccb(work_ccb);
1413208823Smav				xpt_done(request_ccb);
1414208823Smav				return;
1415208823Smav			}
1416203108Smav			xpt_setup_ccb(&reset_ccb->ccb_h, request_ccb->ccb_h.path,
1417203108Smav			      CAM_PRIORITY_NONE);
1418203108Smav			reset_ccb->ccb_h.func_code = XPT_RESET_BUS;
1419203108Smav			xpt_action(reset_ccb);
1420203108Smav			if (reset_ccb->ccb_h.status != CAM_REQ_CMP) {
1421203108Smav				request_ccb->ccb_h.status = reset_ccb->ccb_h.status;
1422203108Smav				xpt_free_ccb(reset_ccb);
1423203108Smav				xpt_free_ccb(work_ccb);
1424203108Smav				xpt_done(request_ccb);
1425203108Smav				return;
1426203108Smav			}
1427203108Smav			xpt_free_ccb(reset_ccb);
1428203108Smav		}
1429203108Smav
1430195534Sscottl		/* Save some state for use while we probe for devices */
1431195534Sscottl		scan_info = (ata_scan_bus_info *)
1432195534Sscottl		    malloc(sizeof(ata_scan_bus_info), M_CAMXPT, M_NOWAIT);
1433195534Sscottl		if (scan_info == NULL) {
1434195534Sscottl			request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1435208823Smav			xpt_free_ccb(work_ccb);
1436195534Sscottl			xpt_done(request_ccb);
1437195534Sscottl			return;
1438195534Sscottl		}
1439195534Sscottl		scan_info->request_ccb = request_ccb;
1440195534Sscottl		scan_info->cpi = &work_ccb->cpi;
1441195534Sscottl		/* If PM supported, probe it first. */
1442195534Sscottl		if (scan_info->cpi->hba_inquiry & PI_SATAPM)
1443201990Smav			scan_info->counter = scan_info->cpi->max_target;
1444201990Smav		else
1445201990Smav			scan_info->counter = 0;
1446195534Sscottl
1447195534Sscottl		work_ccb = xpt_alloc_ccb_nowait();
1448195534Sscottl		if (work_ccb == NULL) {
1449195534Sscottl			free(scan_info, M_CAMXPT);
1450195534Sscottl			request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1451195534Sscottl			xpt_done(request_ccb);
1452195534Sscottl			break;
1453195534Sscottl		}
1454195534Sscottl		goto scan_next;
1455195534Sscottl	case XPT_SCAN_LUN:
1456195534Sscottl		work_ccb = request_ccb;
1457195534Sscottl		/* Reuse the same CCB to query if a device was really found */
1458195534Sscottl		scan_info = (ata_scan_bus_info *)work_ccb->ccb_h.ppriv_ptr0;
1459198389Smav		/* If there is PMP... */
1460201990Smav		if ((scan_info->cpi->hba_inquiry & PI_SATAPM) &&
1461201990Smav		    (scan_info->counter == scan_info->cpi->max_target)) {
1462203108Smav			if (work_ccb->ccb_h.status == CAM_REQ_CMP) {
1463207428Smav				/* everything else will be probed by it */
1464207428Smav				/* Free the current request path- we're done with it. */
1465207428Smav				xpt_free_path(work_ccb->ccb_h.path);
1466201990Smav				goto done;
1467195534Sscottl			} else {
1468195534Sscottl				struct ccb_trans_settings cts;
1469195534Sscottl
1470195534Sscottl				/* Report SIM that PM is absent. */
1471195534Sscottl				bzero(&cts, sizeof(cts));
1472195534Sscottl				xpt_setup_ccb(&cts.ccb_h,
1473207428Smav				    work_ccb->ccb_h.path, CAM_PRIORITY_NONE);
1474195534Sscottl				cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
1475195534Sscottl				cts.type = CTS_TYPE_CURRENT_SETTINGS;
1476195665Smav				cts.xport_specific.sata.pm_present = 0;
1477195534Sscottl				cts.xport_specific.sata.valid = CTS_SATA_VALID_PM;
1478195534Sscottl				xpt_action((union ccb *)&cts);
1479195534Sscottl			}
1480195534Sscottl		}
1481207428Smav		/* Free the current request path- we're done with it. */
1482207428Smav		xpt_free_path(work_ccb->ccb_h.path);
1483201990Smav		if (scan_info->counter ==
1484201990Smav		    ((scan_info->cpi->hba_inquiry & PI_SATAPM) ?
1485201990Smav		    0 : scan_info->cpi->max_target)) {
1486201990Smavdone:
1487195534Sscottl			xpt_free_ccb(work_ccb);
1488195534Sscottl			xpt_free_ccb((union ccb *)scan_info->cpi);
1489195534Sscottl			request_ccb = scan_info->request_ccb;
1490195534Sscottl			free(scan_info, M_CAMXPT);
1491195534Sscottl			request_ccb->ccb_h.status = CAM_REQ_CMP;
1492195534Sscottl			xpt_done(request_ccb);
1493195534Sscottl			break;
1494195534Sscottl		}
1495201990Smav		/* Take next device. Wrap from max (PMP) to 0. */
1496201990Smav		scan_info->counter = (scan_info->counter + 1 ) %
1497201990Smav		    (scan_info->cpi->max_target + 1);
1498195534Sscottlscan_next:
1499195534Sscottl		status = xpt_create_path(&path, xpt_periph,
1500195534Sscottl		    scan_info->request_ccb->ccb_h.path_id,
1501195534Sscottl		    scan_info->counter, 0);
1502195534Sscottl		if (status != CAM_REQ_CMP) {
1503195534Sscottl			printf("xpt_scan_bus: xpt_create_path failed"
1504195534Sscottl			    " with status %#x, bus scan halted\n",
1505195534Sscottl			    status);
1506195534Sscottl			xpt_free_ccb(work_ccb);
1507195534Sscottl			xpt_free_ccb((union ccb *)scan_info->cpi);
1508195534Sscottl			request_ccb = scan_info->request_ccb;
1509195534Sscottl			free(scan_info, M_CAMXPT);
1510195534Sscottl			request_ccb->ccb_h.status = status;
1511195534Sscottl			xpt_done(request_ccb);
1512195534Sscottl			break;
1513195534Sscottl		}
1514195534Sscottl		xpt_setup_ccb(&work_ccb->ccb_h, path,
1515195534Sscottl		    scan_info->request_ccb->ccb_h.pinfo.priority);
1516195534Sscottl		work_ccb->ccb_h.func_code = XPT_SCAN_LUN;
1517195534Sscottl		work_ccb->ccb_h.cbfcnp = ata_scan_bus;
1518195534Sscottl		work_ccb->ccb_h.ppriv_ptr0 = scan_info;
1519195534Sscottl		work_ccb->crcn.flags = scan_info->request_ccb->crcn.flags;
1520195534Sscottl		xpt_action(work_ccb);
1521195534Sscottl		break;
1522195534Sscottl	default:
1523195534Sscottl		break;
1524195534Sscottl	}
1525195534Sscottl}
1526195534Sscottl
1527195534Sscottlstatic void
1528195534Sscottlata_scan_lun(struct cam_periph *periph, struct cam_path *path,
1529195534Sscottl	     cam_flags flags, union ccb *request_ccb)
1530195534Sscottl{
1531195534Sscottl	struct ccb_pathinq cpi;
1532195534Sscottl	cam_status status;
1533195534Sscottl	struct cam_path *new_path;
1534195534Sscottl	struct cam_periph *old_periph;
1535195534Sscottl
1536203108Smav	CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_scan_lun\n"));
1537195534Sscottl
1538203108Smav	xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE);
1539195534Sscottl	cpi.ccb_h.func_code = XPT_PATH_INQ;
1540195534Sscottl	xpt_action((union ccb *)&cpi);
1541195534Sscottl
1542195534Sscottl	if (cpi.ccb_h.status != CAM_REQ_CMP) {
1543195534Sscottl		if (request_ccb != NULL) {
1544195534Sscottl			request_ccb->ccb_h.status = cpi.ccb_h.status;
1545195534Sscottl			xpt_done(request_ccb);
1546195534Sscottl		}
1547195534Sscottl		return;
1548195534Sscottl	}
1549195534Sscottl
1550195534Sscottl	if (request_ccb == NULL) {
1551195534Sscottl		request_ccb = malloc(sizeof(union ccb), M_CAMXPT, M_NOWAIT);
1552195534Sscottl		if (request_ccb == NULL) {
1553195534Sscottl			xpt_print(path, "xpt_scan_lun: can't allocate CCB, "
1554195534Sscottl			    "can't continue\n");
1555195534Sscottl			return;
1556195534Sscottl		}
1557195534Sscottl		new_path = malloc(sizeof(*new_path), M_CAMXPT, M_NOWAIT);
1558195534Sscottl		if (new_path == NULL) {
1559195534Sscottl			xpt_print(path, "xpt_scan_lun: can't allocate path, "
1560195534Sscottl			    "can't continue\n");
1561195534Sscottl			free(request_ccb, M_CAMXPT);
1562195534Sscottl			return;
1563195534Sscottl		}
1564195534Sscottl		status = xpt_compile_path(new_path, xpt_periph,
1565195534Sscottl					  path->bus->path_id,
1566195534Sscottl					  path->target->target_id,
1567195534Sscottl					  path->device->lun_id);
1568195534Sscottl
1569195534Sscottl		if (status != CAM_REQ_CMP) {
1570195534Sscottl			xpt_print(path, "xpt_scan_lun: can't compile path, "
1571195534Sscottl			    "can't continue\n");
1572195534Sscottl			free(request_ccb, M_CAMXPT);
1573195534Sscottl			free(new_path, M_CAMXPT);
1574195534Sscottl			return;
1575195534Sscottl		}
1576203108Smav		xpt_setup_ccb(&request_ccb->ccb_h, new_path, CAM_PRIORITY_XPT);
1577195534Sscottl		request_ccb->ccb_h.cbfcnp = xptscandone;
1578195534Sscottl		request_ccb->ccb_h.func_code = XPT_SCAN_LUN;
1579195534Sscottl		request_ccb->crcn.flags = flags;
1580195534Sscottl	}
1581195534Sscottl
1582195653Smav	if ((old_periph = cam_periph_find(path, "aprobe")) != NULL) {
1583195534Sscottl		probe_softc *softc;
1584195534Sscottl
1585195534Sscottl		softc = (probe_softc *)old_periph->softc;
1586195534Sscottl		TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h,
1587195534Sscottl				  periph_links.tqe);
1588203108Smav		softc->restart = 1;
1589195534Sscottl	} else {
1590195534Sscottl		status = cam_periph_alloc(proberegister, NULL, probecleanup,
1591195653Smav					  probestart, "aprobe",
1592195534Sscottl					  CAM_PERIPH_BIO,
1593195534Sscottl					  request_ccb->ccb_h.path, NULL, 0,
1594195534Sscottl					  request_ccb);
1595195534Sscottl
1596195534Sscottl		if (status != CAM_REQ_CMP) {
1597195534Sscottl			xpt_print(path, "xpt_scan_lun: cam_alloc_periph "
1598195534Sscottl			    "returned an error, can't continue probe\n");
1599195534Sscottl			request_ccb->ccb_h.status = status;
1600195534Sscottl			xpt_done(request_ccb);
1601195534Sscottl		}
1602195534Sscottl	}
1603195534Sscottl}
1604195534Sscottl
1605195534Sscottlstatic void
1606195534Sscottlxptscandone(struct cam_periph *periph, union ccb *done_ccb)
1607195534Sscottl{
1608195534Sscottl	xpt_release_path(done_ccb->ccb_h.path);
1609195534Sscottl	free(done_ccb->ccb_h.path, M_CAMXPT);
1610195534Sscottl	free(done_ccb, M_CAMXPT);
1611195534Sscottl}
1612195534Sscottl
1613195534Sscottlstatic struct cam_ed *
1614195534Sscottlata_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id)
1615195534Sscottl{
1616195534Sscottl	struct cam_path path;
1617199178Smav	struct ata_quirk_entry *quirk;
1618195534Sscottl	struct cam_ed *device;
1619195534Sscottl	struct cam_ed *cur_device;
1620195534Sscottl
1621195534Sscottl	device = xpt_alloc_device(bus, target, lun_id);
1622195534Sscottl	if (device == NULL)
1623195534Sscottl		return (NULL);
1624195534Sscottl
1625195534Sscottl	/*
1626195534Sscottl	 * Take the default quirk entry until we have inquiry
1627195534Sscottl	 * data and can determine a better quirk to use.
1628195534Sscottl	 */
1629199178Smav	quirk = &ata_quirk_table[ata_quirk_table_size - 1];
1630195534Sscottl	device->quirk = (void *)quirk;
1631199178Smav	device->mintags = 0;
1632199178Smav	device->maxtags = 0;
1633195534Sscottl	bzero(&device->inq_data, sizeof(device->inq_data));
1634195534Sscottl	device->inq_flags = 0;
1635195534Sscottl	device->queue_flags = 0;
1636195534Sscottl	device->serial_num = NULL;
1637195534Sscottl	device->serial_num_len = 0;
1638195534Sscottl
1639195534Sscottl	/*
1640195534Sscottl	 * XXX should be limited by number of CCBs this bus can
1641195534Sscottl	 * do.
1642195534Sscottl	 */
1643195534Sscottl	bus->sim->max_ccbs += device->ccbq.devq_openings;
1644195534Sscottl	/* Insertion sort into our target's device list */
1645195534Sscottl	cur_device = TAILQ_FIRST(&target->ed_entries);
1646195534Sscottl	while (cur_device != NULL && cur_device->lun_id < lun_id)
1647195534Sscottl		cur_device = TAILQ_NEXT(cur_device, links);
1648195534Sscottl	if (cur_device != NULL) {
1649195534Sscottl		TAILQ_INSERT_BEFORE(cur_device, device, links);
1650195534Sscottl	} else {
1651195534Sscottl		TAILQ_INSERT_TAIL(&target->ed_entries, device, links);
1652195534Sscottl	}
1653195534Sscottl	target->generation++;
1654195534Sscottl	if (lun_id != CAM_LUN_WILDCARD) {
1655195534Sscottl		xpt_compile_path(&path,
1656195534Sscottl				 NULL,
1657195534Sscottl				 bus->path_id,
1658195534Sscottl				 target->target_id,
1659195534Sscottl				 lun_id);
1660195534Sscottl		ata_device_transport(&path);
1661195534Sscottl		xpt_release_path(&path);
1662195534Sscottl	}
1663195534Sscottl
1664195534Sscottl	return (device);
1665195534Sscottl}
1666195534Sscottl
1667195534Sscottlstatic void
1668195534Sscottlata_device_transport(struct cam_path *path)
1669195534Sscottl{
1670195534Sscottl	struct ccb_pathinq cpi;
1671198331Smav	struct ccb_trans_settings cts;
1672198331Smav	struct scsi_inquiry_data *inq_buf = NULL;
1673198331Smav	struct ata_params *ident_buf = NULL;
1674195534Sscottl
1675195534Sscottl	/* Get transport information from the SIM */
1676203108Smav	xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE);
1677195534Sscottl	cpi.ccb_h.func_code = XPT_PATH_INQ;
1678195534Sscottl	xpt_action((union ccb *)&cpi);
1679195534Sscottl
1680195534Sscottl	path->device->transport = cpi.transport;
1681198331Smav	if ((path->device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0)
1682198331Smav		inq_buf = &path->device->inq_data;
1683198331Smav	if ((path->device->flags & CAM_DEV_IDENTIFY_DATA_VALID) != 0)
1684198331Smav		ident_buf = &path->device->ident_data;
1685198331Smav	if (path->device->protocol == PROTO_ATA) {
1686198331Smav		path->device->protocol_version = ident_buf ?
1687198331Smav		    ata_version(ident_buf->version_major) : cpi.protocol_version;
1688198331Smav	} else if (path->device->protocol == PROTO_SCSI) {
1689198331Smav		path->device->protocol_version = inq_buf ?
1690198331Smav		    SID_ANSI_REV(inq_buf) : cpi.protocol_version;
1691195534Sscottl	}
1692198331Smav	path->device->transport_version = ident_buf ?
1693198331Smav	    ata_version(ident_buf->version_major) : cpi.transport_version;
1694195534Sscottl
1695195534Sscottl	/* Tell the controller what we think */
1696203108Smav	xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
1697195534Sscottl	cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
1698195534Sscottl	cts.type = CTS_TYPE_CURRENT_SETTINGS;
1699195534Sscottl	cts.transport = path->device->transport;
1700195534Sscottl	cts.transport_version = path->device->transport_version;
1701195534Sscottl	cts.protocol = path->device->protocol;
1702195534Sscottl	cts.protocol_version = path->device->protocol_version;
1703195534Sscottl	cts.proto_specific.valid = 0;
1704203376Smav	if (ident_buf) {
1705203376Smav		if (path->device->transport == XPORT_ATA) {
1706223019Smav			cts.xport_specific.ata.atapi =
1707223019Smav			    (ident_buf->config == ATA_PROTO_CFA) ? 0 :
1708203376Smav			    ((ident_buf->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_16) ? 16 :
1709203376Smav			    ((ident_buf->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12) ? 12 : 0;
1710203376Smav			cts.xport_specific.ata.valid = CTS_ATA_VALID_ATAPI;
1711203376Smav		} else {
1712223019Smav			cts.xport_specific.sata.atapi =
1713223019Smav			    (ident_buf->config == ATA_PROTO_CFA) ? 0 :
1714203376Smav			    ((ident_buf->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_16) ? 16 :
1715203376Smav			    ((ident_buf->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12) ? 12 : 0;
1716203376Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_ATAPI;
1717203376Smav		}
1718203376Smav	} else
1719203376Smav		cts.xport_specific.valid = 0;
1720195534Sscottl	xpt_action((union ccb *)&cts);
1721195534Sscottl}
1722195534Sscottl
1723195534Sscottlstatic void
1724223443Swillata_dev_advinfo(union ccb *start_ccb)
1725223443Swill{
1726223443Swill	struct cam_ed *device;
1727223443Swill	struct ccb_dev_advinfo *cdai;
1728223443Swill	off_t amt;
1729223443Swill
1730223443Swill	start_ccb->ccb_h.status = CAM_REQ_INVALID;
1731223443Swill	device = start_ccb->ccb_h.path->device;
1732223443Swill	cdai = &start_ccb->cdai;
1733223443Swill	switch(cdai->buftype) {
1734235897Smav	case CDAI_TYPE_SCSI_DEVID:
1735235897Smav		if (cdai->flags & CDAI_FLAG_STORE)
1736235897Smav			return;
1737235897Smav		cdai->provsiz = device->device_id_len;
1738235897Smav		if (device->device_id_len == 0)
1739235897Smav			break;
1740235897Smav		amt = device->device_id_len;
1741235897Smav		if (cdai->provsiz > cdai->bufsiz)
1742235897Smav			amt = cdai->bufsiz;
1743235897Smav		memcpy(cdai->buf, device->device_id, amt);
1744235897Smav		break;
1745223443Swill	case CDAI_TYPE_SERIAL_NUM:
1746223443Swill		if (cdai->flags & CDAI_FLAG_STORE)
1747235897Smav			return;
1748223443Swill		cdai->provsiz = device->serial_num_len;
1749223443Swill		if (device->serial_num_len == 0)
1750223443Swill			break;
1751223443Swill		amt = device->serial_num_len;
1752223443Swill		if (cdai->provsiz > cdai->bufsiz)
1753223443Swill			amt = cdai->bufsiz;
1754223443Swill		memcpy(cdai->buf, device->serial_num, amt);
1755223443Swill		break;
1756235897Smav	case CDAI_TYPE_PHYS_PATH:
1757235897Smav		if (cdai->flags & CDAI_FLAG_STORE) {
1758235897Smav			if (device->physpath != NULL)
1759235897Smav				free(device->physpath, M_CAMXPT);
1760235897Smav			device->physpath_len = cdai->bufsiz;
1761235897Smav			/* Clear existing buffer if zero length */
1762235897Smav			if (cdai->bufsiz == 0)
1763235897Smav				break;
1764235897Smav			device->physpath = malloc(cdai->bufsiz, M_CAMXPT, M_NOWAIT);
1765235897Smav			if (device->physpath == NULL) {
1766235897Smav				start_ccb->ccb_h.status = CAM_REQ_ABORTED;
1767235897Smav				return;
1768235897Smav			}
1769235897Smav			memcpy(device->physpath, cdai->buf, cdai->bufsiz);
1770235897Smav		} else {
1771235897Smav			cdai->provsiz = device->physpath_len;
1772235897Smav			if (device->physpath_len == 0)
1773235897Smav				break;
1774235897Smav			amt = device->physpath_len;
1775235897Smav			if (cdai->provsiz > cdai->bufsiz)
1776235897Smav				amt = cdai->bufsiz;
1777235897Smav			memcpy(cdai->buf, device->physpath, amt);
1778235897Smav		}
1779235897Smav		break;
1780223443Swill	default:
1781235897Smav		return;
1782223443Swill	}
1783235897Smav	start_ccb->ccb_h.status = CAM_REQ_CMP;
1784235897Smav
1785235897Smav	if (cdai->flags & CDAI_FLAG_STORE) {
1786235897Smav		int owned;
1787235897Smav
1788235897Smav		owned = mtx_owned(start_ccb->ccb_h.path->bus->sim->mtx);
1789235897Smav		if (owned == 0)
1790235897Smav			mtx_lock(start_ccb->ccb_h.path->bus->sim->mtx);
1791235897Smav		xpt_async(AC_ADVINFO_CHANGED, start_ccb->ccb_h.path,
1792235897Smav			  (void *)(uintptr_t)cdai->buftype);
1793235897Smav		if (owned == 0)
1794235897Smav			mtx_unlock(start_ccb->ccb_h.path->bus->sim->mtx);
1795235897Smav	}
1796223443Swill}
1797223443Swill
1798223443Swillstatic void
1799195534Sscottlata_action(union ccb *start_ccb)
1800195534Sscottl{
1801195534Sscottl
1802195534Sscottl	switch (start_ccb->ccb_h.func_code) {
1803195534Sscottl	case XPT_SET_TRAN_SETTINGS:
1804195534Sscottl	{
1805199178Smav		ata_set_transfer_settings(&start_ccb->cts,
1806195534Sscottl					   start_ccb->ccb_h.path->device,
1807195534Sscottl					   /*async_update*/FALSE);
1808195534Sscottl		break;
1809195534Sscottl	}
1810195534Sscottl	case XPT_SCAN_BUS:
1811208582Smjacob	case XPT_SCAN_TGT:
1812195534Sscottl		ata_scan_bus(start_ccb->ccb_h.path->periph, start_ccb);
1813195534Sscottl		break;
1814195534Sscottl	case XPT_SCAN_LUN:
1815195534Sscottl		ata_scan_lun(start_ccb->ccb_h.path->periph,
1816195534Sscottl			      start_ccb->ccb_h.path, start_ccb->crcn.flags,
1817195534Sscottl			      start_ccb);
1818195534Sscottl		break;
1819195534Sscottl	case XPT_GET_TRAN_SETTINGS:
1820195534Sscottl	{
1821195534Sscottl		struct cam_sim *sim;
1822195534Sscottl
1823195534Sscottl		sim = start_ccb->ccb_h.path->bus->sim;
1824195534Sscottl		(*(sim->sim_action))(sim, start_ccb);
1825195534Sscottl		break;
1826195534Sscottl	}
1827203376Smav	case XPT_SCSI_IO:
1828203376Smav	{
1829203376Smav		struct cam_ed *device;
1830203376Smav		u_int	maxlen = 0;
1831203376Smav
1832203376Smav		device = start_ccb->ccb_h.path->device;
1833203376Smav		if (device->protocol == PROTO_SCSI &&
1834203376Smav		    (device->flags & CAM_DEV_IDENTIFY_DATA_VALID)) {
1835203376Smav			uint16_t p =
1836203376Smav			    device->ident_data.config & ATA_PROTO_MASK;
1837203376Smav
1838223019Smav			maxlen =
1839223019Smav			    (device->ident_data.config == ATA_PROTO_CFA) ? 0 :
1840223019Smav			    (p == ATA_PROTO_ATAPI_16) ? 16 :
1841203376Smav			    (p == ATA_PROTO_ATAPI_12) ? 12 : 0;
1842203376Smav		}
1843203376Smav		if (start_ccb->csio.cdb_len > maxlen) {
1844203376Smav			start_ccb->ccb_h.status = CAM_REQ_INVALID;
1845203376Smav			xpt_done(start_ccb);
1846203376Smav			break;
1847203376Smav		}
1848223475Smav		xpt_action_default(start_ccb);
1849223475Smav		break;
1850203376Smav	}
1851223443Swill	case XPT_DEV_ADVINFO:
1852223443Swill	{
1853223443Swill		ata_dev_advinfo(start_ccb);
1854223443Swill		break;
1855223443Swill	}
1856195534Sscottl	default:
1857195534Sscottl		xpt_action_default(start_ccb);
1858195534Sscottl		break;
1859195534Sscottl	}
1860195534Sscottl}
1861195534Sscottl
1862195534Sscottlstatic void
1863199178Smavata_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device,
1864195534Sscottl			   int async_update)
1865195534Sscottl{
1866195534Sscottl	struct	ccb_pathinq cpi;
1867195534Sscottl	struct	ccb_trans_settings cur_cts;
1868195534Sscottl	struct	ccb_trans_settings_scsi *scsi;
1869195534Sscottl	struct	ccb_trans_settings_scsi *cur_scsi;
1870195534Sscottl	struct	cam_sim *sim;
1871195534Sscottl	struct	scsi_inquiry_data *inq_data;
1872195534Sscottl
1873195534Sscottl	if (device == NULL) {
1874195534Sscottl		cts->ccb_h.status = CAM_PATH_INVALID;
1875195534Sscottl		xpt_done((union ccb *)cts);
1876195534Sscottl		return;
1877195534Sscottl	}
1878195534Sscottl
1879195534Sscottl	if (cts->protocol == PROTO_UNKNOWN
1880195534Sscottl	 || cts->protocol == PROTO_UNSPECIFIED) {
1881195534Sscottl		cts->protocol = device->protocol;
1882195534Sscottl		cts->protocol_version = device->protocol_version;
1883195534Sscottl	}
1884195534Sscottl
1885195534Sscottl	if (cts->protocol_version == PROTO_VERSION_UNKNOWN
1886195534Sscottl	 || cts->protocol_version == PROTO_VERSION_UNSPECIFIED)
1887195534Sscottl		cts->protocol_version = device->protocol_version;
1888195534Sscottl
1889195534Sscottl	if (cts->protocol != device->protocol) {
1890195534Sscottl		xpt_print(cts->ccb_h.path, "Uninitialized Protocol %x:%x?\n",
1891195534Sscottl		       cts->protocol, device->protocol);
1892195534Sscottl		cts->protocol = device->protocol;
1893195534Sscottl	}
1894195534Sscottl
1895195534Sscottl	if (cts->protocol_version > device->protocol_version) {
1896195534Sscottl		if (bootverbose) {
1897195534Sscottl			xpt_print(cts->ccb_h.path, "Down reving Protocol "
1898195534Sscottl			    "Version from %d to %d?\n", cts->protocol_version,
1899195534Sscottl			    device->protocol_version);
1900195534Sscottl		}
1901195534Sscottl		cts->protocol_version = device->protocol_version;
1902195534Sscottl	}
1903195534Sscottl
1904195534Sscottl	if (cts->transport == XPORT_UNKNOWN
1905195534Sscottl	 || cts->transport == XPORT_UNSPECIFIED) {
1906195534Sscottl		cts->transport = device->transport;
1907195534Sscottl		cts->transport_version = device->transport_version;
1908195534Sscottl	}
1909195534Sscottl
1910195534Sscottl	if (cts->transport_version == XPORT_VERSION_UNKNOWN
1911195534Sscottl	 || cts->transport_version == XPORT_VERSION_UNSPECIFIED)
1912195534Sscottl		cts->transport_version = device->transport_version;
1913195534Sscottl
1914195534Sscottl	if (cts->transport != device->transport) {
1915195534Sscottl		xpt_print(cts->ccb_h.path, "Uninitialized Transport %x:%x?\n",
1916195534Sscottl		    cts->transport, device->transport);
1917195534Sscottl		cts->transport = device->transport;
1918195534Sscottl	}
1919195534Sscottl
1920195534Sscottl	if (cts->transport_version > device->transport_version) {
1921195534Sscottl		if (bootverbose) {
1922195534Sscottl			xpt_print(cts->ccb_h.path, "Down reving Transport "
1923195534Sscottl			    "Version from %d to %d?\n", cts->transport_version,
1924195534Sscottl			    device->transport_version);
1925195534Sscottl		}
1926195534Sscottl		cts->transport_version = device->transport_version;
1927195534Sscottl	}
1928195534Sscottl
1929195534Sscottl	sim = cts->ccb_h.path->bus->sim;
1930195534Sscottl
1931195534Sscottl	/*
1932195534Sscottl	 * Nothing more of interest to do unless
1933195534Sscottl	 * this is a device connected via the
1934195534Sscottl	 * SCSI protocol.
1935195534Sscottl	 */
1936195534Sscottl	if (cts->protocol != PROTO_SCSI) {
1937195534Sscottl		if (async_update == FALSE)
1938195534Sscottl			(*(sim->sim_action))(sim, (union ccb *)cts);
1939195534Sscottl		return;
1940195534Sscottl	}
1941195534Sscottl
1942195534Sscottl	inq_data = &device->inq_data;
1943195534Sscottl	scsi = &cts->proto_specific.scsi;
1944203108Smav	xpt_setup_ccb(&cpi.ccb_h, cts->ccb_h.path, CAM_PRIORITY_NONE);
1945195534Sscottl	cpi.ccb_h.func_code = XPT_PATH_INQ;
1946195534Sscottl	xpt_action((union ccb *)&cpi);
1947195534Sscottl
1948195534Sscottl	/* SCSI specific sanity checking */
1949195534Sscottl	if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0
1950195534Sscottl	 || (INQ_DATA_TQ_ENABLED(inq_data)) == 0
1951195534Sscottl	 || (device->queue_flags & SCP_QUEUE_DQUE) != 0
1952195534Sscottl	 || (device->mintags == 0)) {
1953195534Sscottl		/*
1954195534Sscottl		 * Can't tag on hardware that doesn't support tags,
1955195534Sscottl		 * doesn't have it enabled, or has broken tag support.
1956195534Sscottl		 */
1957195534Sscottl		scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
1958195534Sscottl	}
1959195534Sscottl
1960195534Sscottl	if (async_update == FALSE) {
1961195534Sscottl		/*
1962195534Sscottl		 * Perform sanity checking against what the
1963195534Sscottl		 * controller and device can do.
1964195534Sscottl		 */
1965203108Smav		xpt_setup_ccb(&cur_cts.ccb_h, cts->ccb_h.path, CAM_PRIORITY_NONE);
1966195534Sscottl		cur_cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
1967195534Sscottl		cur_cts.type = cts->type;
1968195534Sscottl		xpt_action((union ccb *)&cur_cts);
1969195534Sscottl		if ((cur_cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1970195534Sscottl			return;
1971195534Sscottl		}
1972195534Sscottl		cur_scsi = &cur_cts.proto_specific.scsi;
1973195534Sscottl		if ((scsi->valid & CTS_SCSI_VALID_TQ) == 0) {
1974195534Sscottl			scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
1975195534Sscottl			scsi->flags |= cur_scsi->flags & CTS_SCSI_FLAGS_TAG_ENB;
1976195534Sscottl		}
1977195534Sscottl		if ((cur_scsi->valid & CTS_SCSI_VALID_TQ) == 0)
1978195534Sscottl			scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
1979195534Sscottl	}
1980195534Sscottl
1981195534Sscottl	if (cts->type == CTS_TYPE_CURRENT_SETTINGS
1982195534Sscottl	 && (scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
1983195534Sscottl		int device_tagenb;
1984195534Sscottl
1985195534Sscottl		/*
1986195534Sscottl		 * If we are transitioning from tags to no-tags or
1987195534Sscottl		 * vice-versa, we need to carefully freeze and restart
1988195534Sscottl		 * the queue so that we don't overlap tagged and non-tagged
1989195534Sscottl		 * commands.  We also temporarily stop tags if there is
1990195534Sscottl		 * a change in transfer negotiation settings to allow
1991195534Sscottl		 * "tag-less" negotiation.
1992195534Sscottl		 */
1993195534Sscottl		if ((device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0
1994195534Sscottl		 || (device->inq_flags & SID_CmdQue) != 0)
1995195534Sscottl			device_tagenb = TRUE;
1996195534Sscottl		else
1997195534Sscottl			device_tagenb = FALSE;
1998195534Sscottl
1999195534Sscottl		if (((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0
2000195534Sscottl		  && device_tagenb == FALSE)
2001195534Sscottl		 || ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) == 0
2002195534Sscottl		  && device_tagenb == TRUE)) {
2003195534Sscottl
2004195534Sscottl			if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) {
2005195534Sscottl				/*
2006195534Sscottl				 * Delay change to use tags until after a
2007195534Sscottl				 * few commands have gone to this device so
2008195534Sscottl				 * the controller has time to perform transfer
2009195534Sscottl				 * negotiations without tagged messages getting
2010195534Sscottl				 * in the way.
2011195534Sscottl				 */
2012195534Sscottl				device->tag_delay_count = CAM_TAG_DELAY_COUNT;
2013195534Sscottl				device->flags |= CAM_DEV_TAG_AFTER_COUNT;
2014195534Sscottl			} else {
2015199178Smav				xpt_stop_tags(cts->ccb_h.path);
2016195534Sscottl			}
2017195534Sscottl		}
2018195534Sscottl	}
2019195534Sscottl	if (async_update == FALSE)
2020195534Sscottl		(*(sim->sim_action))(sim, (union ccb *)cts);
2021195534Sscottl}
2022195534Sscottl
2023195534Sscottl/*
2024195534Sscottl * Handle any per-device event notifications that require action by the XPT.
2025195534Sscottl */
2026195534Sscottlstatic void
2027195534Sscottlata_dev_async(u_int32_t async_code, struct cam_eb *bus, struct cam_et *target,
2028195534Sscottl	      struct cam_ed *device, void *async_arg)
2029195534Sscottl{
2030195534Sscottl	cam_status status;
2031195534Sscottl	struct cam_path newpath;
2032195534Sscottl
2033195534Sscottl	/*
2034195534Sscottl	 * We only need to handle events for real devices.
2035195534Sscottl	 */
2036195534Sscottl	if (target->target_id == CAM_TARGET_WILDCARD
2037195534Sscottl	 || device->lun_id == CAM_LUN_WILDCARD)
2038195534Sscottl		return;
2039195534Sscottl
2040195534Sscottl	/*
2041195534Sscottl	 * We need our own path with wildcards expanded to
2042195534Sscottl	 * handle certain types of events.
2043195534Sscottl	 */
2044195534Sscottl	if ((async_code == AC_SENT_BDR)
2045195534Sscottl	 || (async_code == AC_BUS_RESET)
2046195534Sscottl	 || (async_code == AC_INQ_CHANGED))
2047195534Sscottl		status = xpt_compile_path(&newpath, NULL,
2048195534Sscottl					  bus->path_id,
2049195534Sscottl					  target->target_id,
2050195534Sscottl					  device->lun_id);
2051195534Sscottl	else
2052195534Sscottl		status = CAM_REQ_CMP_ERR;
2053195534Sscottl
2054195534Sscottl	if (status == CAM_REQ_CMP) {
2055195534Sscottl		if (async_code == AC_INQ_CHANGED) {
2056195534Sscottl			/*
2057195534Sscottl			 * We've sent a start unit command, or
2058195534Sscottl			 * something similar to a device that
2059195534Sscottl			 * may have caused its inquiry data to
2060195534Sscottl			 * change. So we re-scan the device to
2061195534Sscottl			 * refresh the inquiry data for it.
2062195534Sscottl			 */
2063195534Sscottl			ata_scan_lun(newpath.periph, &newpath,
2064195534Sscottl				     CAM_EXPECT_INQ_CHANGE, NULL);
2065203108Smav		} else {
2066203108Smav			/* We need to reinitialize device after reset. */
2067203108Smav			ata_scan_lun(newpath.periph, &newpath,
2068203108Smav				     0, NULL);
2069195534Sscottl		}
2070195534Sscottl		xpt_release_path(&newpath);
2071198748Smav	} else if (async_code == AC_LOST_DEVICE &&
2072198748Smav	    (device->flags & CAM_DEV_UNCONFIGURED) == 0) {
2073195534Sscottl		device->flags |= CAM_DEV_UNCONFIGURED;
2074198748Smav		xpt_release_device(device);
2075195534Sscottl	} else if (async_code == AC_TRANSFER_NEG) {
2076195534Sscottl		struct ccb_trans_settings *settings;
2077195534Sscottl
2078195534Sscottl		settings = (struct ccb_trans_settings *)async_arg;
2079199178Smav		ata_set_transfer_settings(settings, device,
2080195534Sscottl					  /*async_update*/TRUE);
2081195534Sscottl	}
2082195534Sscottl}
2083195534Sscottl
2084204220Smavstatic void
2085204220Smavata_announce_periph(struct cam_periph *periph)
2086204220Smav{
2087204220Smav	struct	ccb_pathinq cpi;
2088204220Smav	struct	ccb_trans_settings cts;
2089204220Smav	struct	cam_path *path = periph->path;
2090204220Smav	u_int	speed;
2091204220Smav	u_int	mb;
2092204220Smav
2093204220Smav	mtx_assert(periph->sim->mtx, MA_OWNED);
2094204220Smav
2095204220Smav	xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
2096204220Smav	cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
2097204220Smav	cts.type = CTS_TYPE_CURRENT_SETTINGS;
2098204220Smav	xpt_action((union ccb*)&cts);
2099204220Smav	if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
2100204220Smav		return;
2101204220Smav	/* Ask the SIM for its base transfer speed */
2102204220Smav	xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL);
2103204220Smav	cpi.ccb_h.func_code = XPT_PATH_INQ;
2104204220Smav	xpt_action((union ccb *)&cpi);
2105204220Smav	/* Report connection speed */
2106204220Smav	speed = cpi.base_transfer_speed;
2107204220Smav	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_ATA) {
2108204220Smav		struct	ccb_trans_settings_ata *ata =
2109204220Smav		    &cts.xport_specific.ata;
2110204220Smav
2111204220Smav		if (ata->valid & CTS_ATA_VALID_MODE)
2112204220Smav			speed = ata_mode2speed(ata->mode);
2113204220Smav	}
2114204220Smav	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SATA) {
2115204220Smav		struct	ccb_trans_settings_sata *sata =
2116204220Smav		    &cts.xport_specific.sata;
2117204220Smav
2118204220Smav		if (sata->valid & CTS_SATA_VALID_REVISION)
2119204220Smav			speed = ata_revision2speed(sata->revision);
2120204220Smav	}
2121204220Smav	mb = speed / 1000;
2122204220Smav	if (mb > 0)
2123204220Smav		printf("%s%d: %d.%03dMB/s transfers",
2124204220Smav		       periph->periph_name, periph->unit_number,
2125204220Smav		       mb, speed % 1000);
2126204220Smav	else
2127204220Smav		printf("%s%d: %dKB/s transfers", periph->periph_name,
2128204220Smav		       periph->unit_number, speed);
2129204220Smav	/* Report additional information about connection */
2130204220Smav	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_ATA) {
2131204220Smav		struct ccb_trans_settings_ata *ata =
2132204220Smav		    &cts.xport_specific.ata;
2133204220Smav
2134204220Smav		printf(" (");
2135204220Smav		if (ata->valid & CTS_ATA_VALID_MODE)
2136204220Smav			printf("%s, ", ata_mode2string(ata->mode));
2137204220Smav		if ((ata->valid & CTS_ATA_VALID_ATAPI) && ata->atapi != 0)
2138204220Smav			printf("ATAPI %dbytes, ", ata->atapi);
2139204220Smav		if (ata->valid & CTS_ATA_VALID_BYTECOUNT)
2140204220Smav			printf("PIO %dbytes", ata->bytecount);
2141204220Smav		printf(")");
2142204220Smav	}
2143204220Smav	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SATA) {
2144204220Smav		struct ccb_trans_settings_sata *sata =
2145204220Smav		    &cts.xport_specific.sata;
2146204220Smav
2147204220Smav		printf(" (");
2148204220Smav		if (sata->valid & CTS_SATA_VALID_REVISION)
2149204220Smav			printf("SATA %d.x, ", sata->revision);
2150204220Smav		else
2151204220Smav			printf("SATA, ");
2152204220Smav		if (sata->valid & CTS_SATA_VALID_MODE)
2153204220Smav			printf("%s, ", ata_mode2string(sata->mode));
2154204220Smav		if ((sata->valid & CTS_ATA_VALID_ATAPI) && sata->atapi != 0)
2155204220Smav			printf("ATAPI %dbytes, ", sata->atapi);
2156204220Smav		if (sata->valid & CTS_SATA_VALID_BYTECOUNT)
2157204220Smav			printf("PIO %dbytes", sata->bytecount);
2158204220Smav		printf(")");
2159204220Smav	}
2160204220Smav	printf("\n");
2161204220Smav}
2162204220Smav
2163