ata_xpt.c revision 307606
1195534Sscottl/*-
2195534Sscottl * Copyright (c) 2009 Alexander Motin <mav@FreeBSD.org>
3195534Sscottl * All rights reserved.
4195534Sscottl *
5195534Sscottl * Redistribution and use in source and binary forms, with or without
6195534Sscottl * modification, are permitted provided that the following conditions
7195534Sscottl * are met:
8195534Sscottl * 1. Redistributions of source code must retain the above copyright
9195534Sscottl *    notice, this list of conditions and the following disclaimer,
10195534Sscottl *    without modification, immediately at the beginning of the file.
11195534Sscottl * 2. Redistributions in binary form must reproduce the above copyright
12195534Sscottl *    notice, this list of conditions and the following disclaimer in the
13195534Sscottl *    documentation and/or other materials provided with the distribution.
14195534Sscottl *
15195534Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16195534Sscottl * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17195534Sscottl * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18195534Sscottl * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19195534Sscottl * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20195534Sscottl * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21195534Sscottl * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22195534Sscottl * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23195534Sscottl * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24195534Sscottl * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25195534Sscottl */
26195534Sscottl
27195534Sscottl#include <sys/cdefs.h>
28195534Sscottl__FBSDID("$FreeBSD: stable/11/sys/cam/ata/ata_xpt.c 307606 2016-10-19 06:15:27Z sephe $");
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
43307606Ssephe#include <sys/eventhandler.h>
44195534Sscottl#include <sys/lock.h>
45195534Sscottl#include <sys/mutex.h>
46195534Sscottl#include <sys/sysctl.h>
47195534Sscottl
48195534Sscottl#include <cam/cam.h>
49195534Sscottl#include <cam/cam_ccb.h>
50195534Sscottl#include <cam/cam_queue.h>
51195534Sscottl#include <cam/cam_periph.h>
52195534Sscottl#include <cam/cam_sim.h>
53195534Sscottl#include <cam/cam_xpt.h>
54195534Sscottl#include <cam/cam_xpt_sim.h>
55195534Sscottl#include <cam/cam_xpt_periph.h>
56195534Sscottl#include <cam/cam_xpt_internal.h>
57195534Sscottl#include <cam/cam_debug.h>
58195534Sscottl
59195534Sscottl#include <cam/scsi/scsi_all.h>
60195534Sscottl#include <cam/scsi/scsi_message.h>
61195534Sscottl#include <cam/ata/ata_all.h>
62195534Sscottl#include <machine/stdarg.h>	/* for xpt_print below */
63195534Sscottl#include "opt_cam.h"
64195534Sscottl
65199178Smavstruct ata_quirk_entry {
66195534Sscottl	struct scsi_inquiry_pattern inq_pat;
67195534Sscottl	u_int8_t quirks;
68199178Smav#define	CAM_QUIRK_MAXTAGS	0x01
69236234Smav	u_int mintags;
70195534Sscottl	u_int maxtags;
71195534Sscottl};
72195534Sscottl
73195534Sscottlstatic periph_init_t probe_periph_init;
74195534Sscottl
75195534Sscottlstatic struct periph_driver probe_driver =
76195534Sscottl{
77195653Smav	probe_periph_init, "aprobe",
78198708Smav	TAILQ_HEAD_INITIALIZER(probe_driver.units), /* generation */ 0,
79198708Smav	CAM_PERIPH_DRV_EARLY
80195534Sscottl};
81195534Sscottl
82195653SmavPERIPHDRIVER_DECLARE(aprobe, probe_driver);
83195534Sscottl
84195534Sscottltypedef enum {
85195534Sscottl	PROBE_RESET,
86195534Sscottl	PROBE_IDENTIFY,
87203421Smav	PROBE_SPINUP,
88195534Sscottl	PROBE_SETMODE,
89207499Smav	PROBE_SETPM,
90207499Smav	PROBE_SETAPST,
91207499Smav	PROBE_SETDMAAA,
92220602Smav	PROBE_SETAN,
93198708Smav	PROBE_SET_MULTI,
94195534Sscottl	PROBE_INQUIRY,
95195534Sscottl	PROBE_FULL_INQUIRY,
96195534Sscottl	PROBE_PM_PID,
97195534Sscottl	PROBE_PM_PRV,
98235897Smav	PROBE_IDENTIFY_SES,
99235897Smav	PROBE_IDENTIFY_SAFTE,
100236613Smav	PROBE_DONE,
101195534Sscottl	PROBE_INVALID
102195534Sscottl} probe_action;
103195534Sscottl
104195534Sscottlstatic char *probe_action_text[] = {
105195534Sscottl	"PROBE_RESET",
106195534Sscottl	"PROBE_IDENTIFY",
107203421Smav	"PROBE_SPINUP",
108195534Sscottl	"PROBE_SETMODE",
109207499Smav	"PROBE_SETPM",
110207499Smav	"PROBE_SETAPST",
111207499Smav	"PROBE_SETDMAAA",
112220602Smav	"PROBE_SETAN",
113198708Smav	"PROBE_SET_MULTI",
114195534Sscottl	"PROBE_INQUIRY",
115195534Sscottl	"PROBE_FULL_INQUIRY",
116195534Sscottl	"PROBE_PM_PID",
117195534Sscottl	"PROBE_PM_PRV",
118235897Smav	"PROBE_IDENTIFY_SES",
119235897Smav	"PROBE_IDENTIFY_SAFTE",
120236613Smav	"PROBE_DONE",
121195534Sscottl	"PROBE_INVALID"
122195534Sscottl};
123195534Sscottl
124195534Sscottl#define PROBE_SET_ACTION(softc, newaction)	\
125195534Sscottldo {									\
126195534Sscottl	char **text;							\
127195534Sscottl	text = probe_action_text;					\
128236613Smav	CAM_DEBUG((softc)->periph->path, CAM_DEBUG_PROBE,		\
129195534Sscottl	    ("Probe %s to %s\n", text[(softc)->action],			\
130195534Sscottl	    text[(newaction)]));					\
131195534Sscottl	(softc)->action = (newaction);					\
132195534Sscottl} while(0)
133195534Sscottl
134195534Sscottltypedef enum {
135195534Sscottl	PROBE_NO_ANNOUNCE	= 0x04
136195534Sscottl} probe_flags;
137195534Sscottl
138195534Sscottltypedef struct {
139195534Sscottl	TAILQ_HEAD(, ccb_hdr) request_ccbs;
140203385Smav	struct ata_params	ident_data;
141195534Sscottl	probe_action	action;
142195534Sscottl	probe_flags	flags;
143195534Sscottl	uint32_t	pm_pid;
144195534Sscottl	uint32_t	pm_prv;
145203108Smav	int		restart;
146203421Smav	int		spinup;
147209744Smav	int		faults;
148207499Smav	u_int		caps;
149195534Sscottl	struct cam_periph *periph;
150195534Sscottl} probe_softc;
151195534Sscottl
152199178Smavstatic struct ata_quirk_entry ata_quirk_table[] =
153195534Sscottl{
154195534Sscottl	{
155195534Sscottl		/* Default tagged queuing parameters for all devices */
156195534Sscottl		{
157195534Sscottl		  T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED,
158195534Sscottl		  /*vendor*/"*", /*product*/"*", /*revision*/"*"
159195534Sscottl		},
160236234Smav		/*quirks*/0, /*mintags*/0, /*maxtags*/0
161195534Sscottl	},
162195534Sscottl};
163195534Sscottl
164195534Sscottlstatic cam_status	proberegister(struct cam_periph *periph,
165195534Sscottl				      void *arg);
166195534Sscottlstatic void	 probeschedule(struct cam_periph *probe_periph);
167195534Sscottlstatic void	 probestart(struct cam_periph *periph, union ccb *start_ccb);
168236437Smavstatic void	 proberequestdefaultnegotiation(struct cam_periph *periph);
169195534Sscottlstatic void	 probedone(struct cam_periph *periph, union ccb *done_ccb);
170195534Sscottlstatic void	 probecleanup(struct cam_periph *periph);
171199178Smavstatic void	 ata_find_quirk(struct cam_ed *device);
172195534Sscottlstatic void	 ata_scan_bus(struct cam_periph *periph, union ccb *ccb);
173195534Sscottlstatic void	 ata_scan_lun(struct cam_periph *periph,
174195534Sscottl			       struct cam_path *path, cam_flags flags,
175195534Sscottl			       union ccb *ccb);
176195534Sscottlstatic void	 xptscandone(struct cam_periph *periph, union ccb *done_ccb);
177195534Sscottlstatic struct cam_ed *
178195534Sscottl		 ata_alloc_device(struct cam_eb *bus, struct cam_et *target,
179195534Sscottl				   lun_id_t lun_id);
180195534Sscottlstatic void	 ata_device_transport(struct cam_path *path);
181236437Smavstatic void	 ata_get_transfer_settings(struct ccb_trans_settings *cts);
182199178Smavstatic void	 ata_set_transfer_settings(struct ccb_trans_settings *cts,
183256843Smav					    struct cam_path *path,
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 (request_ccb == NULL) {
226195534Sscottl		printf("proberegister: no probe CCB, "
227195534Sscottl		       "can't register device\n");
228195534Sscottl		return(CAM_REQ_CMP_ERR);
229195534Sscottl	}
230195534Sscottl
231203421Smav	softc = (probe_softc *)malloc(sizeof(*softc), M_CAMXPT, M_ZERO | M_NOWAIT);
232195534Sscottl
233195534Sscottl	if (softc == NULL) {
234195534Sscottl		printf("proberegister: Unable to probe new device. "
235195534Sscottl		       "Unable to allocate softc\n");
236195534Sscottl		return(CAM_REQ_CMP_ERR);
237195534Sscottl	}
238195534Sscottl	TAILQ_INIT(&softc->request_ccbs);
239195534Sscottl	TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h,
240195534Sscottl			  periph_links.tqe);
241195534Sscottl	softc->flags = 0;
242195534Sscottl	periph->softc = softc;
243195534Sscottl	softc->periph = periph;
244195534Sscottl	softc->action = PROBE_INVALID;
245195534Sscottl	status = cam_periph_acquire(periph);
246195534Sscottl	if (status != CAM_REQ_CMP) {
247195534Sscottl		return (status);
248195534Sscottl	}
249236613Smav	CAM_DEBUG(periph->path, CAM_DEBUG_PROBE, ("Probe started\n"));
250256843Smav	ata_device_transport(periph->path);
251195534Sscottl	probeschedule(periph);
252195534Sscottl	return(CAM_REQ_CMP);
253195534Sscottl}
254195534Sscottl
255195534Sscottlstatic void
256195534Sscottlprobeschedule(struct cam_periph *periph)
257195534Sscottl{
258195534Sscottl	union ccb *ccb;
259195534Sscottl	probe_softc *softc;
260195534Sscottl
261195534Sscottl	softc = (probe_softc *)periph->softc;
262195534Sscottl	ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs);
263195534Sscottl
264198389Smav	if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) ||
265235897Smav	    periph->path->device->protocol == PROTO_SATAPM ||
266235897Smav	    periph->path->device->protocol == PROTO_SEMB)
267195534Sscottl		PROBE_SET_ACTION(softc, PROBE_RESET);
268195534Sscottl	else
269195534Sscottl		PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
270195534Sscottl
271195534Sscottl	if (ccb->crcn.flags & CAM_EXPECT_INQ_CHANGE)
272195534Sscottl		softc->flags |= PROBE_NO_ANNOUNCE;
273195534Sscottl	else
274195534Sscottl		softc->flags &= ~PROBE_NO_ANNOUNCE;
275195534Sscottl
276203108Smav	xpt_schedule(periph, CAM_PRIORITY_XPT);
277195534Sscottl}
278195534Sscottl
279195534Sscottlstatic void
280195534Sscottlprobestart(struct cam_periph *periph, union ccb *start_ccb)
281195534Sscottl{
282199747Smav	struct ccb_trans_settings cts;
283195534Sscottl	struct ccb_ataio *ataio;
284195534Sscottl	struct ccb_scsiio *csio;
285195534Sscottl	probe_softc *softc;
286198708Smav	struct cam_path *path;
287198708Smav	struct ata_params *ident_buf;
288195534Sscottl
289195534Sscottl	CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probestart\n"));
290195534Sscottl
291195534Sscottl	softc = (probe_softc *)periph->softc;
292198708Smav	path = start_ccb->ccb_h.path;
293195534Sscottl	ataio = &start_ccb->ataio;
294195534Sscottl	csio = &start_ccb->csio;
295198708Smav	ident_buf = &periph->path->device->ident_data;
296195534Sscottl
297203108Smav	if (softc->restart) {
298203108Smav		softc->restart = 0;
299203108Smav		if ((path->device->flags & CAM_DEV_UNCONFIGURED) ||
300235897Smav		    path->device->protocol == PROTO_SATAPM ||
301235897Smav		    path->device->protocol == PROTO_SEMB)
302203108Smav			softc->action = PROBE_RESET;
303203108Smav		else
304203108Smav			softc->action = PROBE_IDENTIFY;
305203108Smav	}
306195534Sscottl	switch (softc->action) {
307195534Sscottl	case PROBE_RESET:
308195534Sscottl		cam_fill_ataio(ataio,
309195534Sscottl		      0,
310195534Sscottl		      probedone,
311195534Sscottl		      /*flags*/CAM_DIR_NONE,
312198389Smav		      0,
313195534Sscottl		      /*data_ptr*/NULL,
314195534Sscottl		      /*dxfer_len*/0,
315203108Smav		      15 * 1000);
316195534Sscottl		ata_reset_cmd(ataio);
317195534Sscottl		break;
318195534Sscottl	case PROBE_IDENTIFY:
319195534Sscottl		cam_fill_ataio(ataio,
320195534Sscottl		      1,
321195534Sscottl		      probedone,
322195534Sscottl		      /*flags*/CAM_DIR_IN,
323198389Smav		      0,
324203385Smav		      /*data_ptr*/(u_int8_t *)&softc->ident_data,
325203385Smav		      /*dxfer_len*/sizeof(softc->ident_data),
326195534Sscottl		      30 * 1000);
327195534Sscottl		if (periph->path->device->protocol == PROTO_ATA)
328196659Smav			ata_28bit_cmd(ataio, ATA_ATA_IDENTIFY, 0, 0, 0);
329195534Sscottl		else
330196659Smav			ata_28bit_cmd(ataio, ATA_ATAPI_IDENTIFY, 0, 0, 0);
331195534Sscottl		break;
332203421Smav	case PROBE_SPINUP:
333203421Smav		if (bootverbose)
334203421Smav			xpt_print(path, "Spinning up device\n");
335203421Smav		cam_fill_ataio(ataio,
336203421Smav		      1,
337203421Smav		      probedone,
338203421Smav		      /*flags*/CAM_DIR_NONE | CAM_HIGH_POWER,
339203421Smav		      0,
340203421Smav		      /*data_ptr*/NULL,
341203421Smav		      /*dxfer_len*/0,
342203421Smav		      30 * 1000);
343203421Smav		ata_28bit_cmd(ataio, ATA_SETFEATURES, ATA_SF_PUIS_SPINUP, 0, 0);
344203421Smav		break;
345195534Sscottl	case PROBE_SETMODE:
346199747Smav	{
347199747Smav		int mode, wantmode;
348199747Smav
349199747Smav		mode = 0;
350199747Smav		/* Fetch user modes from SIM. */
351199747Smav		bzero(&cts, sizeof(cts));
352203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
353199747Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
354199747Smav		cts.type = CTS_TYPE_USER_SETTINGS;
355199747Smav		xpt_action((union ccb *)&cts);
356199747Smav		if (path->device->transport == XPORT_ATA) {
357199747Smav			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_MODE)
358199747Smav				mode = cts.xport_specific.ata.mode;
359199747Smav		} else {
360199799Smav			if (cts.xport_specific.sata.valid & CTS_SATA_VALID_MODE)
361199747Smav				mode = cts.xport_specific.sata.mode;
362199747Smav		}
363230912Smav		if (periph->path->device->protocol == PROTO_ATA) {
364230912Smav			if (ata_dma == 0 && (mode == 0 || mode > ATA_PIO_MAX))
365230912Smav				mode = ATA_PIO_MAX;
366230912Smav		} else {
367230912Smav			if (atapi_dma == 0 && (mode == 0 || mode > ATA_PIO_MAX))
368230912Smav				mode = ATA_PIO_MAX;
369230912Smav		}
370199747Smavnegotiate:
371199747Smav		/* Honor device capabilities. */
372199747Smav		wantmode = mode = ata_max_mode(ident_buf, mode);
373199747Smav		/* Report modes to SIM. */
374199747Smav		bzero(&cts, sizeof(cts));
375203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
376199747Smav		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
377199747Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
378199747Smav		if (path->device->transport == XPORT_ATA) {
379199747Smav			cts.xport_specific.ata.mode = mode;
380199747Smav			cts.xport_specific.ata.valid = CTS_ATA_VALID_MODE;
381199747Smav		} else {
382199747Smav			cts.xport_specific.sata.mode = mode;
383199747Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_MODE;
384199747Smav		}
385199747Smav		xpt_action((union ccb *)&cts);
386200171Smav		/* Fetch current modes from SIM. */
387199747Smav		bzero(&cts, sizeof(cts));
388203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
389199747Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
390199747Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
391199747Smav		xpt_action((union ccb *)&cts);
392199747Smav		if (path->device->transport == XPORT_ATA) {
393199747Smav			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_MODE)
394199747Smav				mode = cts.xport_specific.ata.mode;
395199747Smav		} else {
396199747Smav			if (cts.xport_specific.ata.valid & CTS_SATA_VALID_MODE)
397199747Smav				mode = cts.xport_specific.sata.mode;
398199747Smav		}
399199747Smav		/* If SIM disagree - renegotiate. */
400199747Smav		if (mode != wantmode)
401199747Smav			goto negotiate;
402220886Smav		/* Remember what transport thinks about DMA. */
403220886Smav		if (mode < ATA_DMA)
404220886Smav			path->device->inq_flags &= ~SID_DMA;
405220886Smav		else
406220886Smav			path->device->inq_flags |= SID_DMA;
407236393Smav		xpt_async(AC_GETDEV_CHANGED, path, NULL);
408195534Sscottl		cam_fill_ataio(ataio,
409195534Sscottl		      1,
410195534Sscottl		      probedone,
411196353Smav		      /*flags*/CAM_DIR_NONE,
412196353Smav		      0,
413196353Smav		      /*data_ptr*/NULL,
414196353Smav		      /*dxfer_len*/0,
415195534Sscottl		      30 * 1000);
416199747Smav		ata_28bit_cmd(ataio, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
417195534Sscottl		break;
418199747Smav	}
419207499Smav	case PROBE_SETPM:
420207499Smav		cam_fill_ataio(ataio,
421207499Smav		    1,
422207499Smav		    probedone,
423207499Smav		    CAM_DIR_NONE,
424207499Smav		    0,
425207499Smav		    NULL,
426207499Smav		    0,
427207499Smav		    30*1000);
428207499Smav		ata_28bit_cmd(ataio, ATA_SETFEATURES,
429207499Smav		    (softc->caps & CTS_SATA_CAPS_H_PMREQ) ? 0x10 : 0x90,
430207499Smav		    0, 0x03);
431207499Smav		break;
432207499Smav	case PROBE_SETAPST:
433207499Smav		cam_fill_ataio(ataio,
434207499Smav		    1,
435207499Smav		    probedone,
436207499Smav		    CAM_DIR_NONE,
437207499Smav		    0,
438207499Smav		    NULL,
439207499Smav		    0,
440207499Smav		    30*1000);
441207499Smav		ata_28bit_cmd(ataio, ATA_SETFEATURES,
442207499Smav		    (softc->caps & CTS_SATA_CAPS_H_APST) ? 0x10 : 0x90,
443207499Smav		    0, 0x07);
444207499Smav		break;
445207499Smav	case PROBE_SETDMAAA:
446207499Smav		cam_fill_ataio(ataio,
447207499Smav		    1,
448207499Smav		    probedone,
449207499Smav		    CAM_DIR_NONE,
450207499Smav		    0,
451207499Smav		    NULL,
452207499Smav		    0,
453207499Smav		    30*1000);
454207499Smav		ata_28bit_cmd(ataio, ATA_SETFEATURES,
455207499Smav		    (softc->caps & CTS_SATA_CAPS_H_DMAAA) ? 0x10 : 0x90,
456207499Smav		    0, 0x02);
457207499Smav		break;
458220602Smav	case PROBE_SETAN:
459270327Simp		/* Remember what transport thinks about AEN. */
460270327Simp		if (softc->caps & CTS_SATA_CAPS_H_AN)
461238886Smav			path->device->inq_flags |= SID_AEN;
462238886Smav		else
463238886Smav			path->device->inq_flags &= ~SID_AEN;
464238886Smav		xpt_async(AC_GETDEV_CHANGED, path, NULL);
465220602Smav		cam_fill_ataio(ataio,
466220602Smav		    1,
467220602Smav		    probedone,
468220602Smav		    CAM_DIR_NONE,
469220602Smav		    0,
470220602Smav		    NULL,
471220602Smav		    0,
472220602Smav		    30*1000);
473220602Smav		ata_28bit_cmd(ataio, ATA_SETFEATURES,
474220602Smav		    (softc->caps & CTS_SATA_CAPS_H_AN) ? 0x10 : 0x90,
475220602Smav		    0, 0x05);
476220602Smav		break;
477198708Smav	case PROBE_SET_MULTI:
478198708Smav	{
479200171Smav		u_int sectors, bytecount;
480198708Smav
481200171Smav		bytecount = 8192;	/* SATA maximum */
482200171Smav		/* Fetch user bytecount from SIM. */
483200171Smav		bzero(&cts, sizeof(cts));
484203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
485200171Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
486200171Smav		cts.type = CTS_TYPE_USER_SETTINGS;
487200171Smav		xpt_action((union ccb *)&cts);
488200171Smav		if (path->device->transport == XPORT_ATA) {
489200171Smav			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_BYTECOUNT)
490200171Smav				bytecount = cts.xport_specific.ata.bytecount;
491200171Smav		} else {
492200171Smav			if (cts.xport_specific.sata.valid & CTS_SATA_VALID_BYTECOUNT)
493200171Smav				bytecount = cts.xport_specific.sata.bytecount;
494200171Smav		}
495200171Smav		/* Honor device capabilities. */
496200171Smav		sectors = max(1, min(ident_buf->sectors_intr & 0xff,
497200171Smav		    bytecount / ata_logical_sector_size(ident_buf)));
498198708Smav		/* Report bytecount to SIM. */
499198708Smav		bzero(&cts, sizeof(cts));
500203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
501198708Smav		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
502198708Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
503198708Smav		if (path->device->transport == XPORT_ATA) {
504198897Smav			cts.xport_specific.ata.bytecount = sectors *
505198897Smav			    ata_logical_sector_size(ident_buf);
506198708Smav			cts.xport_specific.ata.valid = CTS_ATA_VALID_BYTECOUNT;
507198708Smav		} else {
508198897Smav			cts.xport_specific.sata.bytecount = sectors *
509198897Smav			    ata_logical_sector_size(ident_buf);
510198708Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_BYTECOUNT;
511198708Smav		}
512198708Smav		xpt_action((union ccb *)&cts);
513200171Smav		/* Fetch current bytecount from SIM. */
514200171Smav		bzero(&cts, sizeof(cts));
515203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
516200171Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
517200171Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
518200171Smav		xpt_action((union ccb *)&cts);
519200171Smav		if (path->device->transport == XPORT_ATA) {
520200171Smav			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_BYTECOUNT)
521200171Smav				bytecount = cts.xport_specific.ata.bytecount;
522200171Smav		} else {
523200171Smav			if (cts.xport_specific.sata.valid & CTS_SATA_VALID_BYTECOUNT)
524200171Smav				bytecount = cts.xport_specific.sata.bytecount;
525200171Smav		}
526200171Smav		sectors = bytecount / ata_logical_sector_size(ident_buf);
527198708Smav
528198708Smav		cam_fill_ataio(ataio,
529198708Smav		    1,
530198708Smav		    probedone,
531198708Smav		    CAM_DIR_NONE,
532198708Smav		    0,
533198708Smav		    NULL,
534198708Smav		    0,
535198708Smav		    30*1000);
536198708Smav		ata_28bit_cmd(ataio, ATA_SET_MULTI, 0, 0, sectors);
537198708Smav		break;
538195534Sscottl	}
539195534Sscottl	case PROBE_INQUIRY:
540200171Smav	{
541200171Smav		u_int bytecount;
542200171Smav
543200171Smav		bytecount = 8192;	/* SATA maximum */
544200171Smav		/* Fetch user bytecount from SIM. */
545200171Smav		bzero(&cts, sizeof(cts));
546203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
547200171Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
548200171Smav		cts.type = CTS_TYPE_USER_SETTINGS;
549200171Smav		xpt_action((union ccb *)&cts);
550200171Smav		if (path->device->transport == XPORT_ATA) {
551200171Smav			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_BYTECOUNT)
552200171Smav				bytecount = cts.xport_specific.ata.bytecount;
553200171Smav		} else {
554200171Smav			if (cts.xport_specific.sata.valid & CTS_SATA_VALID_BYTECOUNT)
555200171Smav				bytecount = cts.xport_specific.sata.bytecount;
556200171Smav		}
557200171Smav		/* Honor device capabilities. */
558200171Smav		bytecount &= ~1;
559200171Smav		bytecount = max(2, min(65534, bytecount));
560200171Smav		if (ident_buf->satacapabilities != 0x0000 &&
561200171Smav		    ident_buf->satacapabilities != 0xffff) {
562200171Smav			bytecount = min(8192, bytecount);
563200171Smav		}
564200171Smav		/* Report bytecount to SIM. */
565200171Smav		bzero(&cts, sizeof(cts));
566203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
567200171Smav		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
568200171Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
569200171Smav		if (path->device->transport == XPORT_ATA) {
570200171Smav			cts.xport_specific.ata.bytecount = bytecount;
571200171Smav			cts.xport_specific.ata.valid = CTS_ATA_VALID_BYTECOUNT;
572200171Smav		} else {
573200171Smav			cts.xport_specific.sata.bytecount = bytecount;
574200171Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_BYTECOUNT;
575200171Smav		}
576200171Smav		xpt_action((union ccb *)&cts);
577200171Smav		/* FALLTHROUGH */
578200171Smav	}
579195534Sscottl	case PROBE_FULL_INQUIRY:
580195534Sscottl	{
581195534Sscottl		u_int inquiry_len;
582195534Sscottl		struct scsi_inquiry_data *inq_buf =
583195534Sscottl		    &periph->path->device->inq_data;
584195534Sscottl
585195534Sscottl		if (softc->action == PROBE_INQUIRY)
586195534Sscottl			inquiry_len = SHORT_INQUIRY_LENGTH;
587195534Sscottl		else
588195534Sscottl			inquiry_len = SID_ADDITIONAL_LENGTH(inq_buf);
589195534Sscottl		/*
590195534Sscottl		 * Some parallel SCSI devices fail to send an
591195534Sscottl		 * ignore wide residue message when dealing with
592195534Sscottl		 * odd length inquiry requests.  Round up to be
593195534Sscottl		 * safe.
594195534Sscottl		 */
595195534Sscottl		inquiry_len = roundup2(inquiry_len, 2);
596195534Sscottl		scsi_inquiry(csio,
597195534Sscottl			     /*retries*/1,
598195534Sscottl			     probedone,
599195534Sscottl			     MSG_SIMPLE_Q_TAG,
600195534Sscottl			     (u_int8_t *)inq_buf,
601195534Sscottl			     inquiry_len,
602195534Sscottl			     /*evpd*/FALSE,
603195534Sscottl			     /*page_code*/0,
604195534Sscottl			     SSD_MIN_SIZE,
605195534Sscottl			     /*timeout*/60 * 1000);
606195534Sscottl		break;
607195534Sscottl	}
608195534Sscottl	case PROBE_PM_PID:
609195534Sscottl		cam_fill_ataio(ataio,
610195534Sscottl		      1,
611195534Sscottl		      probedone,
612195534Sscottl		      /*flags*/CAM_DIR_NONE,
613198389Smav		      0,
614195534Sscottl		      /*data_ptr*/NULL,
615195534Sscottl		      /*dxfer_len*/0,
616195534Sscottl		      10 * 1000);
617195534Sscottl		ata_pm_read_cmd(ataio, 0, 15);
618195534Sscottl		break;
619195534Sscottl	case PROBE_PM_PRV:
620195534Sscottl		cam_fill_ataio(ataio,
621195534Sscottl		      1,
622195534Sscottl		      probedone,
623195534Sscottl		      /*flags*/CAM_DIR_NONE,
624198389Smav		      0,
625195534Sscottl		      /*data_ptr*/NULL,
626195534Sscottl		      /*dxfer_len*/0,
627195534Sscottl		      10 * 1000);
628195534Sscottl		ata_pm_read_cmd(ataio, 1, 15);
629195534Sscottl		break;
630235897Smav	case PROBE_IDENTIFY_SES:
631235897Smav		cam_fill_ataio(ataio,
632235897Smav		      1,
633235897Smav		      probedone,
634235897Smav		      /*flags*/CAM_DIR_IN,
635235897Smav		      0,
636235897Smav		      /*data_ptr*/(u_int8_t *)&softc->ident_data,
637235897Smav		      /*dxfer_len*/sizeof(softc->ident_data),
638235897Smav		      30 * 1000);
639235897Smav		ata_28bit_cmd(ataio, ATA_SEP_ATTN, 0xEC, 0x02,
640235897Smav		    sizeof(softc->ident_data) / 4);
641235897Smav		break;
642235897Smav	case PROBE_IDENTIFY_SAFTE:
643235897Smav		cam_fill_ataio(ataio,
644235897Smav		      1,
645235897Smav		      probedone,
646235897Smav		      /*flags*/CAM_DIR_IN,
647235897Smav		      0,
648235897Smav		      /*data_ptr*/(u_int8_t *)&softc->ident_data,
649235897Smav		      /*dxfer_len*/sizeof(softc->ident_data),
650235897Smav		      30 * 1000);
651235897Smav		ata_28bit_cmd(ataio, ATA_SEP_ATTN, 0xEC, 0x00,
652235897Smav		    sizeof(softc->ident_data) / 4);
653235897Smav		break;
654195534Sscottl	default:
655236613Smav		panic("probestart: invalid action state 0x%x\n", softc->action);
656195534Sscottl	}
657249466Smav	start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
658195534Sscottl	xpt_action(start_ccb);
659195534Sscottl}
660236437Smav
661195534Sscottlstatic void
662195534Sscottlproberequestdefaultnegotiation(struct cam_periph *periph)
663195534Sscottl{
664195534Sscottl	struct ccb_trans_settings cts;
665195534Sscottl
666203108Smav	xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NONE);
667195534Sscottl	cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
668195534Sscottl	cts.type = CTS_TYPE_USER_SETTINGS;
669195534Sscottl	xpt_action((union ccb *)&cts);
670236437Smav	if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
671195534Sscottl		return;
672236437Smav	cts.xport_specific.valid = 0;
673195534Sscottl	cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
674195534Sscottl	cts.type = CTS_TYPE_CURRENT_SETTINGS;
675195534Sscottl	xpt_action((union ccb *)&cts);
676195534Sscottl}
677195534Sscottl
678195534Sscottlstatic void
679195534Sscottlprobedone(struct cam_periph *periph, union ccb *done_ccb)
680195534Sscottl{
681199747Smav	struct ccb_trans_settings cts;
682195534Sscottl	struct ata_params *ident_buf;
683235897Smav	struct scsi_inquiry_data *inq_buf;
684195534Sscottl	probe_softc *softc;
685195534Sscottl	struct cam_path *path;
686217444Smav	cam_status status;
687195534Sscottl	u_int32_t  priority;
688207499Smav	u_int caps;
689235897Smav	int changed = 1, found = 1;
690235897Smav	static const uint8_t fake_device_id_hdr[8] =
691235897Smav	    {0, SVPD_DEVICE_ID, 0, 12,
692235897Smav	     SVPD_ID_CODESET_BINARY, SVPD_ID_TYPE_NAA, 0, 8};
693195534Sscottl
694195534Sscottl	CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probedone\n"));
695195534Sscottl
696195534Sscottl	softc = (probe_softc *)periph->softc;
697195534Sscottl	path = done_ccb->ccb_h.path;
698195534Sscottl	priority = done_ccb->ccb_h.pinfo.priority;
699195534Sscottl	ident_buf = &path->device->ident_data;
700235897Smav	inq_buf = &path->device->inq_data;
701195534Sscottl
702198708Smav	if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
703236814Smav		if (cam_periph_error(done_ccb,
704236814Smav		    0, softc->restart ? (SF_NO_RECOVERY | SF_NO_RETRY) : 0,
705249466Smav		    NULL) == ERESTART) {
706249466Smavout:
707249466Smav			/* Drop freeze taken due to CAM_DEV_QFREEZE flag set. */
708249466Smav			cam_release_devq(path, 0, 0, 0, FALSE);
709195534Sscottl			return;
710249466Smav		}
711209744Smav		if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
712195534Sscottl			/* Don't wedge the queue */
713249466Smav			xpt_release_devq(path, /*count*/1, /*run_queue*/TRUE);
714195534Sscottl		}
715217444Smav		status = done_ccb->ccb_h.status & CAM_STATUS_MASK;
716209744Smav		if (softc->restart) {
717209744Smav			softc->faults++;
718209744Smav			if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) ==
719209744Smav			    CAM_CMD_TIMEOUT)
720209744Smav				softc->faults += 4;
721209744Smav			if (softc->faults < 10)
722209744Smav				goto done;
723209744Smav			else
724209744Smav				softc->restart = 0;
725217444Smav
726198708Smav		/* Old PIO2 devices may not support mode setting. */
727217444Smav		} else if (softc->action == PROBE_SETMODE &&
728217444Smav		    status == CAM_ATA_STATUS_ERROR &&
729198708Smav		    ata_max_pmode(ident_buf) <= ATA_PIO2 &&
730217444Smav		    (ident_buf->capabilities1 & ATA_SUPPORT_IORDY) == 0) {
731198708Smav			goto noerror;
732217444Smav
733198708Smav		/*
734217444Smav		 * Some old WD SATA disks report supported and enabled
735217444Smav		 * device-initiated interface power management, but return
736217444Smav		 * ABORT on attempt to disable it.
737217444Smav		 */
738217444Smav		} else if (softc->action == PROBE_SETPM &&
739217444Smav		    status == CAM_ATA_STATUS_ERROR) {
740217444Smav			goto noerror;
741217875Smav
742217875Smav		/*
743217875Smav		 * Some HP SATA disks report supported DMA Auto-Activation,
744217875Smav		 * but return ABORT on attempt to enable it.
745217875Smav		 */
746217875Smav		} else if (softc->action == PROBE_SETDMAAA &&
747217875Smav		    status == CAM_ATA_STATUS_ERROR) {
748217875Smav			goto noerror;
749235897Smav
750235897Smav		/*
751235897Smav		 * SES and SAF-TE SEPs have different IDENTIFY commands,
752235897Smav		 * but SATA specification doesn't tell how to identify them.
753235897Smav		 * Until better way found, just try another if first fail.
754235897Smav		 */
755235897Smav		} else if (softc->action == PROBE_IDENTIFY_SES &&
756235897Smav		    status == CAM_ATA_STATUS_ERROR) {
757235897Smav			PROBE_SET_ACTION(softc, PROBE_IDENTIFY_SAFTE);
758235897Smav			xpt_release_ccb(done_ccb);
759235897Smav			xpt_schedule(periph, priority);
760249466Smav			goto out;
761217444Smav		}
762217444Smav
763217444Smav		/*
764198708Smav		 * If we get to this point, we got an error status back
765198708Smav		 * from the inquiry and the error status doesn't require
766198708Smav		 * automatically retrying the command.  Therefore, the
767198708Smav		 * inquiry failed.  If we had inquiry information before
768198708Smav		 * for this device, but this latest inquiry command failed,
769198708Smav		 * the device has probably gone away.  If this device isn't
770198708Smav		 * already marked unconfigured, notify the peripheral
771198708Smav		 * drivers that this device is no more.
772198708Smav		 */
773209744Smavdevice_fail:	if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0)
774198708Smav			xpt_async(AC_LOST_DEVICE, path, NULL);
775236613Smav		PROBE_SET_ACTION(softc, PROBE_INVALID);
776198708Smav		found = 0;
777198708Smav		goto done;
778198708Smav	}
779198708Smavnoerror:
780203385Smav	if (softc->restart)
781203385Smav		goto done;
782198708Smav	switch (softc->action) {
783198708Smav	case PROBE_RESET:
784195534Sscottl	{
785198708Smav		int sign = (done_ccb->ataio.res.lba_high << 8) +
786198708Smav		    done_ccb->ataio.res.lba_mid;
787236613Smav		CAM_DEBUG(path, CAM_DEBUG_PROBE,
788236613Smav		    ("SIGNATURE: %04x\n", sign));
789198708Smav		if (sign == 0x0000 &&
790198708Smav		    done_ccb->ccb_h.target_id != 15) {
791198708Smav			path->device->protocol = PROTO_ATA;
792198708Smav			PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
793198708Smav		} else if (sign == 0x9669 &&
794198708Smav		    done_ccb->ccb_h.target_id == 15) {
795199747Smav			/* Report SIM that PM is present. */
796198708Smav			bzero(&cts, sizeof(cts));
797203108Smav			xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
798198708Smav			cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
799198708Smav			cts.type = CTS_TYPE_CURRENT_SETTINGS;
800198708Smav			cts.xport_specific.sata.pm_present = 1;
801198708Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_PM;
802198708Smav			xpt_action((union ccb *)&cts);
803198708Smav			path->device->protocol = PROTO_SATAPM;
804198708Smav			PROBE_SET_ACTION(softc, PROBE_PM_PID);
805235897Smav		} else if (sign == 0xc33c &&
806235897Smav		    done_ccb->ccb_h.target_id != 15) {
807235897Smav			path->device->protocol = PROTO_SEMB;
808235897Smav			PROBE_SET_ACTION(softc, PROBE_IDENTIFY_SES);
809198708Smav		} else if (sign == 0xeb14 &&
810198708Smav		    done_ccb->ccb_h.target_id != 15) {
811198708Smav			path->device->protocol = PROTO_SCSI;
812198708Smav			PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
813198708Smav		} else {
814198708Smav			if (done_ccb->ccb_h.target_id != 15) {
815198708Smav				xpt_print(path,
816198708Smav				    "Unexpected signature 0x%04x\n", sign);
817195534Sscottl			}
818198708Smav			goto device_fail;
819198708Smav		}
820198708Smav		xpt_release_ccb(done_ccb);
821198708Smav		xpt_schedule(periph, priority);
822249466Smav		goto out;
823198708Smav	}
824198708Smav	case PROBE_IDENTIFY:
825198708Smav	{
826207222Smav		struct ccb_pathinq cpi;
827198708Smav		int16_t *ptr;
828307606Ssephe		int veto = 0;
829195534Sscottl
830203385Smav		ident_buf = &softc->ident_data;
831198708Smav		for (ptr = (int16_t *)ident_buf;
832198708Smav		     ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) {
833198708Smav			*ptr = le16toh(*ptr);
834198708Smav		}
835307606Ssephe
836307606Ssephe		/*
837307606Ssephe		 * Allow others to veto this ATA disk attachment.  This
838307606Ssephe		 * is mainly used by VMs, whose disk controllers may
839307606Ssephe		 * share the disks with the simulated ATA controllers.
840307606Ssephe		 */
841307606Ssephe		EVENTHANDLER_INVOKE(ada_probe_veto, path, ident_buf, &veto);
842307606Ssephe		if (veto) {
843307606Ssephe			goto device_fail;
844307606Ssephe		}
845307606Ssephe
846198708Smav		if (strncmp(ident_buf->model, "FX", 2) &&
847198708Smav		    strncmp(ident_buf->model, "NEC", 3) &&
848198708Smav		    strncmp(ident_buf->model, "Pioneer", 7) &&
849198708Smav		    strncmp(ident_buf->model, "SHARP", 5)) {
850198708Smav			ata_bswap(ident_buf->model, sizeof(ident_buf->model));
851198708Smav			ata_bswap(ident_buf->revision, sizeof(ident_buf->revision));
852198708Smav			ata_bswap(ident_buf->serial, sizeof(ident_buf->serial));
853198708Smav		}
854198708Smav		ata_btrim(ident_buf->model, sizeof(ident_buf->model));
855198708Smav		ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model));
856198708Smav		ata_btrim(ident_buf->revision, sizeof(ident_buf->revision));
857198708Smav		ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision));
858198708Smav		ata_btrim(ident_buf->serial, sizeof(ident_buf->serial));
859198708Smav		ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial));
860203421Smav		/* Device may need spin-up before IDENTIFY become valid. */
861204354Smav		if ((ident_buf->specconf == 0x37c8 ||
862204354Smav		     ident_buf->specconf == 0x738c) &&
863204354Smav		    ((ident_buf->config & ATA_RESP_INCOMPLETE) ||
864204354Smav		     softc->spinup == 0)) {
865203421Smav			PROBE_SET_ACTION(softc, PROBE_SPINUP);
866203421Smav			xpt_release_ccb(done_ccb);
867203421Smav			xpt_schedule(periph, priority);
868249466Smav			goto out;
869203421Smav		}
870203385Smav		ident_buf = &path->device->ident_data;
871198708Smav		if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) {
872198708Smav			/* Check that it is the same device. */
873203385Smav			if (bcmp(softc->ident_data.model, ident_buf->model,
874203385Smav			     sizeof(ident_buf->model)) ||
875203385Smav			    bcmp(softc->ident_data.revision, ident_buf->revision,
876203385Smav			     sizeof(ident_buf->revision)) ||
877203385Smav			    bcmp(softc->ident_data.serial, ident_buf->serial,
878203385Smav			     sizeof(ident_buf->serial))) {
879198708Smav				/* Device changed. */
880198708Smav				xpt_async(AC_LOST_DEVICE, path, NULL);
881207282Smav			} else {
882203385Smav				bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params));
883207282Smav				changed = 0;
884207282Smav			}
885207282Smav		}
886207282Smav		if (changed) {
887203385Smav			bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params));
888195534Sscottl			/* Clean up from previous instance of this device */
889195534Sscottl			if (path->device->serial_num != NULL) {
890195534Sscottl				free(path->device->serial_num, M_CAMXPT);
891195534Sscottl				path->device->serial_num = NULL;
892195534Sscottl				path->device->serial_num_len = 0;
893195534Sscottl			}
894235897Smav			if (path->device->device_id != NULL) {
895235897Smav				free(path->device->device_id, M_CAMXPT);
896235897Smav				path->device->device_id = NULL;
897235897Smav				path->device->device_id_len = 0;
898235897Smav			}
899195534Sscottl			path->device->serial_num =
900195534Sscottl				(u_int8_t *)malloc((sizeof(ident_buf->serial) + 1),
901198708Smav					   M_CAMXPT, M_NOWAIT);
902195534Sscottl			if (path->device->serial_num != NULL) {
903195534Sscottl				bcopy(ident_buf->serial,
904195534Sscottl				      path->device->serial_num,
905195534Sscottl				      sizeof(ident_buf->serial));
906195534Sscottl				path->device->serial_num[sizeof(ident_buf->serial)]
907195534Sscottl				    = '\0';
908195534Sscottl				path->device->serial_num_len =
909195534Sscottl				    strlen(path->device->serial_num);
910195534Sscottl			}
911235897Smav			if (ident_buf->enabled.extension &
912235897Smav			    ATA_SUPPORT_64BITWWN) {
913235897Smav				path->device->device_id =
914235897Smav				    malloc(16, M_CAMXPT, M_NOWAIT);
915235897Smav				if (path->device->device_id != NULL) {
916235897Smav					path->device->device_id_len = 16;
917235897Smav					bcopy(&fake_device_id_hdr,
918235897Smav					    path->device->device_id, 8);
919250301Smav					bcopy(ident_buf->wwn,
920250301Smav					    path->device->device_id + 8, 8);
921250301Smav					ata_bswap(path->device->device_id + 8, 8);
922235897Smav				}
923235897Smav			}
924195534Sscottl
925198331Smav			path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID;
926236393Smav			xpt_async(AC_GETDEV_CHANGED, path, NULL);
927195534Sscottl		}
928199178Smav		if (ident_buf->satacapabilities & ATA_SUPPORT_NCQ) {
929236234Smav			path->device->mintags = 2;
930236234Smav			path->device->maxtags =
931199178Smav			    ATA_QUEUE_LEN(ident_buf->queue) + 1;
932199178Smav		}
933199178Smav		ata_find_quirk(path->device);
934199263Smav		if (path->device->mintags != 0 &&
935199263Smav		    path->bus->sim->max_tagged_dev_openings != 0) {
936207222Smav			/* Check if the SIM does not want queued commands. */
937207222Smav			bzero(&cpi, sizeof(cpi));
938207222Smav			xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE);
939207222Smav			cpi.ccb_h.func_code = XPT_PATH_INQ;
940207222Smav			xpt_action((union ccb *)&cpi);
941207222Smav			if (cpi.ccb_h.status == CAM_REQ_CMP &&
942207222Smav			    (cpi.hba_inquiry & PI_TAG_ABLE)) {
943207222Smav				/* Report SIM which tags are allowed. */
944207222Smav				bzero(&cts, sizeof(cts));
945207222Smav				xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
946207222Smav				cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
947207222Smav				cts.type = CTS_TYPE_CURRENT_SETTINGS;
948207222Smav				cts.xport_specific.sata.tags = path->device->maxtags;
949207222Smav				cts.xport_specific.sata.valid = CTS_SATA_VALID_TAGS;
950207222Smav				xpt_action((union ccb *)&cts);
951207222Smav			}
952199178Smav		}
953236666Smav		ata_device_transport(path);
954236437Smav		if (changed)
955236437Smav			proberequestdefaultnegotiation(periph);
956198708Smav		PROBE_SET_ACTION(softc, PROBE_SETMODE);
957195534Sscottl		xpt_release_ccb(done_ccb);
958198708Smav		xpt_schedule(periph, priority);
959249466Smav		goto out;
960195534Sscottl	}
961203421Smav	case PROBE_SPINUP:
962203421Smav		if (bootverbose)
963203421Smav			xpt_print(path, "Spin-up done\n");
964203421Smav		softc->spinup = 1;
965203421Smav		PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
966203421Smav		xpt_release_ccb(done_ccb);
967203421Smav		xpt_schedule(periph, priority);
968249466Smav		goto out;
969195534Sscottl	case PROBE_SETMODE:
970207499Smav		/* Set supported bits. */
971207499Smav		bzero(&cts, sizeof(cts));
972207499Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
973207499Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
974207499Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
975207499Smav		xpt_action((union ccb *)&cts);
976249199Smarius		if (path->device->transport == XPORT_SATA &&
977249199Smarius		    cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS)
978207499Smav			caps = cts.xport_specific.sata.caps & CTS_SATA_CAPS_H;
979249199Smarius		else if (path->device->transport == XPORT_ATA &&
980249199Smarius		    cts.xport_specific.ata.valid & CTS_ATA_VALID_CAPS)
981249199Smarius			caps = cts.xport_specific.ata.caps & CTS_ATA_CAPS_H;
982207499Smav		else
983207499Smav			caps = 0;
984249199Smarius		if (path->device->transport == XPORT_SATA &&
985249199Smarius		    ident_buf->satacapabilities != 0xffff) {
986207499Smav			if (ident_buf->satacapabilities & ATA_SUPPORT_IFPWRMNGTRCV)
987207499Smav				caps |= CTS_SATA_CAPS_D_PMREQ;
988207499Smav			if (ident_buf->satacapabilities & ATA_SUPPORT_HAPST)
989207499Smav				caps |= CTS_SATA_CAPS_D_APST;
990207499Smav		}
991207499Smav		/* Mask unwanted bits. */
992207499Smav		bzero(&cts, sizeof(cts));
993207499Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
994207499Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
995207499Smav		cts.type = CTS_TYPE_USER_SETTINGS;
996207499Smav		xpt_action((union ccb *)&cts);
997249199Smarius		if (path->device->transport == XPORT_SATA &&
998249199Smarius		    cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS)
999207499Smav			caps &= cts.xport_specific.sata.caps;
1000249199Smarius		else if (path->device->transport == XPORT_ATA &&
1001249199Smarius		    cts.xport_specific.ata.valid & CTS_ATA_VALID_CAPS)
1002249199Smarius			caps &= cts.xport_specific.ata.caps;
1003215454Smav		else
1004215454Smav			caps = 0;
1005249199Smarius		/*
1006249199Smarius		 * Remember what transport thinks about 48-bit DMA.  If
1007249199Smarius		 * capability information is not provided or transport is
1008249199Smarius		 * SATA, we take support for granted.
1009249199Smarius		 */
1010249199Smarius		if (!(path->device->inq_flags & SID_DMA) ||
1011249199Smarius		    (path->device->transport == XPORT_ATA &&
1012249199Smarius		    (cts.xport_specific.ata.valid & CTS_ATA_VALID_CAPS) &&
1013249199Smarius		    !(caps & CTS_ATA_CAPS_H_DMA48)))
1014249199Smarius			path->device->inq_flags &= ~SID_DMA48;
1015249199Smarius		else
1016249199Smarius			path->device->inq_flags |= SID_DMA48;
1017207499Smav		/* Store result to SIM. */
1018207499Smav		bzero(&cts, sizeof(cts));
1019207499Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
1020207499Smav		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
1021207499Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
1022249199Smarius		if (path->device->transport == XPORT_SATA) {
1023249199Smarius			cts.xport_specific.sata.caps = caps;
1024249199Smarius			cts.xport_specific.sata.valid = CTS_SATA_VALID_CAPS;
1025249199Smarius		} else {
1026249199Smarius			cts.xport_specific.ata.caps = caps;
1027249199Smarius			cts.xport_specific.ata.valid = CTS_ATA_VALID_CAPS;
1028249199Smarius		}
1029207499Smav		xpt_action((union ccb *)&cts);
1030207499Smav		softc->caps = caps;
1031249199Smarius		if (path->device->transport != XPORT_SATA)
1032249199Smarius			goto notsata;
1033217874Smav		if ((ident_buf->satasupport & ATA_SUPPORT_IFPWRMNGT) &&
1034217874Smav		    (!(softc->caps & CTS_SATA_CAPS_H_PMREQ)) !=
1035217874Smav		    (!(ident_buf->sataenabled & ATA_SUPPORT_IFPWRMNGT))) {
1036207499Smav			PROBE_SET_ACTION(softc, PROBE_SETPM);
1037207499Smav			xpt_release_ccb(done_ccb);
1038207499Smav			xpt_schedule(periph, priority);
1039249466Smav			goto out;
1040207499Smav		}
1041207499Smav		/* FALLTHROUGH */
1042207499Smav	case PROBE_SETPM:
1043207499Smav		if (ident_buf->satacapabilities != 0xffff &&
1044217874Smav		    (ident_buf->satacapabilities & ATA_SUPPORT_DAPST) &&
1045217874Smav		    (!(softc->caps & CTS_SATA_CAPS_H_APST)) !=
1046217874Smav		    (!(ident_buf->sataenabled & ATA_ENABLED_DAPST))) {
1047207499Smav			PROBE_SET_ACTION(softc, PROBE_SETAPST);
1048207499Smav			xpt_release_ccb(done_ccb);
1049207499Smav			xpt_schedule(periph, priority);
1050249466Smav			goto out;
1051207499Smav		}
1052207499Smav		/* FALLTHROUGH */
1053207499Smav	case PROBE_SETAPST:
1054217874Smav		if ((ident_buf->satasupport & ATA_SUPPORT_AUTOACTIVATE) &&
1055217874Smav		    (!(softc->caps & CTS_SATA_CAPS_H_DMAAA)) !=
1056217874Smav		    (!(ident_buf->sataenabled & ATA_SUPPORT_AUTOACTIVATE))) {
1057207499Smav			PROBE_SET_ACTION(softc, PROBE_SETDMAAA);
1058207499Smav			xpt_release_ccb(done_ccb);
1059207499Smav			xpt_schedule(periph, priority);
1060249466Smav			goto out;
1061207499Smav		}
1062207499Smav		/* FALLTHROUGH */
1063207499Smav	case PROBE_SETDMAAA:
1064270327Simp		if (path->device->protocol != PROTO_ATA &&
1065270327Simp		    (ident_buf->satasupport & ATA_SUPPORT_ASYNCNOTIF) &&
1066220602Smav		    (!(softc->caps & CTS_SATA_CAPS_H_AN)) !=
1067220602Smav		    (!(ident_buf->sataenabled & ATA_SUPPORT_ASYNCNOTIF))) {
1068220602Smav			PROBE_SET_ACTION(softc, PROBE_SETAN);
1069220602Smav			xpt_release_ccb(done_ccb);
1070220602Smav			xpt_schedule(periph, priority);
1071249466Smav			goto out;
1072220602Smav		}
1073220602Smav		/* FALLTHROUGH */
1074220602Smav	case PROBE_SETAN:
1075207499Smavnotsata:
1076198708Smav		if (path->device->protocol == PROTO_ATA) {
1077198708Smav			PROBE_SET_ACTION(softc, PROBE_SET_MULTI);
1078198708Smav		} else {
1079198708Smav			PROBE_SET_ACTION(softc, PROBE_INQUIRY);
1080195534Sscottl		}
1081198708Smav		xpt_release_ccb(done_ccb);
1082198708Smav		xpt_schedule(periph, priority);
1083249466Smav		goto out;
1084198708Smav	case PROBE_SET_MULTI:
1085198708Smav		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
1086198708Smav			path->device->flags &= ~CAM_DEV_UNCONFIGURED;
1087198748Smav			xpt_acquire_device(path->device);
1088198708Smav			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
1089198708Smav			xpt_action(done_ccb);
1090249466Smav			xpt_async(AC_FOUND_DEVICE, path, done_ccb);
1091198708Smav		}
1092236613Smav		PROBE_SET_ACTION(softc, PROBE_DONE);
1093198708Smav		break;
1094195534Sscottl	case PROBE_INQUIRY:
1095195534Sscottl	case PROBE_FULL_INQUIRY:
1096195534Sscottl	{
1097198708Smav		u_int8_t periph_qual, len;
1098195534Sscottl
1099198708Smav		path->device->flags |= CAM_DEV_INQUIRY_DATA_VALID;
1100195534Sscottl
1101198708Smav		periph_qual = SID_QUAL(inq_buf);
1102195534Sscottl
1103287289Smav		if (periph_qual != SID_QUAL_LU_CONNECTED &&
1104287289Smav		    periph_qual != SID_QUAL_LU_OFFLINE)
1105198708Smav			break;
1106195534Sscottl
1107198708Smav		/*
1108198708Smav		 * We conservatively request only
1109198708Smav		 * SHORT_INQUIRY_LEN bytes of inquiry
1110198708Smav		 * information during our first try
1111198708Smav		 * at sending an INQUIRY. If the device
1112198708Smav		 * has more information to give,
1113198708Smav		 * perform a second request specifying
1114198708Smav		 * the amount of information the device
1115198708Smav		 * is willing to give.
1116198708Smav		 */
1117198708Smav		len = inq_buf->additional_length
1118198708Smav		    + offsetof(struct scsi_inquiry_data, additional_length) + 1;
1119198708Smav		if (softc->action == PROBE_INQUIRY
1120198708Smav		    && len > SHORT_INQUIRY_LENGTH) {
1121198708Smav			PROBE_SET_ACTION(softc, PROBE_FULL_INQUIRY);
1122198708Smav			xpt_release_ccb(done_ccb);
1123198708Smav			xpt_schedule(periph, priority);
1124249466Smav			goto out;
1125195534Sscottl		}
1126198708Smav
1127198708Smav		ata_device_transport(path);
1128198708Smav		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
1129198708Smav			path->device->flags &= ~CAM_DEV_UNCONFIGURED;
1130198748Smav			xpt_acquire_device(path->device);
1131198708Smav			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
1132198708Smav			xpt_action(done_ccb);
1133249466Smav			xpt_async(AC_FOUND_DEVICE, path, done_ccb);
1134198708Smav		}
1135236613Smav		PROBE_SET_ACTION(softc, PROBE_DONE);
1136198708Smav		break;
1137195534Sscottl	}
1138195534Sscottl	case PROBE_PM_PID:
1139198708Smav		if ((path->device->flags & CAM_DEV_IDENTIFY_DATA_VALID) == 0)
1140198708Smav			bzero(ident_buf, sizeof(*ident_buf));
1141198708Smav		softc->pm_pid = (done_ccb->ataio.res.lba_high << 24) +
1142198708Smav		    (done_ccb->ataio.res.lba_mid << 16) +
1143198708Smav		    (done_ccb->ataio.res.lba_low << 8) +
1144198708Smav		    done_ccb->ataio.res.sector_count;
1145198708Smav		((uint32_t *)ident_buf)[0] = softc->pm_pid;
1146198708Smav		snprintf(ident_buf->model, sizeof(ident_buf->model),
1147198708Smav		    "Port Multiplier %08x", softc->pm_pid);
1148198708Smav		PROBE_SET_ACTION(softc, PROBE_PM_PRV);
1149198708Smav		xpt_release_ccb(done_ccb);
1150198708Smav		xpt_schedule(periph, priority);
1151249466Smav		goto out;
1152195534Sscottl	case PROBE_PM_PRV:
1153198708Smav		softc->pm_prv = (done_ccb->ataio.res.lba_high << 24) +
1154198708Smav		    (done_ccb->ataio.res.lba_mid << 16) +
1155198708Smav		    (done_ccb->ataio.res.lba_low << 8) +
1156198708Smav		    done_ccb->ataio.res.sector_count;
1157198708Smav		((uint32_t *)ident_buf)[1] = softc->pm_prv;
1158198708Smav		snprintf(ident_buf->revision, sizeof(ident_buf->revision),
1159198708Smav		    "%04x", softc->pm_prv);
1160198708Smav		path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID;
1161236666Smav		ata_device_transport(path);
1162236666Smav		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED)
1163236666Smav			proberequestdefaultnegotiation(periph);
1164207499Smav		/* Set supported bits. */
1165207499Smav		bzero(&cts, sizeof(cts));
1166207499Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
1167207499Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
1168207499Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
1169207499Smav		xpt_action((union ccb *)&cts);
1170207499Smav		if (cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS)
1171207499Smav			caps = cts.xport_specific.sata.caps & CTS_SATA_CAPS_H;
1172207499Smav		else
1173207499Smav			caps = 0;
1174207499Smav		/* All PMPs must support PM requests. */
1175207499Smav		caps |= CTS_SATA_CAPS_D_PMREQ;
1176207499Smav		/* Mask unwanted bits. */
1177207499Smav		bzero(&cts, sizeof(cts));
1178207499Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
1179207499Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
1180207499Smav		cts.type = CTS_TYPE_USER_SETTINGS;
1181207499Smav		xpt_action((union ccb *)&cts);
1182207499Smav		if (cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS)
1183207499Smav			caps &= cts.xport_specific.sata.caps;
1184215454Smav		else
1185215454Smav			caps = 0;
1186249199Smarius		/* Remember what transport thinks about AEN. */
1187270327Simp		if ((caps & CTS_SATA_CAPS_H_AN) && path->device->protocol != PROTO_ATA)
1188249199Smarius			path->device->inq_flags |= SID_AEN;
1189249199Smarius		else
1190249199Smarius			path->device->inq_flags &= ~SID_AEN;
1191207499Smav		/* Store result to SIM. */
1192207499Smav		bzero(&cts, sizeof(cts));
1193207499Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
1194207499Smav		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
1195207499Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
1196207499Smav		cts.xport_specific.sata.caps = caps;
1197207499Smav		cts.xport_specific.sata.valid = CTS_SATA_VALID_CAPS;
1198207499Smav		xpt_action((union ccb *)&cts);
1199207499Smav		softc->caps = caps;
1200238886Smav		xpt_async(AC_GETDEV_CHANGED, path, NULL);
1201198708Smav		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
1202198708Smav			path->device->flags &= ~CAM_DEV_UNCONFIGURED;
1203198748Smav			xpt_acquire_device(path->device);
1204198708Smav			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
1205198708Smav			xpt_action(done_ccb);
1206249466Smav			xpt_async(AC_FOUND_DEVICE, path, done_ccb);
1207198708Smav		} else {
1208198708Smav			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
1209198708Smav			xpt_action(done_ccb);
1210249466Smav			xpt_async(AC_SCSI_AEN, path, done_ccb);
1211195534Sscottl		}
1212236613Smav		PROBE_SET_ACTION(softc, PROBE_DONE);
1213198708Smav		break;
1214235897Smav	case PROBE_IDENTIFY_SES:
1215235897Smav	case PROBE_IDENTIFY_SAFTE:
1216235897Smav		if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) {
1217235897Smav			/* Check that it is the same device. */
1218235897Smav			if (bcmp(&softc->ident_data, ident_buf, 53)) {
1219235897Smav				/* Device changed. */
1220235897Smav				xpt_async(AC_LOST_DEVICE, path, NULL);
1221235897Smav			} else {
1222235897Smav				bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params));
1223235897Smav				changed = 0;
1224235897Smav			}
1225235897Smav		}
1226235897Smav		if (changed) {
1227235897Smav			bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params));
1228235897Smav			/* Clean up from previous instance of this device */
1229235897Smav			if (path->device->device_id != NULL) {
1230235897Smav				free(path->device->device_id, M_CAMXPT);
1231235897Smav				path->device->device_id = NULL;
1232235897Smav				path->device->device_id_len = 0;
1233235897Smav			}
1234235897Smav			path->device->device_id =
1235235897Smav			    malloc(16, M_CAMXPT, M_NOWAIT);
1236235897Smav			if (path->device->device_id != NULL) {
1237235897Smav				path->device->device_id_len = 16;
1238235897Smav				bcopy(&fake_device_id_hdr,
1239235897Smav				    path->device->device_id, 8);
1240235897Smav				bcopy(((uint8_t*)ident_buf) + 2,
1241235897Smav				    path->device->device_id + 8, 8);
1242235897Smav			}
1243235897Smav
1244235897Smav			path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID;
1245235897Smav		}
1246236666Smav		ata_device_transport(path);
1247236666Smav		if (changed)
1248236666Smav			proberequestdefaultnegotiation(periph);
1249235897Smav
1250235897Smav		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
1251235897Smav			path->device->flags &= ~CAM_DEV_UNCONFIGURED;
1252235897Smav			xpt_acquire_device(path->device);
1253235897Smav			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
1254235897Smav			xpt_action(done_ccb);
1255249466Smav			xpt_async(AC_FOUND_DEVICE, path, done_ccb);
1256235897Smav		}
1257236613Smav		PROBE_SET_ACTION(softc, PROBE_DONE);
1258235897Smav		break;
1259195534Sscottl	default:
1260236613Smav		panic("probedone: invalid action state 0x%x\n", softc->action);
1261195534Sscottl	}
1262198708Smavdone:
1263203108Smav	if (softc->restart) {
1264203108Smav		softc->restart = 0;
1265203108Smav		xpt_release_ccb(done_ccb);
1266195534Sscottl		probeschedule(periph);
1267249466Smav		goto out;
1268195534Sscottl	}
1269203108Smav	xpt_release_ccb(done_ccb);
1270236613Smav	CAM_DEBUG(periph->path, CAM_DEBUG_PROBE, ("Probe completed\n"));
1271203108Smav	while ((done_ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs))) {
1272203108Smav		TAILQ_REMOVE(&softc->request_ccbs,
1273203108Smav		    &done_ccb->ccb_h, periph_links.tqe);
1274203108Smav		done_ccb->ccb_h.status = found ? CAM_REQ_CMP : CAM_REQ_CMP_ERR;
1275203108Smav		xpt_done(done_ccb);
1276203108Smav	}
1277249466Smav	/* Drop freeze taken due to CAM_DEV_QFREEZE flag set. */
1278249466Smav	cam_release_devq(path, 0, 0, 0, FALSE);
1279236228Smav	cam_periph_invalidate(periph);
1280203108Smav	cam_periph_release_locked(periph);
1281195534Sscottl}
1282195534Sscottl
1283195534Sscottlstatic void
1284195534Sscottlprobecleanup(struct cam_periph *periph)
1285195534Sscottl{
1286195534Sscottl	free(periph->softc, M_CAMXPT);
1287195534Sscottl}
1288195534Sscottl
1289195534Sscottlstatic void
1290199178Smavata_find_quirk(struct cam_ed *device)
1291195534Sscottl{
1292199178Smav	struct ata_quirk_entry *quirk;
1293195534Sscottl	caddr_t	match;
1294195534Sscottl
1295199178Smav	match = cam_quirkmatch((caddr_t)&device->ident_data,
1296199178Smav			       (caddr_t)ata_quirk_table,
1297298411Spfg			       nitems(ata_quirk_table),
1298199178Smav			       sizeof(*ata_quirk_table), ata_identify_match);
1299195534Sscottl
1300195534Sscottl	if (match == NULL)
1301195534Sscottl		panic("xpt_find_quirk: device didn't match wildcard entry!!");
1302195534Sscottl
1303199178Smav	quirk = (struct ata_quirk_entry *)match;
1304195534Sscottl	device->quirk = quirk;
1305236234Smav	if (quirk->quirks & CAM_QUIRK_MAXTAGS) {
1306236234Smav		device->mintags = quirk->mintags;
1307236234Smav		device->maxtags = quirk->maxtags;
1308236234Smav	}
1309195534Sscottl}
1310195534Sscottl
1311195534Sscottltypedef struct {
1312195534Sscottl	union	ccb *request_ccb;
1313195534Sscottl	struct 	ccb_pathinq *cpi;
1314195534Sscottl	int	counter;
1315195534Sscottl} ata_scan_bus_info;
1316195534Sscottl
1317195534Sscottl/*
1318195534Sscottl * To start a scan, request_ccb is an XPT_SCAN_BUS ccb.
1319195534Sscottl * As the scan progresses, xpt_scan_bus is used as the
1320195534Sscottl * callback on completion function.
1321195534Sscottl */
1322195534Sscottlstatic void
1323195534Sscottlata_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
1324195534Sscottl{
1325195534Sscottl	struct	cam_path *path;
1326195534Sscottl	ata_scan_bus_info *scan_info;
1327203108Smav	union	ccb *work_ccb, *reset_ccb;
1328256843Smav	struct mtx *mtx;
1329195534Sscottl	cam_status status;
1330195534Sscottl
1331195534Sscottl	CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE,
1332195534Sscottl		  ("xpt_scan_bus\n"));
1333195534Sscottl	switch (request_ccb->ccb_h.func_code) {
1334195534Sscottl	case XPT_SCAN_BUS:
1335208582Smjacob	case XPT_SCAN_TGT:
1336195534Sscottl		/* Find out the characteristics of the bus */
1337195534Sscottl		work_ccb = xpt_alloc_ccb_nowait();
1338195534Sscottl		if (work_ccb == NULL) {
1339195534Sscottl			request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1340195534Sscottl			xpt_done(request_ccb);
1341195534Sscottl			return;
1342195534Sscottl		}
1343195534Sscottl		xpt_setup_ccb(&work_ccb->ccb_h, request_ccb->ccb_h.path,
1344195534Sscottl			      request_ccb->ccb_h.pinfo.priority);
1345195534Sscottl		work_ccb->ccb_h.func_code = XPT_PATH_INQ;
1346195534Sscottl		xpt_action(work_ccb);
1347195534Sscottl		if (work_ccb->ccb_h.status != CAM_REQ_CMP) {
1348195534Sscottl			request_ccb->ccb_h.status = work_ccb->ccb_h.status;
1349195534Sscottl			xpt_free_ccb(work_ccb);
1350195534Sscottl			xpt_done(request_ccb);
1351195534Sscottl			return;
1352195534Sscottl		}
1353195534Sscottl
1354203108Smav		/* We may need to reset bus first, if we haven't done it yet. */
1355203108Smav		if ((work_ccb->cpi.hba_inquiry &
1356203108Smav		    (PI_WIDE_32|PI_WIDE_16|PI_SDTR_ABLE)) &&
1357203108Smav		    !(work_ccb->cpi.hba_misc & PIM_NOBUSRESET) &&
1358203108Smav		    !timevalisset(&request_ccb->ccb_h.path->bus->last_reset)) {
1359203108Smav			reset_ccb = xpt_alloc_ccb_nowait();
1360208823Smav			if (reset_ccb == NULL) {
1361208823Smav				request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1362208823Smav				xpt_free_ccb(work_ccb);
1363208823Smav				xpt_done(request_ccb);
1364208823Smav				return;
1365208823Smav			}
1366203108Smav			xpt_setup_ccb(&reset_ccb->ccb_h, request_ccb->ccb_h.path,
1367203108Smav			      CAM_PRIORITY_NONE);
1368203108Smav			reset_ccb->ccb_h.func_code = XPT_RESET_BUS;
1369203108Smav			xpt_action(reset_ccb);
1370203108Smav			if (reset_ccb->ccb_h.status != CAM_REQ_CMP) {
1371203108Smav				request_ccb->ccb_h.status = reset_ccb->ccb_h.status;
1372203108Smav				xpt_free_ccb(reset_ccb);
1373203108Smav				xpt_free_ccb(work_ccb);
1374203108Smav				xpt_done(request_ccb);
1375203108Smav				return;
1376203108Smav			}
1377203108Smav			xpt_free_ccb(reset_ccb);
1378203108Smav		}
1379203108Smav
1380195534Sscottl		/* Save some state for use while we probe for devices */
1381195534Sscottl		scan_info = (ata_scan_bus_info *)
1382195534Sscottl		    malloc(sizeof(ata_scan_bus_info), M_CAMXPT, M_NOWAIT);
1383195534Sscottl		if (scan_info == NULL) {
1384195534Sscottl			request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1385208823Smav			xpt_free_ccb(work_ccb);
1386195534Sscottl			xpt_done(request_ccb);
1387195534Sscottl			return;
1388195534Sscottl		}
1389195534Sscottl		scan_info->request_ccb = request_ccb;
1390195534Sscottl		scan_info->cpi = &work_ccb->cpi;
1391195534Sscottl		/* If PM supported, probe it first. */
1392195534Sscottl		if (scan_info->cpi->hba_inquiry & PI_SATAPM)
1393201990Smav			scan_info->counter = scan_info->cpi->max_target;
1394201990Smav		else
1395201990Smav			scan_info->counter = 0;
1396195534Sscottl
1397195534Sscottl		work_ccb = xpt_alloc_ccb_nowait();
1398195534Sscottl		if (work_ccb == NULL) {
1399195534Sscottl			free(scan_info, M_CAMXPT);
1400195534Sscottl			request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1401195534Sscottl			xpt_done(request_ccb);
1402195534Sscottl			break;
1403195534Sscottl		}
1404256843Smav		mtx = xpt_path_mtx(scan_info->request_ccb->ccb_h.path);
1405195534Sscottl		goto scan_next;
1406195534Sscottl	case XPT_SCAN_LUN:
1407195534Sscottl		work_ccb = request_ccb;
1408195534Sscottl		/* Reuse the same CCB to query if a device was really found */
1409195534Sscottl		scan_info = (ata_scan_bus_info *)work_ccb->ccb_h.ppriv_ptr0;
1410256843Smav		mtx = xpt_path_mtx(scan_info->request_ccb->ccb_h.path);
1411256843Smav		mtx_lock(mtx);
1412198389Smav		/* If there is PMP... */
1413201990Smav		if ((scan_info->cpi->hba_inquiry & PI_SATAPM) &&
1414201990Smav		    (scan_info->counter == scan_info->cpi->max_target)) {
1415203108Smav			if (work_ccb->ccb_h.status == CAM_REQ_CMP) {
1416207428Smav				/* everything else will be probed by it */
1417207428Smav				/* Free the current request path- we're done with it. */
1418207428Smav				xpt_free_path(work_ccb->ccb_h.path);
1419201990Smav				goto done;
1420195534Sscottl			} else {
1421195534Sscottl				struct ccb_trans_settings cts;
1422195534Sscottl
1423195534Sscottl				/* Report SIM that PM is absent. */
1424195534Sscottl				bzero(&cts, sizeof(cts));
1425195534Sscottl				xpt_setup_ccb(&cts.ccb_h,
1426207428Smav				    work_ccb->ccb_h.path, CAM_PRIORITY_NONE);
1427195534Sscottl				cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
1428195534Sscottl				cts.type = CTS_TYPE_CURRENT_SETTINGS;
1429195665Smav				cts.xport_specific.sata.pm_present = 0;
1430195534Sscottl				cts.xport_specific.sata.valid = CTS_SATA_VALID_PM;
1431195534Sscottl				xpt_action((union ccb *)&cts);
1432195534Sscottl			}
1433195534Sscottl		}
1434207428Smav		/* Free the current request path- we're done with it. */
1435207428Smav		xpt_free_path(work_ccb->ccb_h.path);
1436201990Smav		if (scan_info->counter ==
1437201990Smav		    ((scan_info->cpi->hba_inquiry & PI_SATAPM) ?
1438201990Smav		    0 : scan_info->cpi->max_target)) {
1439201990Smavdone:
1440256843Smav			mtx_unlock(mtx);
1441195534Sscottl			xpt_free_ccb(work_ccb);
1442195534Sscottl			xpt_free_ccb((union ccb *)scan_info->cpi);
1443195534Sscottl			request_ccb = scan_info->request_ccb;
1444195534Sscottl			free(scan_info, M_CAMXPT);
1445195534Sscottl			request_ccb->ccb_h.status = CAM_REQ_CMP;
1446195534Sscottl			xpt_done(request_ccb);
1447195534Sscottl			break;
1448195534Sscottl		}
1449201990Smav		/* Take next device. Wrap from max (PMP) to 0. */
1450201990Smav		scan_info->counter = (scan_info->counter + 1 ) %
1451201990Smav		    (scan_info->cpi->max_target + 1);
1452195534Sscottlscan_next:
1453249468Smav		status = xpt_create_path(&path, NULL,
1454195534Sscottl		    scan_info->request_ccb->ccb_h.path_id,
1455195534Sscottl		    scan_info->counter, 0);
1456195534Sscottl		if (status != CAM_REQ_CMP) {
1457256843Smav			if (request_ccb->ccb_h.func_code == XPT_SCAN_LUN)
1458256843Smav				mtx_unlock(mtx);
1459195534Sscottl			printf("xpt_scan_bus: xpt_create_path failed"
1460195534Sscottl			    " with status %#x, bus scan halted\n",
1461195534Sscottl			    status);
1462195534Sscottl			xpt_free_ccb(work_ccb);
1463195534Sscottl			xpt_free_ccb((union ccb *)scan_info->cpi);
1464195534Sscottl			request_ccb = scan_info->request_ccb;
1465195534Sscottl			free(scan_info, M_CAMXPT);
1466195534Sscottl			request_ccb->ccb_h.status = status;
1467195534Sscottl			xpt_done(request_ccb);
1468195534Sscottl			break;
1469195534Sscottl		}
1470195534Sscottl		xpt_setup_ccb(&work_ccb->ccb_h, path,
1471195534Sscottl		    scan_info->request_ccb->ccb_h.pinfo.priority);
1472195534Sscottl		work_ccb->ccb_h.func_code = XPT_SCAN_LUN;
1473195534Sscottl		work_ccb->ccb_h.cbfcnp = ata_scan_bus;
1474256843Smav		work_ccb->ccb_h.flags |= CAM_UNLOCKED;
1475195534Sscottl		work_ccb->ccb_h.ppriv_ptr0 = scan_info;
1476195534Sscottl		work_ccb->crcn.flags = scan_info->request_ccb->crcn.flags;
1477256843Smav		mtx_unlock(mtx);
1478256843Smav		if (request_ccb->ccb_h.func_code == XPT_SCAN_LUN)
1479256843Smav			mtx = NULL;
1480195534Sscottl		xpt_action(work_ccb);
1481256843Smav		if (mtx != NULL)
1482256843Smav			mtx_lock(mtx);
1483195534Sscottl		break;
1484195534Sscottl	default:
1485195534Sscottl		break;
1486195534Sscottl	}
1487195534Sscottl}
1488195534Sscottl
1489195534Sscottlstatic void
1490195534Sscottlata_scan_lun(struct cam_periph *periph, struct cam_path *path,
1491195534Sscottl	     cam_flags flags, union ccb *request_ccb)
1492195534Sscottl{
1493195534Sscottl	struct ccb_pathinq cpi;
1494195534Sscottl	cam_status status;
1495195534Sscottl	struct cam_path *new_path;
1496195534Sscottl	struct cam_periph *old_periph;
1497256843Smav	int lock;
1498195534Sscottl
1499203108Smav	CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_scan_lun\n"));
1500195534Sscottl
1501203108Smav	xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE);
1502195534Sscottl	cpi.ccb_h.func_code = XPT_PATH_INQ;
1503195534Sscottl	xpt_action((union ccb *)&cpi);
1504195534Sscottl
1505195534Sscottl	if (cpi.ccb_h.status != CAM_REQ_CMP) {
1506195534Sscottl		if (request_ccb != NULL) {
1507195534Sscottl			request_ccb->ccb_h.status = cpi.ccb_h.status;
1508195534Sscottl			xpt_done(request_ccb);
1509195534Sscottl		}
1510195534Sscottl		return;
1511195534Sscottl	}
1512195534Sscottl
1513195534Sscottl	if (request_ccb == NULL) {
1514241455Smav		request_ccb = xpt_alloc_ccb_nowait();
1515195534Sscottl		if (request_ccb == NULL) {
1516195534Sscottl			xpt_print(path, "xpt_scan_lun: can't allocate CCB, "
1517195534Sscottl			    "can't continue\n");
1518195534Sscottl			return;
1519195534Sscottl		}
1520249468Smav		status = xpt_create_path(&new_path, NULL,
1521195534Sscottl					  path->bus->path_id,
1522195534Sscottl					  path->target->target_id,
1523195534Sscottl					  path->device->lun_id);
1524195534Sscottl		if (status != CAM_REQ_CMP) {
1525241455Smav			xpt_print(path, "xpt_scan_lun: can't create path, "
1526195534Sscottl			    "can't continue\n");
1527241455Smav			xpt_free_ccb(request_ccb);
1528195534Sscottl			return;
1529195534Sscottl		}
1530203108Smav		xpt_setup_ccb(&request_ccb->ccb_h, new_path, CAM_PRIORITY_XPT);
1531195534Sscottl		request_ccb->ccb_h.cbfcnp = xptscandone;
1532256843Smav		request_ccb->ccb_h.flags |= CAM_UNLOCKED;
1533195534Sscottl		request_ccb->ccb_h.func_code = XPT_SCAN_LUN;
1534195534Sscottl		request_ccb->crcn.flags = flags;
1535195534Sscottl	}
1536195534Sscottl
1537256843Smav	lock = (xpt_path_owned(path) == 0);
1538256843Smav	if (lock)
1539256843Smav		xpt_path_lock(path);
1540195653Smav	if ((old_periph = cam_periph_find(path, "aprobe")) != NULL) {
1541236228Smav		if ((old_periph->flags & CAM_PERIPH_INVALID) == 0) {
1542236228Smav			probe_softc *softc;
1543195534Sscottl
1544236228Smav			softc = (probe_softc *)old_periph->softc;
1545236228Smav			TAILQ_INSERT_TAIL(&softc->request_ccbs,
1546236228Smav				&request_ccb->ccb_h, periph_links.tqe);
1547236228Smav			softc->restart = 1;
1548236228Smav		} else {
1549236228Smav			request_ccb->ccb_h.status = CAM_REQ_CMP_ERR;
1550236228Smav			xpt_done(request_ccb);
1551236228Smav		}
1552195534Sscottl	} else {
1553195534Sscottl		status = cam_periph_alloc(proberegister, NULL, probecleanup,
1554195653Smav					  probestart, "aprobe",
1555195534Sscottl					  CAM_PERIPH_BIO,
1556195534Sscottl					  request_ccb->ccb_h.path, NULL, 0,
1557195534Sscottl					  request_ccb);
1558195534Sscottl
1559195534Sscottl		if (status != CAM_REQ_CMP) {
1560195534Sscottl			xpt_print(path, "xpt_scan_lun: cam_alloc_periph "
1561195534Sscottl			    "returned an error, can't continue probe\n");
1562195534Sscottl			request_ccb->ccb_h.status = status;
1563195534Sscottl			xpt_done(request_ccb);
1564195534Sscottl		}
1565195534Sscottl	}
1566256843Smav	if (lock)
1567256843Smav		xpt_path_unlock(path);
1568195534Sscottl}
1569195534Sscottl
1570195534Sscottlstatic void
1571195534Sscottlxptscandone(struct cam_periph *periph, union ccb *done_ccb)
1572195534Sscottl{
1573241455Smav
1574241455Smav	xpt_free_path(done_ccb->ccb_h.path);
1575241455Smav	xpt_free_ccb(done_ccb);
1576195534Sscottl}
1577195534Sscottl
1578195534Sscottlstatic struct cam_ed *
1579195534Sscottlata_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id)
1580195534Sscottl{
1581199178Smav	struct ata_quirk_entry *quirk;
1582195534Sscottl	struct cam_ed *device;
1583195534Sscottl
1584195534Sscottl	device = xpt_alloc_device(bus, target, lun_id);
1585195534Sscottl	if (device == NULL)
1586195534Sscottl		return (NULL);
1587195534Sscottl
1588195534Sscottl	/*
1589195534Sscottl	 * Take the default quirk entry until we have inquiry
1590195534Sscottl	 * data and can determine a better quirk to use.
1591195534Sscottl	 */
1592298411Spfg	quirk = &ata_quirk_table[nitems(ata_quirk_table) - 1];
1593195534Sscottl	device->quirk = (void *)quirk;
1594199178Smav	device->mintags = 0;
1595199178Smav	device->maxtags = 0;
1596195534Sscottl	bzero(&device->inq_data, sizeof(device->inq_data));
1597195534Sscottl	device->inq_flags = 0;
1598195534Sscottl	device->queue_flags = 0;
1599195534Sscottl	device->serial_num = NULL;
1600195534Sscottl	device->serial_num_len = 0;
1601195534Sscottl	return (device);
1602195534Sscottl}
1603195534Sscottl
1604195534Sscottlstatic void
1605195534Sscottlata_device_transport(struct cam_path *path)
1606195534Sscottl{
1607195534Sscottl	struct ccb_pathinq cpi;
1608198331Smav	struct ccb_trans_settings cts;
1609198331Smav	struct scsi_inquiry_data *inq_buf = NULL;
1610198331Smav	struct ata_params *ident_buf = NULL;
1611195534Sscottl
1612195534Sscottl	/* Get transport information from the SIM */
1613203108Smav	xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE);
1614195534Sscottl	cpi.ccb_h.func_code = XPT_PATH_INQ;
1615195534Sscottl	xpt_action((union ccb *)&cpi);
1616195534Sscottl
1617195534Sscottl	path->device->transport = cpi.transport;
1618198331Smav	if ((path->device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0)
1619198331Smav		inq_buf = &path->device->inq_data;
1620198331Smav	if ((path->device->flags & CAM_DEV_IDENTIFY_DATA_VALID) != 0)
1621198331Smav		ident_buf = &path->device->ident_data;
1622198331Smav	if (path->device->protocol == PROTO_ATA) {
1623198331Smav		path->device->protocol_version = ident_buf ?
1624198331Smav		    ata_version(ident_buf->version_major) : cpi.protocol_version;
1625198331Smav	} else if (path->device->protocol == PROTO_SCSI) {
1626198331Smav		path->device->protocol_version = inq_buf ?
1627198331Smav		    SID_ANSI_REV(inq_buf) : cpi.protocol_version;
1628195534Sscottl	}
1629198331Smav	path->device->transport_version = ident_buf ?
1630198331Smav	    ata_version(ident_buf->version_major) : cpi.transport_version;
1631195534Sscottl
1632195534Sscottl	/* Tell the controller what we think */
1633203108Smav	xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
1634195534Sscottl	cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
1635195534Sscottl	cts.type = CTS_TYPE_CURRENT_SETTINGS;
1636195534Sscottl	cts.transport = path->device->transport;
1637195534Sscottl	cts.transport_version = path->device->transport_version;
1638195534Sscottl	cts.protocol = path->device->protocol;
1639195534Sscottl	cts.protocol_version = path->device->protocol_version;
1640195534Sscottl	cts.proto_specific.valid = 0;
1641203376Smav	if (ident_buf) {
1642203376Smav		if (path->device->transport == XPORT_ATA) {
1643223019Smav			cts.xport_specific.ata.atapi =
1644223019Smav			    (ident_buf->config == ATA_PROTO_CFA) ? 0 :
1645203376Smav			    ((ident_buf->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_16) ? 16 :
1646203376Smav			    ((ident_buf->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12) ? 12 : 0;
1647203376Smav			cts.xport_specific.ata.valid = CTS_ATA_VALID_ATAPI;
1648203376Smav		} else {
1649223019Smav			cts.xport_specific.sata.atapi =
1650223019Smav			    (ident_buf->config == ATA_PROTO_CFA) ? 0 :
1651203376Smav			    ((ident_buf->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_16) ? 16 :
1652203376Smav			    ((ident_buf->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12) ? 12 : 0;
1653203376Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_ATAPI;
1654203376Smav		}
1655203376Smav	} else
1656203376Smav		cts.xport_specific.valid = 0;
1657195534Sscottl	xpt_action((union ccb *)&cts);
1658195534Sscottl}
1659195534Sscottl
1660195534Sscottlstatic void
1661223443Swillata_dev_advinfo(union ccb *start_ccb)
1662223443Swill{
1663223443Swill	struct cam_ed *device;
1664223443Swill	struct ccb_dev_advinfo *cdai;
1665223443Swill	off_t amt;
1666223443Swill
1667223443Swill	start_ccb->ccb_h.status = CAM_REQ_INVALID;
1668223443Swill	device = start_ccb->ccb_h.path->device;
1669223443Swill	cdai = &start_ccb->cdai;
1670223443Swill	switch(cdai->buftype) {
1671235897Smav	case CDAI_TYPE_SCSI_DEVID:
1672235897Smav		if (cdai->flags & CDAI_FLAG_STORE)
1673235897Smav			return;
1674235897Smav		cdai->provsiz = device->device_id_len;
1675235897Smav		if (device->device_id_len == 0)
1676235897Smav			break;
1677235897Smav		amt = device->device_id_len;
1678235897Smav		if (cdai->provsiz > cdai->bufsiz)
1679235897Smav			amt = cdai->bufsiz;
1680235897Smav		memcpy(cdai->buf, device->device_id, amt);
1681235897Smav		break;
1682223443Swill	case CDAI_TYPE_SERIAL_NUM:
1683223443Swill		if (cdai->flags & CDAI_FLAG_STORE)
1684235897Smav			return;
1685223443Swill		cdai->provsiz = device->serial_num_len;
1686223443Swill		if (device->serial_num_len == 0)
1687223443Swill			break;
1688223443Swill		amt = device->serial_num_len;
1689223443Swill		if (cdai->provsiz > cdai->bufsiz)
1690223443Swill			amt = cdai->bufsiz;
1691223443Swill		memcpy(cdai->buf, device->serial_num, amt);
1692223443Swill		break;
1693235897Smav	case CDAI_TYPE_PHYS_PATH:
1694235897Smav		if (cdai->flags & CDAI_FLAG_STORE) {
1695235897Smav			if (device->physpath != NULL)
1696235897Smav				free(device->physpath, M_CAMXPT);
1697235897Smav			device->physpath_len = cdai->bufsiz;
1698235897Smav			/* Clear existing buffer if zero length */
1699235897Smav			if (cdai->bufsiz == 0)
1700235897Smav				break;
1701235897Smav			device->physpath = malloc(cdai->bufsiz, M_CAMXPT, M_NOWAIT);
1702235897Smav			if (device->physpath == NULL) {
1703235897Smav				start_ccb->ccb_h.status = CAM_REQ_ABORTED;
1704235897Smav				return;
1705235897Smav			}
1706235897Smav			memcpy(device->physpath, cdai->buf, cdai->bufsiz);
1707235897Smav		} else {
1708235897Smav			cdai->provsiz = device->physpath_len;
1709235897Smav			if (device->physpath_len == 0)
1710235897Smav				break;
1711235897Smav			amt = device->physpath_len;
1712235897Smav			if (cdai->provsiz > cdai->bufsiz)
1713235897Smav				amt = cdai->bufsiz;
1714235897Smav			memcpy(cdai->buf, device->physpath, amt);
1715235897Smav		}
1716235897Smav		break;
1717223443Swill	default:
1718235897Smav		return;
1719223443Swill	}
1720235897Smav	start_ccb->ccb_h.status = CAM_REQ_CMP;
1721235897Smav
1722235897Smav	if (cdai->flags & CDAI_FLAG_STORE) {
1723235897Smav		xpt_async(AC_ADVINFO_CHANGED, start_ccb->ccb_h.path,
1724235897Smav			  (void *)(uintptr_t)cdai->buftype);
1725235897Smav	}
1726223443Swill}
1727223443Swill
1728223443Swillstatic void
1729195534Sscottlata_action(union ccb *start_ccb)
1730195534Sscottl{
1731195534Sscottl
1732195534Sscottl	switch (start_ccb->ccb_h.func_code) {
1733195534Sscottl	case XPT_SET_TRAN_SETTINGS:
1734195534Sscottl	{
1735199178Smav		ata_set_transfer_settings(&start_ccb->cts,
1736256843Smav					   start_ccb->ccb_h.path,
1737195534Sscottl					   /*async_update*/FALSE);
1738195534Sscottl		break;
1739195534Sscottl	}
1740195534Sscottl	case XPT_SCAN_BUS:
1741208582Smjacob	case XPT_SCAN_TGT:
1742195534Sscottl		ata_scan_bus(start_ccb->ccb_h.path->periph, start_ccb);
1743195534Sscottl		break;
1744195534Sscottl	case XPT_SCAN_LUN:
1745195534Sscottl		ata_scan_lun(start_ccb->ccb_h.path->periph,
1746195534Sscottl			      start_ccb->ccb_h.path, start_ccb->crcn.flags,
1747195534Sscottl			      start_ccb);
1748195534Sscottl		break;
1749195534Sscottl	case XPT_GET_TRAN_SETTINGS:
1750195534Sscottl	{
1751236437Smav		ata_get_transfer_settings(&start_ccb->cts);
1752195534Sscottl		break;
1753195534Sscottl	}
1754203376Smav	case XPT_SCSI_IO:
1755203376Smav	{
1756203376Smav		struct cam_ed *device;
1757203376Smav		u_int	maxlen = 0;
1758203376Smav
1759203376Smav		device = start_ccb->ccb_h.path->device;
1760203376Smav		if (device->protocol == PROTO_SCSI &&
1761203376Smav		    (device->flags & CAM_DEV_IDENTIFY_DATA_VALID)) {
1762203376Smav			uint16_t p =
1763203376Smav			    device->ident_data.config & ATA_PROTO_MASK;
1764203376Smav
1765223019Smav			maxlen =
1766223019Smav			    (device->ident_data.config == ATA_PROTO_CFA) ? 0 :
1767223019Smav			    (p == ATA_PROTO_ATAPI_16) ? 16 :
1768203376Smav			    (p == ATA_PROTO_ATAPI_12) ? 12 : 0;
1769203376Smav		}
1770203376Smav		if (start_ccb->csio.cdb_len > maxlen) {
1771203376Smav			start_ccb->ccb_h.status = CAM_REQ_INVALID;
1772203376Smav			xpt_done(start_ccb);
1773203376Smav			break;
1774203376Smav		}
1775223475Smav		xpt_action_default(start_ccb);
1776223475Smav		break;
1777203376Smav	}
1778223443Swill	case XPT_DEV_ADVINFO:
1779223443Swill	{
1780223443Swill		ata_dev_advinfo(start_ccb);
1781223443Swill		break;
1782223443Swill	}
1783195534Sscottl	default:
1784195534Sscottl		xpt_action_default(start_ccb);
1785195534Sscottl		break;
1786195534Sscottl	}
1787195534Sscottl}
1788195534Sscottl
1789195534Sscottlstatic void
1790236437Smavata_get_transfer_settings(struct ccb_trans_settings *cts)
1791236437Smav{
1792236437Smav	struct	ccb_trans_settings_ata *ata;
1793236437Smav	struct	ccb_trans_settings_scsi *scsi;
1794236437Smav	struct	cam_ed *device;
1795236437Smav
1796236437Smav	device = cts->ccb_h.path->device;
1797256843Smav	xpt_action_default((union ccb *)cts);
1798236437Smav
1799236666Smav	if (cts->protocol == PROTO_UNKNOWN ||
1800236666Smav	    cts->protocol == PROTO_UNSPECIFIED) {
1801236666Smav		cts->protocol = device->protocol;
1802236666Smav		cts->protocol_version = device->protocol_version;
1803236666Smav	}
1804236666Smav
1805236437Smav	if (cts->protocol == PROTO_ATA) {
1806236437Smav		ata = &cts->proto_specific.ata;
1807236437Smav		if ((ata->valid & CTS_ATA_VALID_TQ) == 0) {
1808236437Smav			ata->valid |= CTS_ATA_VALID_TQ;
1809236437Smav			if (cts->type == CTS_TYPE_USER_SETTINGS ||
1810236437Smav			    (device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 ||
1811236437Smav			    (device->inq_flags & SID_CmdQue) != 0)
1812236437Smav				ata->flags |= CTS_ATA_FLAGS_TAG_ENB;
1813236437Smav		}
1814236437Smav	}
1815236437Smav	if (cts->protocol == PROTO_SCSI) {
1816236437Smav		scsi = &cts->proto_specific.scsi;
1817236437Smav		if ((scsi->valid & CTS_SCSI_VALID_TQ) == 0) {
1818236437Smav			scsi->valid |= CTS_SCSI_VALID_TQ;
1819236437Smav			if (cts->type == CTS_TYPE_USER_SETTINGS ||
1820236437Smav			    (device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 ||
1821236437Smav			    (device->inq_flags & SID_CmdQue) != 0)
1822236437Smav				scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
1823236437Smav		}
1824236437Smav	}
1825236666Smav
1826236666Smav	if (cts->transport == XPORT_UNKNOWN ||
1827236666Smav	    cts->transport == XPORT_UNSPECIFIED) {
1828236666Smav		cts->transport = device->transport;
1829236666Smav		cts->transport_version = device->transport_version;
1830236666Smav	}
1831236437Smav}
1832236437Smav
1833236437Smavstatic void
1834256843Smavata_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_path *path,
1835195534Sscottl			   int async_update)
1836195534Sscottl{
1837195534Sscottl	struct	ccb_pathinq cpi;
1838236437Smav	struct	ccb_trans_settings_ata *ata;
1839195534Sscottl	struct	ccb_trans_settings_scsi *scsi;
1840236437Smav	struct	ata_params *ident_data;
1841195534Sscottl	struct	scsi_inquiry_data *inq_data;
1842256843Smav	struct	cam_ed *device;
1843195534Sscottl
1844256843Smav	if (path == NULL || (device = path->device) == NULL) {
1845195534Sscottl		cts->ccb_h.status = CAM_PATH_INVALID;
1846195534Sscottl		xpt_done((union ccb *)cts);
1847195534Sscottl		return;
1848195534Sscottl	}
1849195534Sscottl
1850195534Sscottl	if (cts->protocol == PROTO_UNKNOWN
1851195534Sscottl	 || cts->protocol == PROTO_UNSPECIFIED) {
1852195534Sscottl		cts->protocol = device->protocol;
1853195534Sscottl		cts->protocol_version = device->protocol_version;
1854195534Sscottl	}
1855195534Sscottl
1856195534Sscottl	if (cts->protocol_version == PROTO_VERSION_UNKNOWN
1857195534Sscottl	 || cts->protocol_version == PROTO_VERSION_UNSPECIFIED)
1858195534Sscottl		cts->protocol_version = device->protocol_version;
1859195534Sscottl
1860195534Sscottl	if (cts->protocol != device->protocol) {
1861256843Smav		xpt_print(path, "Uninitialized Protocol %x:%x?\n",
1862195534Sscottl		       cts->protocol, device->protocol);
1863195534Sscottl		cts->protocol = device->protocol;
1864195534Sscottl	}
1865195534Sscottl
1866195534Sscottl	if (cts->protocol_version > device->protocol_version) {
1867195534Sscottl		if (bootverbose) {
1868256843Smav			xpt_print(path, "Down reving Protocol "
1869195534Sscottl			    "Version from %d to %d?\n", cts->protocol_version,
1870195534Sscottl			    device->protocol_version);
1871195534Sscottl		}
1872195534Sscottl		cts->protocol_version = device->protocol_version;
1873195534Sscottl	}
1874195534Sscottl
1875195534Sscottl	if (cts->transport == XPORT_UNKNOWN
1876195534Sscottl	 || cts->transport == XPORT_UNSPECIFIED) {
1877195534Sscottl		cts->transport = device->transport;
1878195534Sscottl		cts->transport_version = device->transport_version;
1879195534Sscottl	}
1880195534Sscottl
1881195534Sscottl	if (cts->transport_version == XPORT_VERSION_UNKNOWN
1882195534Sscottl	 || cts->transport_version == XPORT_VERSION_UNSPECIFIED)
1883195534Sscottl		cts->transport_version = device->transport_version;
1884195534Sscottl
1885195534Sscottl	if (cts->transport != device->transport) {
1886256843Smav		xpt_print(path, "Uninitialized Transport %x:%x?\n",
1887195534Sscottl		    cts->transport, device->transport);
1888195534Sscottl		cts->transport = device->transport;
1889195534Sscottl	}
1890195534Sscottl
1891195534Sscottl	if (cts->transport_version > device->transport_version) {
1892195534Sscottl		if (bootverbose) {
1893256843Smav			xpt_print(path, "Down reving Transport "
1894195534Sscottl			    "Version from %d to %d?\n", cts->transport_version,
1895195534Sscottl			    device->transport_version);
1896195534Sscottl		}
1897195534Sscottl		cts->transport_version = device->transport_version;
1898195534Sscottl	}
1899195534Sscottl
1900236437Smav	ident_data = &device->ident_data;
1901195534Sscottl	inq_data = &device->inq_data;
1902236437Smav	if (cts->protocol == PROTO_ATA)
1903236437Smav		ata = &cts->proto_specific.ata;
1904236437Smav	else
1905236437Smav		ata = NULL;
1906236437Smav	if (cts->protocol == PROTO_SCSI)
1907236437Smav		scsi = &cts->proto_specific.scsi;
1908236437Smav	else
1909236437Smav		scsi = NULL;
1910256843Smav	xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE);
1911195534Sscottl	cpi.ccb_h.func_code = XPT_PATH_INQ;
1912195534Sscottl	xpt_action((union ccb *)&cpi);
1913195534Sscottl
1914236437Smav	/* Sanity checking */
1915195534Sscottl	if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0
1916236437Smav	 || (ata && (ident_data->satacapabilities & ATA_SUPPORT_NCQ) == 0)
1917236437Smav	 || (scsi && (INQ_DATA_TQ_ENABLED(inq_data)) == 0)
1918195534Sscottl	 || (device->queue_flags & SCP_QUEUE_DQUE) != 0
1919195534Sscottl	 || (device->mintags == 0)) {
1920195534Sscottl		/*
1921195534Sscottl		 * Can't tag on hardware that doesn't support tags,
1922195534Sscottl		 * doesn't have it enabled, or has broken tag support.
1923195534Sscottl		 */
1924236437Smav		if (ata)
1925236437Smav			ata->flags &= ~CTS_ATA_FLAGS_TAG_ENB;
1926236437Smav		if (scsi)
1927195534Sscottl			scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
1928195534Sscottl	}
1929195534Sscottl
1930236437Smav	/* Start/stop tags use. */
1931236437Smav	if (cts->type == CTS_TYPE_CURRENT_SETTINGS &&
1932236437Smav	    ((ata && (ata->valid & CTS_ATA_VALID_TQ) != 0) ||
1933236437Smav	     (scsi && (scsi->valid & CTS_SCSI_VALID_TQ) != 0))) {
1934236437Smav		int nowt, newt = 0;
1935195534Sscottl
1936236437Smav		nowt = ((device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 ||
1937236437Smav			(device->inq_flags & SID_CmdQue) != 0);
1938236437Smav		if (ata)
1939236437Smav			newt = (ata->flags & CTS_ATA_FLAGS_TAG_ENB) != 0;
1940236437Smav		if (scsi)
1941236437Smav			newt = (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0;
1942195534Sscottl
1943236437Smav		if (newt && !nowt) {
1944236437Smav			/*
1945236437Smav			 * Delay change to use tags until after a
1946236437Smav			 * few commands have gone to this device so
1947236437Smav			 * the controller has time to perform transfer
1948236437Smav			 * negotiations without tagged messages getting
1949236437Smav			 * in the way.
1950236437Smav			 */
1951236437Smav			device->tag_delay_count = CAM_TAG_DELAY_COUNT;
1952236437Smav			device->flags |= CAM_DEV_TAG_AFTER_COUNT;
1953236437Smav		} else if (nowt && !newt)
1954256843Smav			xpt_stop_tags(path);
1955236437Smav	}
1956195534Sscottl
1957195534Sscottl	if (async_update == FALSE)
1958256843Smav		xpt_action_default((union ccb *)cts);
1959195534Sscottl}
1960195534Sscottl
1961195534Sscottl/*
1962195534Sscottl * Handle any per-device event notifications that require action by the XPT.
1963195534Sscottl */
1964195534Sscottlstatic void
1965195534Sscottlata_dev_async(u_int32_t async_code, struct cam_eb *bus, struct cam_et *target,
1966195534Sscottl	      struct cam_ed *device, void *async_arg)
1967195534Sscottl{
1968195534Sscottl	cam_status status;
1969195534Sscottl	struct cam_path newpath;
1970195534Sscottl
1971195534Sscottl	/*
1972195534Sscottl	 * We only need to handle events for real devices.
1973195534Sscottl	 */
1974195534Sscottl	if (target->target_id == CAM_TARGET_WILDCARD
1975195534Sscottl	 || device->lun_id == CAM_LUN_WILDCARD)
1976195534Sscottl		return;
1977195534Sscottl
1978195534Sscottl	/*
1979195534Sscottl	 * We need our own path with wildcards expanded to
1980195534Sscottl	 * handle certain types of events.
1981195534Sscottl	 */
1982195534Sscottl	if ((async_code == AC_SENT_BDR)
1983195534Sscottl	 || (async_code == AC_BUS_RESET)
1984195534Sscottl	 || (async_code == AC_INQ_CHANGED))
1985195534Sscottl		status = xpt_compile_path(&newpath, NULL,
1986195534Sscottl					  bus->path_id,
1987195534Sscottl					  target->target_id,
1988195534Sscottl					  device->lun_id);
1989195534Sscottl	else
1990195534Sscottl		status = CAM_REQ_CMP_ERR;
1991195534Sscottl
1992195534Sscottl	if (status == CAM_REQ_CMP) {
1993195534Sscottl		if (async_code == AC_INQ_CHANGED) {
1994195534Sscottl			/*
1995195534Sscottl			 * We've sent a start unit command, or
1996195534Sscottl			 * something similar to a device that
1997195534Sscottl			 * may have caused its inquiry data to
1998195534Sscottl			 * change. So we re-scan the device to
1999195534Sscottl			 * refresh the inquiry data for it.
2000195534Sscottl			 */
2001195534Sscottl			ata_scan_lun(newpath.periph, &newpath,
2002195534Sscottl				     CAM_EXPECT_INQ_CHANGE, NULL);
2003203108Smav		} else {
2004203108Smav			/* We need to reinitialize device after reset. */
2005203108Smav			ata_scan_lun(newpath.periph, &newpath,
2006203108Smav				     0, NULL);
2007195534Sscottl		}
2008195534Sscottl		xpt_release_path(&newpath);
2009198748Smav	} else if (async_code == AC_LOST_DEVICE &&
2010198748Smav	    (device->flags & CAM_DEV_UNCONFIGURED) == 0) {
2011195534Sscottl		device->flags |= CAM_DEV_UNCONFIGURED;
2012198748Smav		xpt_release_device(device);
2013195534Sscottl	} else if (async_code == AC_TRANSFER_NEG) {
2014195534Sscottl		struct ccb_trans_settings *settings;
2015256843Smav		struct cam_path path;
2016195534Sscottl
2017195534Sscottl		settings = (struct ccb_trans_settings *)async_arg;
2018256843Smav		xpt_compile_path(&path, NULL, bus->path_id, target->target_id,
2019256843Smav				 device->lun_id);
2020256843Smav		ata_set_transfer_settings(settings, &path,
2021195534Sscottl					  /*async_update*/TRUE);
2022256843Smav		xpt_release_path(&path);
2023195534Sscottl	}
2024195534Sscottl}
2025195534Sscottl
2026204220Smavstatic void
2027204220Smavata_announce_periph(struct cam_periph *periph)
2028204220Smav{
2029204220Smav	struct	ccb_pathinq cpi;
2030204220Smav	struct	ccb_trans_settings cts;
2031204220Smav	struct	cam_path *path = periph->path;
2032204220Smav	u_int	speed;
2033204220Smav	u_int	mb;
2034204220Smav
2035256843Smav	cam_periph_assert(periph, MA_OWNED);
2036204220Smav
2037204220Smav	xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
2038204220Smav	cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
2039204220Smav	cts.type = CTS_TYPE_CURRENT_SETTINGS;
2040204220Smav	xpt_action((union ccb*)&cts);
2041204220Smav	if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
2042204220Smav		return;
2043204220Smav	/* Ask the SIM for its base transfer speed */
2044204220Smav	xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL);
2045204220Smav	cpi.ccb_h.func_code = XPT_PATH_INQ;
2046204220Smav	xpt_action((union ccb *)&cpi);
2047204220Smav	/* Report connection speed */
2048204220Smav	speed = cpi.base_transfer_speed;
2049204220Smav	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_ATA) {
2050236437Smav		struct	ccb_trans_settings_pata *pata =
2051204220Smav		    &cts.xport_specific.ata;
2052204220Smav
2053236437Smav		if (pata->valid & CTS_ATA_VALID_MODE)
2054236437Smav			speed = ata_mode2speed(pata->mode);
2055204220Smav	}
2056204220Smav	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SATA) {
2057204220Smav		struct	ccb_trans_settings_sata *sata =
2058204220Smav		    &cts.xport_specific.sata;
2059204220Smav
2060204220Smav		if (sata->valid & CTS_SATA_VALID_REVISION)
2061204220Smav			speed = ata_revision2speed(sata->revision);
2062204220Smav	}
2063204220Smav	mb = speed / 1000;
2064204220Smav	if (mb > 0)
2065204220Smav		printf("%s%d: %d.%03dMB/s transfers",
2066204220Smav		       periph->periph_name, periph->unit_number,
2067204220Smav		       mb, speed % 1000);
2068204220Smav	else
2069204220Smav		printf("%s%d: %dKB/s transfers", periph->periph_name,
2070204220Smav		       periph->unit_number, speed);
2071204220Smav	/* Report additional information about connection */
2072204220Smav	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_ATA) {
2073236437Smav		struct ccb_trans_settings_pata *pata =
2074204220Smav		    &cts.xport_specific.ata;
2075204220Smav
2076204220Smav		printf(" (");
2077236437Smav		if (pata->valid & CTS_ATA_VALID_MODE)
2078236437Smav			printf("%s, ", ata_mode2string(pata->mode));
2079236437Smav		if ((pata->valid & CTS_ATA_VALID_ATAPI) && pata->atapi != 0)
2080236437Smav			printf("ATAPI %dbytes, ", pata->atapi);
2081236437Smav		if (pata->valid & CTS_ATA_VALID_BYTECOUNT)
2082236437Smav			printf("PIO %dbytes", pata->bytecount);
2083204220Smav		printf(")");
2084204220Smav	}
2085204220Smav	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SATA) {
2086204220Smav		struct ccb_trans_settings_sata *sata =
2087204220Smav		    &cts.xport_specific.sata;
2088204220Smav
2089204220Smav		printf(" (");
2090204220Smav		if (sata->valid & CTS_SATA_VALID_REVISION)
2091204220Smav			printf("SATA %d.x, ", sata->revision);
2092204220Smav		else
2093204220Smav			printf("SATA, ");
2094204220Smav		if (sata->valid & CTS_SATA_VALID_MODE)
2095204220Smav			printf("%s, ", ata_mode2string(sata->mode));
2096204220Smav		if ((sata->valid & CTS_ATA_VALID_ATAPI) && sata->atapi != 0)
2097204220Smav			printf("ATAPI %dbytes, ", sata->atapi);
2098204220Smav		if (sata->valid & CTS_SATA_VALID_BYTECOUNT)
2099204220Smav			printf("PIO %dbytes", sata->bytecount);
2100204220Smav		printf(")");
2101204220Smav	}
2102204220Smav	printf("\n");
2103204220Smav}
2104