ata_xpt.c revision 238886
1195534Sscottl/*-
2195534Sscottl * Copyright (c) 2009 Alexander Motin <mav@FreeBSD.org>
3195534Sscottl * All rights reserved.
4195534Sscottl *
5195534Sscottl * Redistribution and use in source and binary forms, with or without
6195534Sscottl * modification, are permitted provided that the following conditions
7195534Sscottl * are met:
8195534Sscottl * 1. Redistributions of source code must retain the above copyright
9195534Sscottl *    notice, this list of conditions and the following disclaimer,
10195534Sscottl *    without modification, immediately at the beginning of the file.
11195534Sscottl * 2. Redistributions in binary form must reproduce the above copyright
12195534Sscottl *    notice, this list of conditions and the following disclaimer in the
13195534Sscottl *    documentation and/or other materials provided with the distribution.
14195534Sscottl *
15195534Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16195534Sscottl * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17195534Sscottl * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18195534Sscottl * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19195534Sscottl * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20195534Sscottl * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21195534Sscottl * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22195534Sscottl * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23195534Sscottl * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24195534Sscottl * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25195534Sscottl */
26195534Sscottl
27195534Sscottl#include <sys/cdefs.h>
28195534Sscottl__FBSDID("$FreeBSD: head/sys/cam/ata/ata_xpt.c 238886 2012-07-29 11:51:48Z mav $");
29195534Sscottl
30195534Sscottl#include <sys/param.h>
31195534Sscottl#include <sys/bus.h>
32195534Sscottl#include <sys/endian.h>
33195534Sscottl#include <sys/systm.h>
34195534Sscottl#include <sys/types.h>
35195534Sscottl#include <sys/malloc.h>
36195534Sscottl#include <sys/kernel.h>
37195534Sscottl#include <sys/time.h>
38195534Sscottl#include <sys/conf.h>
39195534Sscottl#include <sys/fcntl.h>
40195534Sscottl#include <sys/interrupt.h>
41195534Sscottl#include <sys/sbuf.h>
42195534Sscottl
43195534Sscottl#include <sys/lock.h>
44195534Sscottl#include <sys/mutex.h>
45195534Sscottl#include <sys/sysctl.h>
46195534Sscottl
47195534Sscottl#include <cam/cam.h>
48195534Sscottl#include <cam/cam_ccb.h>
49195534Sscottl#include <cam/cam_queue.h>
50195534Sscottl#include <cam/cam_periph.h>
51195534Sscottl#include <cam/cam_sim.h>
52195534Sscottl#include <cam/cam_xpt.h>
53195534Sscottl#include <cam/cam_xpt_sim.h>
54195534Sscottl#include <cam/cam_xpt_periph.h>
55195534Sscottl#include <cam/cam_xpt_internal.h>
56195534Sscottl#include <cam/cam_debug.h>
57195534Sscottl
58195534Sscottl#include <cam/scsi/scsi_all.h>
59195534Sscottl#include <cam/scsi/scsi_message.h>
60195534Sscottl#include <cam/ata/ata_all.h>
61195534Sscottl#include <machine/stdarg.h>	/* for xpt_print below */
62195534Sscottl#include "opt_cam.h"
63195534Sscottl
64199178Smavstruct ata_quirk_entry {
65195534Sscottl	struct scsi_inquiry_pattern inq_pat;
66195534Sscottl	u_int8_t quirks;
67199178Smav#define	CAM_QUIRK_MAXTAGS	0x01
68236234Smav	u_int mintags;
69195534Sscottl	u_int maxtags;
70195534Sscottl};
71195534Sscottl
72195534Sscottlstatic periph_init_t probe_periph_init;
73195534Sscottl
74195534Sscottlstatic struct periph_driver probe_driver =
75195534Sscottl{
76195653Smav	probe_periph_init, "aprobe",
77198708Smav	TAILQ_HEAD_INITIALIZER(probe_driver.units), /* generation */ 0,
78198708Smav	CAM_PERIPH_DRV_EARLY
79195534Sscottl};
80195534Sscottl
81195653SmavPERIPHDRIVER_DECLARE(aprobe, probe_driver);
82195534Sscottl
83195534Sscottltypedef enum {
84195534Sscottl	PROBE_RESET,
85195534Sscottl	PROBE_IDENTIFY,
86203421Smav	PROBE_SPINUP,
87195534Sscottl	PROBE_SETMODE,
88207499Smav	PROBE_SETPM,
89207499Smav	PROBE_SETAPST,
90207499Smav	PROBE_SETDMAAA,
91220602Smav	PROBE_SETAN,
92198708Smav	PROBE_SET_MULTI,
93195534Sscottl	PROBE_INQUIRY,
94195534Sscottl	PROBE_FULL_INQUIRY,
95195534Sscottl	PROBE_PM_PID,
96195534Sscottl	PROBE_PM_PRV,
97235897Smav	PROBE_IDENTIFY_SES,
98235897Smav	PROBE_IDENTIFY_SAFTE,
99236613Smav	PROBE_DONE,
100195534Sscottl	PROBE_INVALID
101195534Sscottl} probe_action;
102195534Sscottl
103195534Sscottlstatic char *probe_action_text[] = {
104195534Sscottl	"PROBE_RESET",
105195534Sscottl	"PROBE_IDENTIFY",
106203421Smav	"PROBE_SPINUP",
107195534Sscottl	"PROBE_SETMODE",
108207499Smav	"PROBE_SETPM",
109207499Smav	"PROBE_SETAPST",
110207499Smav	"PROBE_SETDMAAA",
111220602Smav	"PROBE_SETAN",
112198708Smav	"PROBE_SET_MULTI",
113195534Sscottl	"PROBE_INQUIRY",
114195534Sscottl	"PROBE_FULL_INQUIRY",
115195534Sscottl	"PROBE_PM_PID",
116195534Sscottl	"PROBE_PM_PRV",
117235897Smav	"PROBE_IDENTIFY_SES",
118235897Smav	"PROBE_IDENTIFY_SAFTE",
119236613Smav	"PROBE_DONE",
120195534Sscottl	"PROBE_INVALID"
121195534Sscottl};
122195534Sscottl
123195534Sscottl#define PROBE_SET_ACTION(softc, newaction)	\
124195534Sscottldo {									\
125195534Sscottl	char **text;							\
126195534Sscottl	text = probe_action_text;					\
127236613Smav	CAM_DEBUG((softc)->periph->path, CAM_DEBUG_PROBE,		\
128195534Sscottl	    ("Probe %s to %s\n", text[(softc)->action],			\
129195534Sscottl	    text[(newaction)]));					\
130195534Sscottl	(softc)->action = (newaction);					\
131195534Sscottl} while(0)
132195534Sscottl
133195534Sscottltypedef enum {
134195534Sscottl	PROBE_NO_ANNOUNCE	= 0x04
135195534Sscottl} probe_flags;
136195534Sscottl
137195534Sscottltypedef struct {
138195534Sscottl	TAILQ_HEAD(, ccb_hdr) request_ccbs;
139203385Smav	struct ata_params	ident_data;
140195534Sscottl	probe_action	action;
141195534Sscottl	probe_flags	flags;
142195534Sscottl	uint32_t	pm_pid;
143195534Sscottl	uint32_t	pm_prv;
144203108Smav	int		restart;
145203421Smav	int		spinup;
146209744Smav	int		faults;
147207499Smav	u_int		caps;
148195534Sscottl	struct cam_periph *periph;
149195534Sscottl} probe_softc;
150195534Sscottl
151199178Smavstatic struct ata_quirk_entry ata_quirk_table[] =
152195534Sscottl{
153195534Sscottl	{
154195534Sscottl		/* Default tagged queuing parameters for all devices */
155195534Sscottl		{
156195534Sscottl		  T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED,
157195534Sscottl		  /*vendor*/"*", /*product*/"*", /*revision*/"*"
158195534Sscottl		},
159236234Smav		/*quirks*/0, /*mintags*/0, /*maxtags*/0
160195534Sscottl	},
161195534Sscottl};
162195534Sscottl
163199178Smavstatic const int ata_quirk_table_size =
164199178Smav	sizeof(ata_quirk_table) / sizeof(*ata_quirk_table);
165195534Sscottl
166195534Sscottlstatic cam_status	proberegister(struct cam_periph *periph,
167195534Sscottl				      void *arg);
168195534Sscottlstatic void	 probeschedule(struct cam_periph *probe_periph);
169195534Sscottlstatic void	 probestart(struct cam_periph *periph, union ccb *start_ccb);
170236437Smavstatic void	 proberequestdefaultnegotiation(struct cam_periph *periph);
171195534Sscottlstatic void	 probedone(struct cam_periph *periph, union ccb *done_ccb);
172195534Sscottlstatic void	 probecleanup(struct cam_periph *periph);
173199178Smavstatic void	 ata_find_quirk(struct cam_ed *device);
174195534Sscottlstatic void	 ata_scan_bus(struct cam_periph *periph, union ccb *ccb);
175195534Sscottlstatic void	 ata_scan_lun(struct cam_periph *periph,
176195534Sscottl			       struct cam_path *path, cam_flags flags,
177195534Sscottl			       union ccb *ccb);
178195534Sscottlstatic void	 xptscandone(struct cam_periph *periph, union ccb *done_ccb);
179195534Sscottlstatic struct cam_ed *
180195534Sscottl		 ata_alloc_device(struct cam_eb *bus, struct cam_et *target,
181195534Sscottl				   lun_id_t lun_id);
182195534Sscottlstatic void	 ata_device_transport(struct cam_path *path);
183236437Smavstatic void	 ata_get_transfer_settings(struct ccb_trans_settings *cts);
184199178Smavstatic void	 ata_set_transfer_settings(struct ccb_trans_settings *cts,
185195534Sscottl					    struct cam_ed *device,
186195534Sscottl					    int async_update);
187195534Sscottlstatic void	 ata_dev_async(u_int32_t async_code,
188195534Sscottl				struct cam_eb *bus,
189195534Sscottl				struct cam_et *target,
190195534Sscottl				struct cam_ed *device,
191195534Sscottl				void *async_arg);
192195534Sscottlstatic void	 ata_action(union ccb *start_ccb);
193204220Smavstatic void	 ata_announce_periph(struct cam_periph *periph);
194195534Sscottl
195230912Smavstatic int ata_dma = 1;
196230912Smavstatic int atapi_dma = 1;
197230912Smav
198230912SmavTUNABLE_INT("hw.ata.ata_dma", &ata_dma);
199230912SmavTUNABLE_INT("hw.ata.atapi_dma", &atapi_dma);
200230912Smav
201195534Sscottlstatic struct xpt_xport ata_xport = {
202195534Sscottl	.alloc_device = ata_alloc_device,
203195534Sscottl	.action = ata_action,
204195534Sscottl	.async = ata_dev_async,
205204220Smav	.announce = ata_announce_periph,
206195534Sscottl};
207195534Sscottl
208195534Sscottlstruct xpt_xport *
209195534Sscottlata_get_xport(void)
210195534Sscottl{
211195534Sscottl	return (&ata_xport);
212195534Sscottl}
213195534Sscottl
214195534Sscottlstatic void
215195534Sscottlprobe_periph_init()
216195534Sscottl{
217195534Sscottl}
218195534Sscottl
219195534Sscottlstatic cam_status
220195534Sscottlproberegister(struct cam_periph *periph, void *arg)
221195534Sscottl{
222195534Sscottl	union ccb *request_ccb;	/* CCB representing the probe request */
223195534Sscottl	cam_status status;
224195534Sscottl	probe_softc *softc;
225195534Sscottl
226195534Sscottl	request_ccb = (union ccb *)arg;
227195534Sscottl	if (periph == NULL) {
228195534Sscottl		printf("proberegister: periph was NULL!!\n");
229195534Sscottl		return(CAM_REQ_CMP_ERR);
230195534Sscottl	}
231195534Sscottl
232195534Sscottl	if (request_ccb == NULL) {
233195534Sscottl		printf("proberegister: no probe CCB, "
234195534Sscottl		       "can't register device\n");
235195534Sscottl		return(CAM_REQ_CMP_ERR);
236195534Sscottl	}
237195534Sscottl
238203421Smav	softc = (probe_softc *)malloc(sizeof(*softc), M_CAMXPT, M_ZERO | M_NOWAIT);
239195534Sscottl
240195534Sscottl	if (softc == NULL) {
241195534Sscottl		printf("proberegister: Unable to probe new device. "
242195534Sscottl		       "Unable to allocate softc\n");
243195534Sscottl		return(CAM_REQ_CMP_ERR);
244195534Sscottl	}
245195534Sscottl	TAILQ_INIT(&softc->request_ccbs);
246195534Sscottl	TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h,
247195534Sscottl			  periph_links.tqe);
248195534Sscottl	softc->flags = 0;
249195534Sscottl	periph->softc = softc;
250195534Sscottl	softc->periph = periph;
251195534Sscottl	softc->action = PROBE_INVALID;
252195534Sscottl	status = cam_periph_acquire(periph);
253195534Sscottl	if (status != CAM_REQ_CMP) {
254195534Sscottl		return (status);
255195534Sscottl	}
256236613Smav	CAM_DEBUG(periph->path, CAM_DEBUG_PROBE, ("Probe started\n"));
257236613Smav
258195534Sscottl	/*
259203108Smav	 * Ensure nobody slip in until probe finish.
260195534Sscottl	 */
261203108Smav	cam_freeze_devq_arg(periph->path,
262203108Smav	    RELSIM_RELEASE_RUNLEVEL, CAM_RL_XPT + 1);
263195534Sscottl	probeschedule(periph);
264195534Sscottl	return(CAM_REQ_CMP);
265195534Sscottl}
266195534Sscottl
267195534Sscottlstatic void
268195534Sscottlprobeschedule(struct cam_periph *periph)
269195534Sscottl{
270195534Sscottl	union ccb *ccb;
271195534Sscottl	probe_softc *softc;
272195534Sscottl
273195534Sscottl	softc = (probe_softc *)periph->softc;
274195534Sscottl	ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs);
275195534Sscottl
276198389Smav	if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) ||
277235897Smav	    periph->path->device->protocol == PROTO_SATAPM ||
278235897Smav	    periph->path->device->protocol == PROTO_SEMB)
279195534Sscottl		PROBE_SET_ACTION(softc, PROBE_RESET);
280195534Sscottl	else
281195534Sscottl		PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
282195534Sscottl
283195534Sscottl	if (ccb->crcn.flags & CAM_EXPECT_INQ_CHANGE)
284195534Sscottl		softc->flags |= PROBE_NO_ANNOUNCE;
285195534Sscottl	else
286195534Sscottl		softc->flags &= ~PROBE_NO_ANNOUNCE;
287195534Sscottl
288203108Smav	xpt_schedule(periph, CAM_PRIORITY_XPT);
289195534Sscottl}
290195534Sscottl
291195534Sscottlstatic void
292195534Sscottlprobestart(struct cam_periph *periph, union ccb *start_ccb)
293195534Sscottl{
294199747Smav	struct ccb_trans_settings cts;
295195534Sscottl	struct ccb_ataio *ataio;
296195534Sscottl	struct ccb_scsiio *csio;
297195534Sscottl	probe_softc *softc;
298198708Smav	struct cam_path *path;
299198708Smav	struct ata_params *ident_buf;
300195534Sscottl
301195534Sscottl	CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probestart\n"));
302195534Sscottl
303195534Sscottl	softc = (probe_softc *)periph->softc;
304198708Smav	path = start_ccb->ccb_h.path;
305195534Sscottl	ataio = &start_ccb->ataio;
306195534Sscottl	csio = &start_ccb->csio;
307198708Smav	ident_buf = &periph->path->device->ident_data;
308195534Sscottl
309203108Smav	if (softc->restart) {
310203108Smav		softc->restart = 0;
311203108Smav		if ((path->device->flags & CAM_DEV_UNCONFIGURED) ||
312235897Smav		    path->device->protocol == PROTO_SATAPM ||
313235897Smav		    path->device->protocol == PROTO_SEMB)
314203108Smav			softc->action = PROBE_RESET;
315203108Smav		else
316203108Smav			softc->action = PROBE_IDENTIFY;
317203108Smav	}
318195534Sscottl	switch (softc->action) {
319195534Sscottl	case PROBE_RESET:
320195534Sscottl		cam_fill_ataio(ataio,
321195534Sscottl		      0,
322195534Sscottl		      probedone,
323195534Sscottl		      /*flags*/CAM_DIR_NONE,
324198389Smav		      0,
325195534Sscottl		      /*data_ptr*/NULL,
326195534Sscottl		      /*dxfer_len*/0,
327203108Smav		      15 * 1000);
328195534Sscottl		ata_reset_cmd(ataio);
329195534Sscottl		break;
330195534Sscottl	case PROBE_IDENTIFY:
331195534Sscottl		cam_fill_ataio(ataio,
332195534Sscottl		      1,
333195534Sscottl		      probedone,
334195534Sscottl		      /*flags*/CAM_DIR_IN,
335198389Smav		      0,
336203385Smav		      /*data_ptr*/(u_int8_t *)&softc->ident_data,
337203385Smav		      /*dxfer_len*/sizeof(softc->ident_data),
338195534Sscottl		      30 * 1000);
339195534Sscottl		if (periph->path->device->protocol == PROTO_ATA)
340196659Smav			ata_28bit_cmd(ataio, ATA_ATA_IDENTIFY, 0, 0, 0);
341195534Sscottl		else
342196659Smav			ata_28bit_cmd(ataio, ATA_ATAPI_IDENTIFY, 0, 0, 0);
343195534Sscottl		break;
344203421Smav	case PROBE_SPINUP:
345203421Smav		if (bootverbose)
346203421Smav			xpt_print(path, "Spinning up device\n");
347203421Smav		cam_fill_ataio(ataio,
348203421Smav		      1,
349203421Smav		      probedone,
350203421Smav		      /*flags*/CAM_DIR_NONE | CAM_HIGH_POWER,
351203421Smav		      0,
352203421Smav		      /*data_ptr*/NULL,
353203421Smav		      /*dxfer_len*/0,
354203421Smav		      30 * 1000);
355203421Smav		ata_28bit_cmd(ataio, ATA_SETFEATURES, ATA_SF_PUIS_SPINUP, 0, 0);
356203421Smav		break;
357195534Sscottl	case PROBE_SETMODE:
358199747Smav	{
359199747Smav		int mode, wantmode;
360199747Smav
361199747Smav		mode = 0;
362199747Smav		/* Fetch user modes from SIM. */
363199747Smav		bzero(&cts, sizeof(cts));
364203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
365199747Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
366199747Smav		cts.type = CTS_TYPE_USER_SETTINGS;
367199747Smav		xpt_action((union ccb *)&cts);
368199747Smav		if (path->device->transport == XPORT_ATA) {
369199747Smav			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_MODE)
370199747Smav				mode = cts.xport_specific.ata.mode;
371199747Smav		} else {
372199799Smav			if (cts.xport_specific.sata.valid & CTS_SATA_VALID_MODE)
373199747Smav				mode = cts.xport_specific.sata.mode;
374199747Smav		}
375230912Smav		if (periph->path->device->protocol == PROTO_ATA) {
376230912Smav			if (ata_dma == 0 && (mode == 0 || mode > ATA_PIO_MAX))
377230912Smav				mode = ATA_PIO_MAX;
378230912Smav		} else {
379230912Smav			if (atapi_dma == 0 && (mode == 0 || mode > ATA_PIO_MAX))
380230912Smav				mode = ATA_PIO_MAX;
381230912Smav		}
382199747Smavnegotiate:
383199747Smav		/* Honor device capabilities. */
384199747Smav		wantmode = mode = ata_max_mode(ident_buf, mode);
385199747Smav		/* Report modes to SIM. */
386199747Smav		bzero(&cts, sizeof(cts));
387203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
388199747Smav		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
389199747Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
390199747Smav		if (path->device->transport == XPORT_ATA) {
391199747Smav			cts.xport_specific.ata.mode = mode;
392199747Smav			cts.xport_specific.ata.valid = CTS_ATA_VALID_MODE;
393199747Smav		} else {
394199747Smav			cts.xport_specific.sata.mode = mode;
395199747Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_MODE;
396199747Smav		}
397199747Smav		xpt_action((union ccb *)&cts);
398200171Smav		/* Fetch current modes from SIM. */
399199747Smav		bzero(&cts, sizeof(cts));
400203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
401199747Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
402199747Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
403199747Smav		xpt_action((union ccb *)&cts);
404199747Smav		if (path->device->transport == XPORT_ATA) {
405199747Smav			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_MODE)
406199747Smav				mode = cts.xport_specific.ata.mode;
407199747Smav		} else {
408199747Smav			if (cts.xport_specific.ata.valid & CTS_SATA_VALID_MODE)
409199747Smav				mode = cts.xport_specific.sata.mode;
410199747Smav		}
411199747Smav		/* If SIM disagree - renegotiate. */
412199747Smav		if (mode != wantmode)
413199747Smav			goto negotiate;
414220886Smav		/* Remember what transport thinks about DMA. */
415220886Smav		if (mode < ATA_DMA)
416220886Smav			path->device->inq_flags &= ~SID_DMA;
417220886Smav		else
418220886Smav			path->device->inq_flags |= SID_DMA;
419236393Smav		xpt_async(AC_GETDEV_CHANGED, path, NULL);
420195534Sscottl		cam_fill_ataio(ataio,
421195534Sscottl		      1,
422195534Sscottl		      probedone,
423196353Smav		      /*flags*/CAM_DIR_NONE,
424196353Smav		      0,
425196353Smav		      /*data_ptr*/NULL,
426196353Smav		      /*dxfer_len*/0,
427195534Sscottl		      30 * 1000);
428199747Smav		ata_28bit_cmd(ataio, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
429195534Sscottl		break;
430199747Smav	}
431207499Smav	case PROBE_SETPM:
432207499Smav		cam_fill_ataio(ataio,
433207499Smav		    1,
434207499Smav		    probedone,
435207499Smav		    CAM_DIR_NONE,
436207499Smav		    0,
437207499Smav		    NULL,
438207499Smav		    0,
439207499Smav		    30*1000);
440207499Smav		ata_28bit_cmd(ataio, ATA_SETFEATURES,
441207499Smav		    (softc->caps & CTS_SATA_CAPS_H_PMREQ) ? 0x10 : 0x90,
442207499Smav		    0, 0x03);
443207499Smav		break;
444207499Smav	case PROBE_SETAPST:
445207499Smav		cam_fill_ataio(ataio,
446207499Smav		    1,
447207499Smav		    probedone,
448207499Smav		    CAM_DIR_NONE,
449207499Smav		    0,
450207499Smav		    NULL,
451207499Smav		    0,
452207499Smav		    30*1000);
453207499Smav		ata_28bit_cmd(ataio, ATA_SETFEATURES,
454207499Smav		    (softc->caps & CTS_SATA_CAPS_H_APST) ? 0x10 : 0x90,
455207499Smav		    0, 0x07);
456207499Smav		break;
457207499Smav	case PROBE_SETDMAAA:
458207499Smav		cam_fill_ataio(ataio,
459207499Smav		    1,
460207499Smav		    probedone,
461207499Smav		    CAM_DIR_NONE,
462207499Smav		    0,
463207499Smav		    NULL,
464207499Smav		    0,
465207499Smav		    30*1000);
466207499Smav		ata_28bit_cmd(ataio, ATA_SETFEATURES,
467207499Smav		    (softc->caps & CTS_SATA_CAPS_H_DMAAA) ? 0x10 : 0x90,
468207499Smav		    0, 0x02);
469207499Smav		break;
470220602Smav	case PROBE_SETAN:
471238886Smav		/* Remember what transport thinks about AEN. */
472238886Smav		if (softc->caps & CTS_SATA_CAPS_H_AN)
473238886Smav			path->device->inq_flags |= SID_AEN;
474238886Smav		else
475238886Smav			path->device->inq_flags &= ~SID_AEN;
476238886Smav		xpt_async(AC_GETDEV_CHANGED, path, NULL);
477220602Smav		cam_fill_ataio(ataio,
478220602Smav		    1,
479220602Smav		    probedone,
480220602Smav		    CAM_DIR_NONE,
481220602Smav		    0,
482220602Smav		    NULL,
483220602Smav		    0,
484220602Smav		    30*1000);
485220602Smav		ata_28bit_cmd(ataio, ATA_SETFEATURES,
486220602Smav		    (softc->caps & CTS_SATA_CAPS_H_AN) ? 0x10 : 0x90,
487220602Smav		    0, 0x05);
488220602Smav		break;
489198708Smav	case PROBE_SET_MULTI:
490198708Smav	{
491200171Smav		u_int sectors, bytecount;
492198708Smav
493200171Smav		bytecount = 8192;	/* SATA maximum */
494200171Smav		/* Fetch user bytecount from SIM. */
495200171Smav		bzero(&cts, sizeof(cts));
496203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
497200171Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
498200171Smav		cts.type = CTS_TYPE_USER_SETTINGS;
499200171Smav		xpt_action((union ccb *)&cts);
500200171Smav		if (path->device->transport == XPORT_ATA) {
501200171Smav			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_BYTECOUNT)
502200171Smav				bytecount = cts.xport_specific.ata.bytecount;
503200171Smav		} else {
504200171Smav			if (cts.xport_specific.sata.valid & CTS_SATA_VALID_BYTECOUNT)
505200171Smav				bytecount = cts.xport_specific.sata.bytecount;
506200171Smav		}
507200171Smav		/* Honor device capabilities. */
508200171Smav		sectors = max(1, min(ident_buf->sectors_intr & 0xff,
509200171Smav		    bytecount / ata_logical_sector_size(ident_buf)));
510198708Smav		/* Report bytecount to SIM. */
511198708Smav		bzero(&cts, sizeof(cts));
512203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
513198708Smav		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
514198708Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
515198708Smav		if (path->device->transport == XPORT_ATA) {
516198897Smav			cts.xport_specific.ata.bytecount = sectors *
517198897Smav			    ata_logical_sector_size(ident_buf);
518198708Smav			cts.xport_specific.ata.valid = CTS_ATA_VALID_BYTECOUNT;
519198708Smav		} else {
520198897Smav			cts.xport_specific.sata.bytecount = sectors *
521198897Smav			    ata_logical_sector_size(ident_buf);
522198708Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_BYTECOUNT;
523198708Smav		}
524198708Smav		xpt_action((union ccb *)&cts);
525200171Smav		/* Fetch current bytecount from SIM. */
526200171Smav		bzero(&cts, sizeof(cts));
527203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
528200171Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
529200171Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
530200171Smav		xpt_action((union ccb *)&cts);
531200171Smav		if (path->device->transport == XPORT_ATA) {
532200171Smav			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_BYTECOUNT)
533200171Smav				bytecount = cts.xport_specific.ata.bytecount;
534200171Smav		} else {
535200171Smav			if (cts.xport_specific.sata.valid & CTS_SATA_VALID_BYTECOUNT)
536200171Smav				bytecount = cts.xport_specific.sata.bytecount;
537200171Smav		}
538200171Smav		sectors = bytecount / ata_logical_sector_size(ident_buf);
539198708Smav
540198708Smav		cam_fill_ataio(ataio,
541198708Smav		    1,
542198708Smav		    probedone,
543198708Smav		    CAM_DIR_NONE,
544198708Smav		    0,
545198708Smav		    NULL,
546198708Smav		    0,
547198708Smav		    30*1000);
548198708Smav		ata_28bit_cmd(ataio, ATA_SET_MULTI, 0, 0, sectors);
549198708Smav		break;
550195534Sscottl	}
551195534Sscottl	case PROBE_INQUIRY:
552200171Smav	{
553200171Smav		u_int bytecount;
554200171Smav
555200171Smav		bytecount = 8192;	/* SATA maximum */
556200171Smav		/* Fetch user bytecount from SIM. */
557200171Smav		bzero(&cts, sizeof(cts));
558203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
559200171Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
560200171Smav		cts.type = CTS_TYPE_USER_SETTINGS;
561200171Smav		xpt_action((union ccb *)&cts);
562200171Smav		if (path->device->transport == XPORT_ATA) {
563200171Smav			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_BYTECOUNT)
564200171Smav				bytecount = cts.xport_specific.ata.bytecount;
565200171Smav		} else {
566200171Smav			if (cts.xport_specific.sata.valid & CTS_SATA_VALID_BYTECOUNT)
567200171Smav				bytecount = cts.xport_specific.sata.bytecount;
568200171Smav		}
569200171Smav		/* Honor device capabilities. */
570200171Smav		bytecount &= ~1;
571200171Smav		bytecount = max(2, min(65534, bytecount));
572200171Smav		if (ident_buf->satacapabilities != 0x0000 &&
573200171Smav		    ident_buf->satacapabilities != 0xffff) {
574200171Smav			bytecount = min(8192, bytecount);
575200171Smav		}
576200171Smav		/* Report bytecount to SIM. */
577200171Smav		bzero(&cts, sizeof(cts));
578203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
579200171Smav		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
580200171Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
581200171Smav		if (path->device->transport == XPORT_ATA) {
582200171Smav			cts.xport_specific.ata.bytecount = bytecount;
583200171Smav			cts.xport_specific.ata.valid = CTS_ATA_VALID_BYTECOUNT;
584200171Smav		} else {
585200171Smav			cts.xport_specific.sata.bytecount = bytecount;
586200171Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_BYTECOUNT;
587200171Smav		}
588200171Smav		xpt_action((union ccb *)&cts);
589200171Smav		/* FALLTHROUGH */
590200171Smav	}
591195534Sscottl	case PROBE_FULL_INQUIRY:
592195534Sscottl	{
593195534Sscottl		u_int inquiry_len;
594195534Sscottl		struct scsi_inquiry_data *inq_buf =
595195534Sscottl		    &periph->path->device->inq_data;
596195534Sscottl
597195534Sscottl		if (softc->action == PROBE_INQUIRY)
598195534Sscottl			inquiry_len = SHORT_INQUIRY_LENGTH;
599195534Sscottl		else
600195534Sscottl			inquiry_len = SID_ADDITIONAL_LENGTH(inq_buf);
601195534Sscottl		/*
602195534Sscottl		 * Some parallel SCSI devices fail to send an
603195534Sscottl		 * ignore wide residue message when dealing with
604195534Sscottl		 * odd length inquiry requests.  Round up to be
605195534Sscottl		 * safe.
606195534Sscottl		 */
607195534Sscottl		inquiry_len = roundup2(inquiry_len, 2);
608195534Sscottl		scsi_inquiry(csio,
609195534Sscottl			     /*retries*/1,
610195534Sscottl			     probedone,
611195534Sscottl			     MSG_SIMPLE_Q_TAG,
612195534Sscottl			     (u_int8_t *)inq_buf,
613195534Sscottl			     inquiry_len,
614195534Sscottl			     /*evpd*/FALSE,
615195534Sscottl			     /*page_code*/0,
616195534Sscottl			     SSD_MIN_SIZE,
617195534Sscottl			     /*timeout*/60 * 1000);
618195534Sscottl		break;
619195534Sscottl	}
620195534Sscottl	case PROBE_PM_PID:
621195534Sscottl		cam_fill_ataio(ataio,
622195534Sscottl		      1,
623195534Sscottl		      probedone,
624195534Sscottl		      /*flags*/CAM_DIR_NONE,
625198389Smav		      0,
626195534Sscottl		      /*data_ptr*/NULL,
627195534Sscottl		      /*dxfer_len*/0,
628195534Sscottl		      10 * 1000);
629195534Sscottl		ata_pm_read_cmd(ataio, 0, 15);
630195534Sscottl		break;
631195534Sscottl	case PROBE_PM_PRV:
632195534Sscottl		cam_fill_ataio(ataio,
633195534Sscottl		      1,
634195534Sscottl		      probedone,
635195534Sscottl		      /*flags*/CAM_DIR_NONE,
636198389Smav		      0,
637195534Sscottl		      /*data_ptr*/NULL,
638195534Sscottl		      /*dxfer_len*/0,
639195534Sscottl		      10 * 1000);
640195534Sscottl		ata_pm_read_cmd(ataio, 1, 15);
641195534Sscottl		break;
642235897Smav	case PROBE_IDENTIFY_SES:
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, 0x02,
652235897Smav		    sizeof(softc->ident_data) / 4);
653235897Smav		break;
654235897Smav	case PROBE_IDENTIFY_SAFTE:
655235897Smav		cam_fill_ataio(ataio,
656235897Smav		      1,
657235897Smav		      probedone,
658235897Smav		      /*flags*/CAM_DIR_IN,
659235897Smav		      0,
660235897Smav		      /*data_ptr*/(u_int8_t *)&softc->ident_data,
661235897Smav		      /*dxfer_len*/sizeof(softc->ident_data),
662235897Smav		      30 * 1000);
663235897Smav		ata_28bit_cmd(ataio, ATA_SEP_ATTN, 0xEC, 0x00,
664235897Smav		    sizeof(softc->ident_data) / 4);
665235897Smav		break;
666195534Sscottl	default:
667236613Smav		panic("probestart: invalid action state 0x%x\n", softc->action);
668195534Sscottl	}
669195534Sscottl	xpt_action(start_ccb);
670195534Sscottl}
671236437Smav
672195534Sscottlstatic void
673195534Sscottlproberequestdefaultnegotiation(struct cam_periph *periph)
674195534Sscottl{
675195534Sscottl	struct ccb_trans_settings cts;
676195534Sscottl
677203108Smav	xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NONE);
678195534Sscottl	cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
679195534Sscottl	cts.type = CTS_TYPE_USER_SETTINGS;
680195534Sscottl	xpt_action((union ccb *)&cts);
681236437Smav	if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
682195534Sscottl		return;
683236437Smav	cts.xport_specific.valid = 0;
684195534Sscottl	cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
685195534Sscottl	cts.type = CTS_TYPE_CURRENT_SETTINGS;
686195534Sscottl	xpt_action((union ccb *)&cts);
687195534Sscottl}
688195534Sscottl
689195534Sscottlstatic void
690195534Sscottlprobedone(struct cam_periph *periph, union ccb *done_ccb)
691195534Sscottl{
692199747Smav	struct ccb_trans_settings cts;
693195534Sscottl	struct ata_params *ident_buf;
694235897Smav	struct scsi_inquiry_data *inq_buf;
695195534Sscottl	probe_softc *softc;
696195534Sscottl	struct cam_path *path;
697217444Smav	cam_status status;
698195534Sscottl	u_int32_t  priority;
699207499Smav	u_int caps;
700235897Smav	int changed = 1, found = 1;
701235897Smav	static const uint8_t fake_device_id_hdr[8] =
702235897Smav	    {0, SVPD_DEVICE_ID, 0, 12,
703235897Smav	     SVPD_ID_CODESET_BINARY, SVPD_ID_TYPE_NAA, 0, 8};
704195534Sscottl
705195534Sscottl	CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probedone\n"));
706195534Sscottl
707195534Sscottl	softc = (probe_softc *)periph->softc;
708195534Sscottl	path = done_ccb->ccb_h.path;
709195534Sscottl	priority = done_ccb->ccb_h.pinfo.priority;
710195534Sscottl	ident_buf = &path->device->ident_data;
711235897Smav	inq_buf = &path->device->inq_data;
712195534Sscottl
713198708Smav	if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
714236814Smav		if (cam_periph_error(done_ccb,
715236814Smav		    0, softc->restart ? (SF_NO_RECOVERY | SF_NO_RETRY) : 0,
716236814Smav		    NULL) == ERESTART)
717195534Sscottl			return;
718209744Smav		if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
719195534Sscottl			/* Don't wedge the queue */
720195534Sscottl			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
721195534Sscottl					 /*run_queue*/TRUE);
722195534Sscottl		}
723217444Smav		status = done_ccb->ccb_h.status & CAM_STATUS_MASK;
724209744Smav		if (softc->restart) {
725209744Smav			softc->faults++;
726209744Smav			if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) ==
727209744Smav			    CAM_CMD_TIMEOUT)
728209744Smav				softc->faults += 4;
729209744Smav			if (softc->faults < 10)
730209744Smav				goto done;
731209744Smav			else
732209744Smav				softc->restart = 0;
733217444Smav
734198708Smav		/* Old PIO2 devices may not support mode setting. */
735217444Smav		} else if (softc->action == PROBE_SETMODE &&
736217444Smav		    status == CAM_ATA_STATUS_ERROR &&
737198708Smav		    ata_max_pmode(ident_buf) <= ATA_PIO2 &&
738217444Smav		    (ident_buf->capabilities1 & ATA_SUPPORT_IORDY) == 0) {
739198708Smav			goto noerror;
740217444Smav
741198708Smav		/*
742217444Smav		 * Some old WD SATA disks report supported and enabled
743217444Smav		 * device-initiated interface power management, but return
744217444Smav		 * ABORT on attempt to disable it.
745217444Smav		 */
746217444Smav		} else if (softc->action == PROBE_SETPM &&
747217444Smav		    status == CAM_ATA_STATUS_ERROR) {
748217444Smav			goto noerror;
749217875Smav
750217875Smav		/*
751217875Smav		 * Some HP SATA disks report supported DMA Auto-Activation,
752217875Smav		 * but return ABORT on attempt to enable it.
753217875Smav		 */
754217875Smav		} else if (softc->action == PROBE_SETDMAAA &&
755217875Smav		    status == CAM_ATA_STATUS_ERROR) {
756217875Smav			goto noerror;
757235897Smav
758235897Smav		/*
759235897Smav		 * SES and SAF-TE SEPs have different IDENTIFY commands,
760235897Smav		 * but SATA specification doesn't tell how to identify them.
761235897Smav		 * Until better way found, just try another if first fail.
762235897Smav		 */
763235897Smav		} else if (softc->action == PROBE_IDENTIFY_SES &&
764235897Smav		    status == CAM_ATA_STATUS_ERROR) {
765235897Smav			PROBE_SET_ACTION(softc, PROBE_IDENTIFY_SAFTE);
766235897Smav			xpt_release_ccb(done_ccb);
767235897Smav			xpt_schedule(periph, priority);
768235897Smav			return;
769217444Smav		}
770217444Smav
771217444Smav		/*
772198708Smav		 * If we get to this point, we got an error status back
773198708Smav		 * from the inquiry and the error status doesn't require
774198708Smav		 * automatically retrying the command.  Therefore, the
775198708Smav		 * inquiry failed.  If we had inquiry information before
776198708Smav		 * for this device, but this latest inquiry command failed,
777198708Smav		 * the device has probably gone away.  If this device isn't
778198708Smav		 * already marked unconfigured, notify the peripheral
779198708Smav		 * drivers that this device is no more.
780198708Smav		 */
781209744Smavdevice_fail:	if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0)
782198708Smav			xpt_async(AC_LOST_DEVICE, path, NULL);
783236613Smav		PROBE_SET_ACTION(softc, PROBE_INVALID);
784198708Smav		found = 0;
785198708Smav		goto done;
786198708Smav	}
787198708Smavnoerror:
788203385Smav	if (softc->restart)
789203385Smav		goto done;
790198708Smav	switch (softc->action) {
791198708Smav	case PROBE_RESET:
792195534Sscottl	{
793198708Smav		int sign = (done_ccb->ataio.res.lba_high << 8) +
794198708Smav		    done_ccb->ataio.res.lba_mid;
795236613Smav		CAM_DEBUG(path, CAM_DEBUG_PROBE,
796236613Smav		    ("SIGNATURE: %04x\n", sign));
797198708Smav		if (sign == 0x0000 &&
798198708Smav		    done_ccb->ccb_h.target_id != 15) {
799198708Smav			path->device->protocol = PROTO_ATA;
800198708Smav			PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
801198708Smav		} else if (sign == 0x9669 &&
802198708Smav		    done_ccb->ccb_h.target_id == 15) {
803199747Smav			/* Report SIM that PM is present. */
804198708Smav			bzero(&cts, sizeof(cts));
805203108Smav			xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
806198708Smav			cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
807198708Smav			cts.type = CTS_TYPE_CURRENT_SETTINGS;
808198708Smav			cts.xport_specific.sata.pm_present = 1;
809198708Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_PM;
810198708Smav			xpt_action((union ccb *)&cts);
811198708Smav			path->device->protocol = PROTO_SATAPM;
812198708Smav			PROBE_SET_ACTION(softc, PROBE_PM_PID);
813235897Smav		} else if (sign == 0xc33c &&
814235897Smav		    done_ccb->ccb_h.target_id != 15) {
815235897Smav			path->device->protocol = PROTO_SEMB;
816235897Smav			PROBE_SET_ACTION(softc, PROBE_IDENTIFY_SES);
817198708Smav		} else if (sign == 0xeb14 &&
818198708Smav		    done_ccb->ccb_h.target_id != 15) {
819198708Smav			path->device->protocol = PROTO_SCSI;
820198708Smav			PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
821198708Smav		} else {
822198708Smav			if (done_ccb->ccb_h.target_id != 15) {
823198708Smav				xpt_print(path,
824198708Smav				    "Unexpected signature 0x%04x\n", sign);
825195534Sscottl			}
826198708Smav			goto device_fail;
827198708Smav		}
828198708Smav		xpt_release_ccb(done_ccb);
829198708Smav		xpt_schedule(periph, priority);
830198708Smav		return;
831198708Smav	}
832198708Smav	case PROBE_IDENTIFY:
833198708Smav	{
834207222Smav		struct ccb_pathinq cpi;
835198708Smav		int16_t *ptr;
836195534Sscottl
837203385Smav		ident_buf = &softc->ident_data;
838198708Smav		for (ptr = (int16_t *)ident_buf;
839198708Smav		     ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) {
840198708Smav			*ptr = le16toh(*ptr);
841198708Smav		}
842198708Smav		if (strncmp(ident_buf->model, "FX", 2) &&
843198708Smav		    strncmp(ident_buf->model, "NEC", 3) &&
844198708Smav		    strncmp(ident_buf->model, "Pioneer", 7) &&
845198708Smav		    strncmp(ident_buf->model, "SHARP", 5)) {
846198708Smav			ata_bswap(ident_buf->model, sizeof(ident_buf->model));
847198708Smav			ata_bswap(ident_buf->revision, sizeof(ident_buf->revision));
848198708Smav			ata_bswap(ident_buf->serial, sizeof(ident_buf->serial));
849198708Smav		}
850198708Smav		ata_btrim(ident_buf->model, sizeof(ident_buf->model));
851198708Smav		ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model));
852198708Smav		ata_btrim(ident_buf->revision, sizeof(ident_buf->revision));
853198708Smav		ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision));
854198708Smav		ata_btrim(ident_buf->serial, sizeof(ident_buf->serial));
855198708Smav		ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial));
856203421Smav		/* Device may need spin-up before IDENTIFY become valid. */
857204354Smav		if ((ident_buf->specconf == 0x37c8 ||
858204354Smav		     ident_buf->specconf == 0x738c) &&
859204354Smav		    ((ident_buf->config & ATA_RESP_INCOMPLETE) ||
860204354Smav		     softc->spinup == 0)) {
861203421Smav			PROBE_SET_ACTION(softc, PROBE_SPINUP);
862203421Smav			xpt_release_ccb(done_ccb);
863203421Smav			xpt_schedule(periph, priority);
864203421Smav			return;
865203421Smav		}
866203385Smav		ident_buf = &path->device->ident_data;
867198708Smav		if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) {
868198708Smav			/* Check that it is the same device. */
869203385Smav			if (bcmp(softc->ident_data.model, ident_buf->model,
870203385Smav			     sizeof(ident_buf->model)) ||
871203385Smav			    bcmp(softc->ident_data.revision, ident_buf->revision,
872203385Smav			     sizeof(ident_buf->revision)) ||
873203385Smav			    bcmp(softc->ident_data.serial, ident_buf->serial,
874203385Smav			     sizeof(ident_buf->serial))) {
875198708Smav				/* Device changed. */
876198708Smav				xpt_async(AC_LOST_DEVICE, path, NULL);
877207282Smav			} else {
878203385Smav				bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params));
879207282Smav				changed = 0;
880207282Smav			}
881207282Smav		}
882207282Smav		if (changed) {
883203385Smav			bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params));
884195534Sscottl			/* Clean up from previous instance of this device */
885195534Sscottl			if (path->device->serial_num != NULL) {
886195534Sscottl				free(path->device->serial_num, M_CAMXPT);
887195534Sscottl				path->device->serial_num = NULL;
888195534Sscottl				path->device->serial_num_len = 0;
889195534Sscottl			}
890235897Smav			if (path->device->device_id != NULL) {
891235897Smav				free(path->device->device_id, M_CAMXPT);
892235897Smav				path->device->device_id = NULL;
893235897Smav				path->device->device_id_len = 0;
894235897Smav			}
895195534Sscottl			path->device->serial_num =
896195534Sscottl				(u_int8_t *)malloc((sizeof(ident_buf->serial) + 1),
897198708Smav					   M_CAMXPT, M_NOWAIT);
898195534Sscottl			if (path->device->serial_num != NULL) {
899195534Sscottl				bcopy(ident_buf->serial,
900195534Sscottl				      path->device->serial_num,
901195534Sscottl				      sizeof(ident_buf->serial));
902195534Sscottl				path->device->serial_num[sizeof(ident_buf->serial)]
903195534Sscottl				    = '\0';
904195534Sscottl				path->device->serial_num_len =
905195534Sscottl				    strlen(path->device->serial_num);
906195534Sscottl			}
907235897Smav			if (ident_buf->enabled.extension &
908235897Smav			    ATA_SUPPORT_64BITWWN) {
909235897Smav				path->device->device_id =
910235897Smav				    malloc(16, M_CAMXPT, M_NOWAIT);
911235897Smav				if (path->device->device_id != NULL) {
912235897Smav					path->device->device_id_len = 16;
913235897Smav					bcopy(&fake_device_id_hdr,
914235897Smav					    path->device->device_id, 8);
915235897Smav					bcopy(ident_buf->wwn,
916235897Smav					    path->device->device_id + 8, 8);
917235897Smav				}
918235897Smav			}
919195534Sscottl
920198331Smav			path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID;
921236393Smav			xpt_async(AC_GETDEV_CHANGED, path, NULL);
922195534Sscottl		}
923199178Smav		if (ident_buf->satacapabilities & ATA_SUPPORT_NCQ) {
924236234Smav			path->device->mintags = 2;
925236234Smav			path->device->maxtags =
926199178Smav			    ATA_QUEUE_LEN(ident_buf->queue) + 1;
927199178Smav		}
928199178Smav		ata_find_quirk(path->device);
929199263Smav		if (path->device->mintags != 0 &&
930199263Smav		    path->bus->sim->max_tagged_dev_openings != 0) {
931207222Smav			/* Check if the SIM does not want queued commands. */
932207222Smav			bzero(&cpi, sizeof(cpi));
933207222Smav			xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE);
934207222Smav			cpi.ccb_h.func_code = XPT_PATH_INQ;
935207222Smav			xpt_action((union ccb *)&cpi);
936207222Smav			if (cpi.ccb_h.status == CAM_REQ_CMP &&
937207222Smav			    (cpi.hba_inquiry & PI_TAG_ABLE)) {
938207222Smav				/* Report SIM which tags are allowed. */
939207222Smav				bzero(&cts, sizeof(cts));
940207222Smav				xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
941207222Smav				cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
942207222Smav				cts.type = CTS_TYPE_CURRENT_SETTINGS;
943207222Smav				cts.xport_specific.sata.tags = path->device->maxtags;
944207222Smav				cts.xport_specific.sata.valid = CTS_SATA_VALID_TAGS;
945207222Smav				xpt_action((union ccb *)&cts);
946207222Smav			}
947199178Smav		}
948236666Smav		ata_device_transport(path);
949236437Smav		if (changed)
950236437Smav			proberequestdefaultnegotiation(periph);
951198708Smav		PROBE_SET_ACTION(softc, PROBE_SETMODE);
952195534Sscottl		xpt_release_ccb(done_ccb);
953198708Smav		xpt_schedule(periph, priority);
954198708Smav		return;
955195534Sscottl	}
956203421Smav	case PROBE_SPINUP:
957203421Smav		if (bootverbose)
958203421Smav			xpt_print(path, "Spin-up done\n");
959203421Smav		softc->spinup = 1;
960203421Smav		PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
961203421Smav		xpt_release_ccb(done_ccb);
962203421Smav		xpt_schedule(periph, priority);
963203421Smav		return;
964195534Sscottl	case PROBE_SETMODE:
965207499Smav		if (path->device->transport != XPORT_SATA)
966207499Smav			goto notsata;
967207499Smav		/* Set supported bits. */
968207499Smav		bzero(&cts, sizeof(cts));
969207499Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
970207499Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
971207499Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
972207499Smav		xpt_action((union ccb *)&cts);
973207499Smav		if (cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS)
974207499Smav			caps = cts.xport_specific.sata.caps & CTS_SATA_CAPS_H;
975207499Smav		else
976207499Smav			caps = 0;
977207499Smav		if (ident_buf->satacapabilities != 0xffff) {
978207499Smav			if (ident_buf->satacapabilities & ATA_SUPPORT_IFPWRMNGTRCV)
979207499Smav				caps |= CTS_SATA_CAPS_D_PMREQ;
980207499Smav			if (ident_buf->satacapabilities & ATA_SUPPORT_HAPST)
981207499Smav				caps |= CTS_SATA_CAPS_D_APST;
982207499Smav		}
983207499Smav		/* Mask unwanted bits. */
984207499Smav		bzero(&cts, sizeof(cts));
985207499Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
986207499Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
987207499Smav		cts.type = CTS_TYPE_USER_SETTINGS;
988207499Smav		xpt_action((union ccb *)&cts);
989207499Smav		if (cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS)
990207499Smav			caps &= cts.xport_specific.sata.caps;
991215454Smav		else
992215454Smav			caps = 0;
993207499Smav		/* Store result to SIM. */
994207499Smav		bzero(&cts, sizeof(cts));
995207499Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
996207499Smav		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
997207499Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
998207499Smav		cts.xport_specific.sata.caps = caps;
999207499Smav		cts.xport_specific.sata.valid = CTS_SATA_VALID_CAPS;
1000207499Smav		xpt_action((union ccb *)&cts);
1001207499Smav		softc->caps = caps;
1002217874Smav		if ((ident_buf->satasupport & ATA_SUPPORT_IFPWRMNGT) &&
1003217874Smav		    (!(softc->caps & CTS_SATA_CAPS_H_PMREQ)) !=
1004217874Smav		    (!(ident_buf->sataenabled & ATA_SUPPORT_IFPWRMNGT))) {
1005207499Smav			PROBE_SET_ACTION(softc, PROBE_SETPM);
1006207499Smav			xpt_release_ccb(done_ccb);
1007207499Smav			xpt_schedule(periph, priority);
1008207499Smav			return;
1009207499Smav		}
1010207499Smav		/* FALLTHROUGH */
1011207499Smav	case PROBE_SETPM:
1012207499Smav		if (ident_buf->satacapabilities != 0xffff &&
1013217874Smav		    (ident_buf->satacapabilities & ATA_SUPPORT_DAPST) &&
1014217874Smav		    (!(softc->caps & CTS_SATA_CAPS_H_APST)) !=
1015217874Smav		    (!(ident_buf->sataenabled & ATA_ENABLED_DAPST))) {
1016207499Smav			PROBE_SET_ACTION(softc, PROBE_SETAPST);
1017207499Smav			xpt_release_ccb(done_ccb);
1018207499Smav			xpt_schedule(periph, priority);
1019207499Smav			return;
1020207499Smav		}
1021207499Smav		/* FALLTHROUGH */
1022207499Smav	case PROBE_SETAPST:
1023217874Smav		if ((ident_buf->satasupport & ATA_SUPPORT_AUTOACTIVATE) &&
1024217874Smav		    (!(softc->caps & CTS_SATA_CAPS_H_DMAAA)) !=
1025217874Smav		    (!(ident_buf->sataenabled & ATA_SUPPORT_AUTOACTIVATE))) {
1026207499Smav			PROBE_SET_ACTION(softc, PROBE_SETDMAAA);
1027207499Smav			xpt_release_ccb(done_ccb);
1028207499Smav			xpt_schedule(periph, priority);
1029207499Smav			return;
1030207499Smav		}
1031207499Smav		/* FALLTHROUGH */
1032207499Smav	case PROBE_SETDMAAA:
1033220602Smav		if ((ident_buf->satasupport & ATA_SUPPORT_ASYNCNOTIF) &&
1034220602Smav		    (!(softc->caps & CTS_SATA_CAPS_H_AN)) !=
1035220602Smav		    (!(ident_buf->sataenabled & ATA_SUPPORT_ASYNCNOTIF))) {
1036220602Smav			PROBE_SET_ACTION(softc, PROBE_SETAN);
1037220602Smav			xpt_release_ccb(done_ccb);
1038220602Smav			xpt_schedule(periph, priority);
1039220602Smav			return;
1040220602Smav		}
1041220602Smav		/* FALLTHROUGH */
1042220602Smav	case PROBE_SETAN:
1043207499Smavnotsata:
1044198708Smav		if (path->device->protocol == PROTO_ATA) {
1045198708Smav			PROBE_SET_ACTION(softc, PROBE_SET_MULTI);
1046198708Smav		} else {
1047198708Smav			PROBE_SET_ACTION(softc, PROBE_INQUIRY);
1048195534Sscottl		}
1049198708Smav		xpt_release_ccb(done_ccb);
1050198708Smav		xpt_schedule(periph, priority);
1051198708Smav		return;
1052198708Smav	case PROBE_SET_MULTI:
1053198708Smav		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
1054198708Smav			path->device->flags &= ~CAM_DEV_UNCONFIGURED;
1055198748Smav			xpt_acquire_device(path->device);
1056198708Smav			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
1057198708Smav			xpt_action(done_ccb);
1058198708Smav			xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path,
1059198708Smav			    done_ccb);
1060198708Smav		}
1061236613Smav		PROBE_SET_ACTION(softc, PROBE_DONE);
1062198708Smav		break;
1063195534Sscottl	case PROBE_INQUIRY:
1064195534Sscottl	case PROBE_FULL_INQUIRY:
1065195534Sscottl	{
1066198708Smav		u_int8_t periph_qual, len;
1067195534Sscottl
1068198708Smav		path->device->flags |= CAM_DEV_INQUIRY_DATA_VALID;
1069195534Sscottl
1070198708Smav		periph_qual = SID_QUAL(inq_buf);
1071195534Sscottl
1072198708Smav		if (periph_qual != SID_QUAL_LU_CONNECTED)
1073198708Smav			break;
1074195534Sscottl
1075198708Smav		/*
1076198708Smav		 * We conservatively request only
1077198708Smav		 * SHORT_INQUIRY_LEN bytes of inquiry
1078198708Smav		 * information during our first try
1079198708Smav		 * at sending an INQUIRY. If the device
1080198708Smav		 * has more information to give,
1081198708Smav		 * perform a second request specifying
1082198708Smav		 * the amount of information the device
1083198708Smav		 * is willing to give.
1084198708Smav		 */
1085198708Smav		len = inq_buf->additional_length
1086198708Smav		    + offsetof(struct scsi_inquiry_data, additional_length) + 1;
1087198708Smav		if (softc->action == PROBE_INQUIRY
1088198708Smav		    && len > SHORT_INQUIRY_LENGTH) {
1089198708Smav			PROBE_SET_ACTION(softc, PROBE_FULL_INQUIRY);
1090198708Smav			xpt_release_ccb(done_ccb);
1091198708Smav			xpt_schedule(periph, priority);
1092195534Sscottl			return;
1093195534Sscottl		}
1094198708Smav
1095198708Smav		ata_device_transport(path);
1096198708Smav		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
1097198708Smav			path->device->flags &= ~CAM_DEV_UNCONFIGURED;
1098198748Smav			xpt_acquire_device(path->device);
1099198708Smav			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
1100198708Smav			xpt_action(done_ccb);
1101198708Smav			xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, done_ccb);
1102198708Smav		}
1103236613Smav		PROBE_SET_ACTION(softc, PROBE_DONE);
1104198708Smav		break;
1105195534Sscottl	}
1106195534Sscottl	case PROBE_PM_PID:
1107198708Smav		if ((path->device->flags & CAM_DEV_IDENTIFY_DATA_VALID) == 0)
1108198708Smav			bzero(ident_buf, sizeof(*ident_buf));
1109198708Smav		softc->pm_pid = (done_ccb->ataio.res.lba_high << 24) +
1110198708Smav		    (done_ccb->ataio.res.lba_mid << 16) +
1111198708Smav		    (done_ccb->ataio.res.lba_low << 8) +
1112198708Smav		    done_ccb->ataio.res.sector_count;
1113198708Smav		((uint32_t *)ident_buf)[0] = softc->pm_pid;
1114198708Smav		snprintf(ident_buf->model, sizeof(ident_buf->model),
1115198708Smav		    "Port Multiplier %08x", softc->pm_pid);
1116198708Smav		PROBE_SET_ACTION(softc, PROBE_PM_PRV);
1117198708Smav		xpt_release_ccb(done_ccb);
1118198708Smav		xpt_schedule(periph, priority);
1119198708Smav		return;
1120195534Sscottl	case PROBE_PM_PRV:
1121198708Smav		softc->pm_prv = (done_ccb->ataio.res.lba_high << 24) +
1122198708Smav		    (done_ccb->ataio.res.lba_mid << 16) +
1123198708Smav		    (done_ccb->ataio.res.lba_low << 8) +
1124198708Smav		    done_ccb->ataio.res.sector_count;
1125198708Smav		((uint32_t *)ident_buf)[1] = softc->pm_prv;
1126198708Smav		snprintf(ident_buf->revision, sizeof(ident_buf->revision),
1127198708Smav		    "%04x", softc->pm_prv);
1128198708Smav		path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID;
1129236666Smav		ata_device_transport(path);
1130236666Smav		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED)
1131236666Smav			proberequestdefaultnegotiation(periph);
1132207499Smav		/* Set supported bits. */
1133207499Smav		bzero(&cts, sizeof(cts));
1134207499Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
1135207499Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
1136207499Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
1137207499Smav		xpt_action((union ccb *)&cts);
1138207499Smav		if (cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS)
1139207499Smav			caps = cts.xport_specific.sata.caps & CTS_SATA_CAPS_H;
1140207499Smav		else
1141207499Smav			caps = 0;
1142207499Smav		/* All PMPs must support PM requests. */
1143207499Smav		caps |= CTS_SATA_CAPS_D_PMREQ;
1144207499Smav		/* Mask unwanted bits. */
1145207499Smav		bzero(&cts, sizeof(cts));
1146207499Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
1147207499Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
1148207499Smav		cts.type = CTS_TYPE_USER_SETTINGS;
1149207499Smav		xpt_action((union ccb *)&cts);
1150207499Smav		if (cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS)
1151207499Smav			caps &= cts.xport_specific.sata.caps;
1152215454Smav		else
1153215454Smav			caps = 0;
1154207499Smav		/* Store result to SIM. */
1155207499Smav		bzero(&cts, sizeof(cts));
1156207499Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
1157207499Smav		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
1158207499Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
1159207499Smav		cts.xport_specific.sata.caps = caps;
1160207499Smav		cts.xport_specific.sata.valid = CTS_SATA_VALID_CAPS;
1161207499Smav		xpt_action((union ccb *)&cts);
1162207499Smav		softc->caps = caps;
1163238886Smav		/* Remember what transport thinks about AEN. */
1164238886Smav		if (softc->caps & CTS_SATA_CAPS_H_AN)
1165238886Smav			path->device->inq_flags |= SID_AEN;
1166238886Smav		else
1167238886Smav			path->device->inq_flags &= ~SID_AEN;
1168238886Smav		xpt_async(AC_GETDEV_CHANGED, path, NULL);
1169198708Smav		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
1170198708Smav			path->device->flags &= ~CAM_DEV_UNCONFIGURED;
1171198748Smav			xpt_acquire_device(path->device);
1172198708Smav			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
1173198708Smav			xpt_action(done_ccb);
1174198708Smav			xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path,
1175198708Smav			    done_ccb);
1176198708Smav		} else {
1177198708Smav			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
1178198708Smav			xpt_action(done_ccb);
1179198708Smav			xpt_async(AC_SCSI_AEN, done_ccb->ccb_h.path, done_ccb);
1180195534Sscottl		}
1181236613Smav		PROBE_SET_ACTION(softc, PROBE_DONE);
1182198708Smav		break;
1183235897Smav	case PROBE_IDENTIFY_SES:
1184235897Smav	case PROBE_IDENTIFY_SAFTE:
1185235897Smav		if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) {
1186235897Smav			/* Check that it is the same device. */
1187235897Smav			if (bcmp(&softc->ident_data, ident_buf, 53)) {
1188235897Smav				/* Device changed. */
1189235897Smav				xpt_async(AC_LOST_DEVICE, path, NULL);
1190235897Smav			} else {
1191235897Smav				bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params));
1192235897Smav				changed = 0;
1193235897Smav			}
1194235897Smav		}
1195235897Smav		if (changed) {
1196235897Smav			bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params));
1197235897Smav			/* Clean up from previous instance of this device */
1198235897Smav			if (path->device->device_id != NULL) {
1199235897Smav				free(path->device->device_id, M_CAMXPT);
1200235897Smav				path->device->device_id = NULL;
1201235897Smav				path->device->device_id_len = 0;
1202235897Smav			}
1203235897Smav			path->device->device_id =
1204235897Smav			    malloc(16, M_CAMXPT, M_NOWAIT);
1205235897Smav			if (path->device->device_id != NULL) {
1206235897Smav				path->device->device_id_len = 16;
1207235897Smav				bcopy(&fake_device_id_hdr,
1208235897Smav				    path->device->device_id, 8);
1209235897Smav				bcopy(((uint8_t*)ident_buf) + 2,
1210235897Smav				    path->device->device_id + 8, 8);
1211235897Smav			}
1212235897Smav
1213235897Smav			path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID;
1214235897Smav		}
1215236666Smav		ata_device_transport(path);
1216236666Smav		if (changed)
1217236666Smav			proberequestdefaultnegotiation(periph);
1218235897Smav
1219235897Smav		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
1220235897Smav			path->device->flags &= ~CAM_DEV_UNCONFIGURED;
1221235897Smav			xpt_acquire_device(path->device);
1222235897Smav			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
1223235897Smav			xpt_action(done_ccb);
1224235897Smav			xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path,
1225235897Smav			    done_ccb);
1226235897Smav		}
1227236613Smav		PROBE_SET_ACTION(softc, PROBE_DONE);
1228235897Smav		break;
1229195534Sscottl	default:
1230236613Smav		panic("probedone: invalid action state 0x%x\n", softc->action);
1231195534Sscottl	}
1232198708Smavdone:
1233203108Smav	if (softc->restart) {
1234203108Smav		softc->restart = 0;
1235203108Smav		xpt_release_ccb(done_ccb);
1236195534Sscottl		probeschedule(periph);
1237203108Smav		return;
1238195534Sscottl	}
1239203108Smav	xpt_release_ccb(done_ccb);
1240236613Smav	CAM_DEBUG(periph->path, CAM_DEBUG_PROBE, ("Probe completed\n"));
1241203108Smav	while ((done_ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs))) {
1242203108Smav		TAILQ_REMOVE(&softc->request_ccbs,
1243203108Smav		    &done_ccb->ccb_h, periph_links.tqe);
1244203108Smav		done_ccb->ccb_h.status = found ? CAM_REQ_CMP : CAM_REQ_CMP_ERR;
1245203108Smav		xpt_done(done_ccb);
1246203108Smav	}
1247236228Smav	cam_periph_invalidate(periph);
1248203108Smav	cam_release_devq(periph->path,
1249203108Smav	    RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_XPT + 1, FALSE);
1250203108Smav	cam_periph_release_locked(periph);
1251195534Sscottl}
1252195534Sscottl
1253195534Sscottlstatic void
1254195534Sscottlprobecleanup(struct cam_periph *periph)
1255195534Sscottl{
1256195534Sscottl	free(periph->softc, M_CAMXPT);
1257195534Sscottl}
1258195534Sscottl
1259195534Sscottlstatic void
1260199178Smavata_find_quirk(struct cam_ed *device)
1261195534Sscottl{
1262199178Smav	struct ata_quirk_entry *quirk;
1263195534Sscottl	caddr_t	match;
1264195534Sscottl
1265199178Smav	match = cam_quirkmatch((caddr_t)&device->ident_data,
1266199178Smav			       (caddr_t)ata_quirk_table,
1267199178Smav			       ata_quirk_table_size,
1268199178Smav			       sizeof(*ata_quirk_table), ata_identify_match);
1269195534Sscottl
1270195534Sscottl	if (match == NULL)
1271195534Sscottl		panic("xpt_find_quirk: device didn't match wildcard entry!!");
1272195534Sscottl
1273199178Smav	quirk = (struct ata_quirk_entry *)match;
1274195534Sscottl	device->quirk = quirk;
1275236234Smav	if (quirk->quirks & CAM_QUIRK_MAXTAGS) {
1276236234Smav		device->mintags = quirk->mintags;
1277236234Smav		device->maxtags = quirk->maxtags;
1278236234Smav	}
1279195534Sscottl}
1280195534Sscottl
1281195534Sscottltypedef struct {
1282195534Sscottl	union	ccb *request_ccb;
1283195534Sscottl	struct 	ccb_pathinq *cpi;
1284195534Sscottl	int	counter;
1285195534Sscottl} ata_scan_bus_info;
1286195534Sscottl
1287195534Sscottl/*
1288195534Sscottl * To start a scan, request_ccb is an XPT_SCAN_BUS ccb.
1289195534Sscottl * As the scan progresses, xpt_scan_bus is used as the
1290195534Sscottl * callback on completion function.
1291195534Sscottl */
1292195534Sscottlstatic void
1293195534Sscottlata_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
1294195534Sscottl{
1295195534Sscottl	struct	cam_path *path;
1296195534Sscottl	ata_scan_bus_info *scan_info;
1297203108Smav	union	ccb *work_ccb, *reset_ccb;
1298195534Sscottl	cam_status status;
1299195534Sscottl
1300195534Sscottl	CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE,
1301195534Sscottl		  ("xpt_scan_bus\n"));
1302195534Sscottl	switch (request_ccb->ccb_h.func_code) {
1303195534Sscottl	case XPT_SCAN_BUS:
1304208582Smjacob	case XPT_SCAN_TGT:
1305195534Sscottl		/* Find out the characteristics of the bus */
1306195534Sscottl		work_ccb = xpt_alloc_ccb_nowait();
1307195534Sscottl		if (work_ccb == NULL) {
1308195534Sscottl			request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1309195534Sscottl			xpt_done(request_ccb);
1310195534Sscottl			return;
1311195534Sscottl		}
1312195534Sscottl		xpt_setup_ccb(&work_ccb->ccb_h, request_ccb->ccb_h.path,
1313195534Sscottl			      request_ccb->ccb_h.pinfo.priority);
1314195534Sscottl		work_ccb->ccb_h.func_code = XPT_PATH_INQ;
1315195534Sscottl		xpt_action(work_ccb);
1316195534Sscottl		if (work_ccb->ccb_h.status != CAM_REQ_CMP) {
1317195534Sscottl			request_ccb->ccb_h.status = work_ccb->ccb_h.status;
1318195534Sscottl			xpt_free_ccb(work_ccb);
1319195534Sscottl			xpt_done(request_ccb);
1320195534Sscottl			return;
1321195534Sscottl		}
1322195534Sscottl
1323203108Smav		/* We may need to reset bus first, if we haven't done it yet. */
1324203108Smav		if ((work_ccb->cpi.hba_inquiry &
1325203108Smav		    (PI_WIDE_32|PI_WIDE_16|PI_SDTR_ABLE)) &&
1326203108Smav		    !(work_ccb->cpi.hba_misc & PIM_NOBUSRESET) &&
1327203108Smav		    !timevalisset(&request_ccb->ccb_h.path->bus->last_reset)) {
1328203108Smav			reset_ccb = xpt_alloc_ccb_nowait();
1329208823Smav			if (reset_ccb == NULL) {
1330208823Smav				request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1331208823Smav				xpt_free_ccb(work_ccb);
1332208823Smav				xpt_done(request_ccb);
1333208823Smav				return;
1334208823Smav			}
1335203108Smav			xpt_setup_ccb(&reset_ccb->ccb_h, request_ccb->ccb_h.path,
1336203108Smav			      CAM_PRIORITY_NONE);
1337203108Smav			reset_ccb->ccb_h.func_code = XPT_RESET_BUS;
1338203108Smav			xpt_action(reset_ccb);
1339203108Smav			if (reset_ccb->ccb_h.status != CAM_REQ_CMP) {
1340203108Smav				request_ccb->ccb_h.status = reset_ccb->ccb_h.status;
1341203108Smav				xpt_free_ccb(reset_ccb);
1342203108Smav				xpt_free_ccb(work_ccb);
1343203108Smav				xpt_done(request_ccb);
1344203108Smav				return;
1345203108Smav			}
1346203108Smav			xpt_free_ccb(reset_ccb);
1347203108Smav		}
1348203108Smav
1349195534Sscottl		/* Save some state for use while we probe for devices */
1350195534Sscottl		scan_info = (ata_scan_bus_info *)
1351195534Sscottl		    malloc(sizeof(ata_scan_bus_info), M_CAMXPT, M_NOWAIT);
1352195534Sscottl		if (scan_info == NULL) {
1353195534Sscottl			request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1354208823Smav			xpt_free_ccb(work_ccb);
1355195534Sscottl			xpt_done(request_ccb);
1356195534Sscottl			return;
1357195534Sscottl		}
1358195534Sscottl		scan_info->request_ccb = request_ccb;
1359195534Sscottl		scan_info->cpi = &work_ccb->cpi;
1360195534Sscottl		/* If PM supported, probe it first. */
1361195534Sscottl		if (scan_info->cpi->hba_inquiry & PI_SATAPM)
1362201990Smav			scan_info->counter = scan_info->cpi->max_target;
1363201990Smav		else
1364201990Smav			scan_info->counter = 0;
1365195534Sscottl
1366195534Sscottl		work_ccb = xpt_alloc_ccb_nowait();
1367195534Sscottl		if (work_ccb == NULL) {
1368195534Sscottl			free(scan_info, M_CAMXPT);
1369195534Sscottl			request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1370195534Sscottl			xpt_done(request_ccb);
1371195534Sscottl			break;
1372195534Sscottl		}
1373195534Sscottl		goto scan_next;
1374195534Sscottl	case XPT_SCAN_LUN:
1375195534Sscottl		work_ccb = request_ccb;
1376195534Sscottl		/* Reuse the same CCB to query if a device was really found */
1377195534Sscottl		scan_info = (ata_scan_bus_info *)work_ccb->ccb_h.ppriv_ptr0;
1378198389Smav		/* If there is PMP... */
1379201990Smav		if ((scan_info->cpi->hba_inquiry & PI_SATAPM) &&
1380201990Smav		    (scan_info->counter == scan_info->cpi->max_target)) {
1381203108Smav			if (work_ccb->ccb_h.status == CAM_REQ_CMP) {
1382207428Smav				/* everything else will be probed by it */
1383207428Smav				/* Free the current request path- we're done with it. */
1384207428Smav				xpt_free_path(work_ccb->ccb_h.path);
1385201990Smav				goto done;
1386195534Sscottl			} else {
1387195534Sscottl				struct ccb_trans_settings cts;
1388195534Sscottl
1389195534Sscottl				/* Report SIM that PM is absent. */
1390195534Sscottl				bzero(&cts, sizeof(cts));
1391195534Sscottl				xpt_setup_ccb(&cts.ccb_h,
1392207428Smav				    work_ccb->ccb_h.path, CAM_PRIORITY_NONE);
1393195534Sscottl				cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
1394195534Sscottl				cts.type = CTS_TYPE_CURRENT_SETTINGS;
1395195665Smav				cts.xport_specific.sata.pm_present = 0;
1396195534Sscottl				cts.xport_specific.sata.valid = CTS_SATA_VALID_PM;
1397195534Sscottl				xpt_action((union ccb *)&cts);
1398195534Sscottl			}
1399195534Sscottl		}
1400207428Smav		/* Free the current request path- we're done with it. */
1401207428Smav		xpt_free_path(work_ccb->ccb_h.path);
1402201990Smav		if (scan_info->counter ==
1403201990Smav		    ((scan_info->cpi->hba_inquiry & PI_SATAPM) ?
1404201990Smav		    0 : scan_info->cpi->max_target)) {
1405201990Smavdone:
1406195534Sscottl			xpt_free_ccb(work_ccb);
1407195534Sscottl			xpt_free_ccb((union ccb *)scan_info->cpi);
1408195534Sscottl			request_ccb = scan_info->request_ccb;
1409195534Sscottl			free(scan_info, M_CAMXPT);
1410195534Sscottl			request_ccb->ccb_h.status = CAM_REQ_CMP;
1411195534Sscottl			xpt_done(request_ccb);
1412195534Sscottl			break;
1413195534Sscottl		}
1414201990Smav		/* Take next device. Wrap from max (PMP) to 0. */
1415201990Smav		scan_info->counter = (scan_info->counter + 1 ) %
1416201990Smav		    (scan_info->cpi->max_target + 1);
1417195534Sscottlscan_next:
1418195534Sscottl		status = xpt_create_path(&path, xpt_periph,
1419195534Sscottl		    scan_info->request_ccb->ccb_h.path_id,
1420195534Sscottl		    scan_info->counter, 0);
1421195534Sscottl		if (status != CAM_REQ_CMP) {
1422195534Sscottl			printf("xpt_scan_bus: xpt_create_path failed"
1423195534Sscottl			    " with status %#x, bus scan halted\n",
1424195534Sscottl			    status);
1425195534Sscottl			xpt_free_ccb(work_ccb);
1426195534Sscottl			xpt_free_ccb((union ccb *)scan_info->cpi);
1427195534Sscottl			request_ccb = scan_info->request_ccb;
1428195534Sscottl			free(scan_info, M_CAMXPT);
1429195534Sscottl			request_ccb->ccb_h.status = status;
1430195534Sscottl			xpt_done(request_ccb);
1431195534Sscottl			break;
1432195534Sscottl		}
1433195534Sscottl		xpt_setup_ccb(&work_ccb->ccb_h, path,
1434195534Sscottl		    scan_info->request_ccb->ccb_h.pinfo.priority);
1435195534Sscottl		work_ccb->ccb_h.func_code = XPT_SCAN_LUN;
1436195534Sscottl		work_ccb->ccb_h.cbfcnp = ata_scan_bus;
1437195534Sscottl		work_ccb->ccb_h.ppriv_ptr0 = scan_info;
1438195534Sscottl		work_ccb->crcn.flags = scan_info->request_ccb->crcn.flags;
1439195534Sscottl		xpt_action(work_ccb);
1440195534Sscottl		break;
1441195534Sscottl	default:
1442195534Sscottl		break;
1443195534Sscottl	}
1444195534Sscottl}
1445195534Sscottl
1446195534Sscottlstatic void
1447195534Sscottlata_scan_lun(struct cam_periph *periph, struct cam_path *path,
1448195534Sscottl	     cam_flags flags, union ccb *request_ccb)
1449195534Sscottl{
1450195534Sscottl	struct ccb_pathinq cpi;
1451195534Sscottl	cam_status status;
1452195534Sscottl	struct cam_path *new_path;
1453195534Sscottl	struct cam_periph *old_periph;
1454195534Sscottl
1455203108Smav	CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_scan_lun\n"));
1456195534Sscottl
1457203108Smav	xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE);
1458195534Sscottl	cpi.ccb_h.func_code = XPT_PATH_INQ;
1459195534Sscottl	xpt_action((union ccb *)&cpi);
1460195534Sscottl
1461195534Sscottl	if (cpi.ccb_h.status != CAM_REQ_CMP) {
1462195534Sscottl		if (request_ccb != NULL) {
1463195534Sscottl			request_ccb->ccb_h.status = cpi.ccb_h.status;
1464195534Sscottl			xpt_done(request_ccb);
1465195534Sscottl		}
1466195534Sscottl		return;
1467195534Sscottl	}
1468195534Sscottl
1469195534Sscottl	if (request_ccb == NULL) {
1470195534Sscottl		request_ccb = malloc(sizeof(union ccb), M_CAMXPT, M_NOWAIT);
1471195534Sscottl		if (request_ccb == NULL) {
1472195534Sscottl			xpt_print(path, "xpt_scan_lun: can't allocate CCB, "
1473195534Sscottl			    "can't continue\n");
1474195534Sscottl			return;
1475195534Sscottl		}
1476195534Sscottl		new_path = malloc(sizeof(*new_path), M_CAMXPT, M_NOWAIT);
1477195534Sscottl		if (new_path == NULL) {
1478195534Sscottl			xpt_print(path, "xpt_scan_lun: can't allocate path, "
1479195534Sscottl			    "can't continue\n");
1480195534Sscottl			free(request_ccb, M_CAMXPT);
1481195534Sscottl			return;
1482195534Sscottl		}
1483195534Sscottl		status = xpt_compile_path(new_path, xpt_periph,
1484195534Sscottl					  path->bus->path_id,
1485195534Sscottl					  path->target->target_id,
1486195534Sscottl					  path->device->lun_id);
1487195534Sscottl
1488195534Sscottl		if (status != CAM_REQ_CMP) {
1489195534Sscottl			xpt_print(path, "xpt_scan_lun: can't compile path, "
1490195534Sscottl			    "can't continue\n");
1491195534Sscottl			free(request_ccb, M_CAMXPT);
1492195534Sscottl			free(new_path, M_CAMXPT);
1493195534Sscottl			return;
1494195534Sscottl		}
1495203108Smav		xpt_setup_ccb(&request_ccb->ccb_h, new_path, CAM_PRIORITY_XPT);
1496195534Sscottl		request_ccb->ccb_h.cbfcnp = xptscandone;
1497195534Sscottl		request_ccb->ccb_h.func_code = XPT_SCAN_LUN;
1498195534Sscottl		request_ccb->crcn.flags = flags;
1499195534Sscottl	}
1500195534Sscottl
1501195653Smav	if ((old_periph = cam_periph_find(path, "aprobe")) != NULL) {
1502236228Smav		if ((old_periph->flags & CAM_PERIPH_INVALID) == 0) {
1503236228Smav			probe_softc *softc;
1504195534Sscottl
1505236228Smav			softc = (probe_softc *)old_periph->softc;
1506236228Smav			TAILQ_INSERT_TAIL(&softc->request_ccbs,
1507236228Smav				&request_ccb->ccb_h, periph_links.tqe);
1508236228Smav			softc->restart = 1;
1509236228Smav		} else {
1510236228Smav			request_ccb->ccb_h.status = CAM_REQ_CMP_ERR;
1511236228Smav			xpt_done(request_ccb);
1512236228Smav		}
1513195534Sscottl	} else {
1514195534Sscottl		status = cam_periph_alloc(proberegister, NULL, probecleanup,
1515195653Smav					  probestart, "aprobe",
1516195534Sscottl					  CAM_PERIPH_BIO,
1517195534Sscottl					  request_ccb->ccb_h.path, NULL, 0,
1518195534Sscottl					  request_ccb);
1519195534Sscottl
1520195534Sscottl		if (status != CAM_REQ_CMP) {
1521195534Sscottl			xpt_print(path, "xpt_scan_lun: cam_alloc_periph "
1522195534Sscottl			    "returned an error, can't continue probe\n");
1523195534Sscottl			request_ccb->ccb_h.status = status;
1524195534Sscottl			xpt_done(request_ccb);
1525195534Sscottl		}
1526195534Sscottl	}
1527195534Sscottl}
1528195534Sscottl
1529195534Sscottlstatic void
1530195534Sscottlxptscandone(struct cam_periph *periph, union ccb *done_ccb)
1531195534Sscottl{
1532195534Sscottl	xpt_release_path(done_ccb->ccb_h.path);
1533195534Sscottl	free(done_ccb->ccb_h.path, M_CAMXPT);
1534195534Sscottl	free(done_ccb, M_CAMXPT);
1535195534Sscottl}
1536195534Sscottl
1537195534Sscottlstatic struct cam_ed *
1538195534Sscottlata_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id)
1539195534Sscottl{
1540195534Sscottl	struct cam_path path;
1541199178Smav	struct ata_quirk_entry *quirk;
1542195534Sscottl	struct cam_ed *device;
1543195534Sscottl	struct cam_ed *cur_device;
1544195534Sscottl
1545195534Sscottl	device = xpt_alloc_device(bus, target, lun_id);
1546195534Sscottl	if (device == NULL)
1547195534Sscottl		return (NULL);
1548195534Sscottl
1549195534Sscottl	/*
1550195534Sscottl	 * Take the default quirk entry until we have inquiry
1551195534Sscottl	 * data and can determine a better quirk to use.
1552195534Sscottl	 */
1553199178Smav	quirk = &ata_quirk_table[ata_quirk_table_size - 1];
1554195534Sscottl	device->quirk = (void *)quirk;
1555199178Smav	device->mintags = 0;
1556199178Smav	device->maxtags = 0;
1557195534Sscottl	bzero(&device->inq_data, sizeof(device->inq_data));
1558195534Sscottl	device->inq_flags = 0;
1559195534Sscottl	device->queue_flags = 0;
1560195534Sscottl	device->serial_num = NULL;
1561195534Sscottl	device->serial_num_len = 0;
1562195534Sscottl
1563195534Sscottl	/*
1564195534Sscottl	 * XXX should be limited by number of CCBs this bus can
1565195534Sscottl	 * do.
1566195534Sscottl	 */
1567195534Sscottl	bus->sim->max_ccbs += device->ccbq.devq_openings;
1568195534Sscottl	/* Insertion sort into our target's device list */
1569195534Sscottl	cur_device = TAILQ_FIRST(&target->ed_entries);
1570195534Sscottl	while (cur_device != NULL && cur_device->lun_id < lun_id)
1571195534Sscottl		cur_device = TAILQ_NEXT(cur_device, links);
1572195534Sscottl	if (cur_device != NULL) {
1573195534Sscottl		TAILQ_INSERT_BEFORE(cur_device, device, links);
1574195534Sscottl	} else {
1575195534Sscottl		TAILQ_INSERT_TAIL(&target->ed_entries, device, links);
1576195534Sscottl	}
1577195534Sscottl	target->generation++;
1578195534Sscottl	if (lun_id != CAM_LUN_WILDCARD) {
1579195534Sscottl		xpt_compile_path(&path,
1580195534Sscottl				 NULL,
1581195534Sscottl				 bus->path_id,
1582195534Sscottl				 target->target_id,
1583195534Sscottl				 lun_id);
1584195534Sscottl		ata_device_transport(&path);
1585195534Sscottl		xpt_release_path(&path);
1586195534Sscottl	}
1587195534Sscottl
1588195534Sscottl	return (device);
1589195534Sscottl}
1590195534Sscottl
1591195534Sscottlstatic void
1592195534Sscottlata_device_transport(struct cam_path *path)
1593195534Sscottl{
1594195534Sscottl	struct ccb_pathinq cpi;
1595198331Smav	struct ccb_trans_settings cts;
1596198331Smav	struct scsi_inquiry_data *inq_buf = NULL;
1597198331Smav	struct ata_params *ident_buf = NULL;
1598195534Sscottl
1599195534Sscottl	/* Get transport information from the SIM */
1600203108Smav	xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE);
1601195534Sscottl	cpi.ccb_h.func_code = XPT_PATH_INQ;
1602195534Sscottl	xpt_action((union ccb *)&cpi);
1603195534Sscottl
1604195534Sscottl	path->device->transport = cpi.transport;
1605198331Smav	if ((path->device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0)
1606198331Smav		inq_buf = &path->device->inq_data;
1607198331Smav	if ((path->device->flags & CAM_DEV_IDENTIFY_DATA_VALID) != 0)
1608198331Smav		ident_buf = &path->device->ident_data;
1609198331Smav	if (path->device->protocol == PROTO_ATA) {
1610198331Smav		path->device->protocol_version = ident_buf ?
1611198331Smav		    ata_version(ident_buf->version_major) : cpi.protocol_version;
1612198331Smav	} else if (path->device->protocol == PROTO_SCSI) {
1613198331Smav		path->device->protocol_version = inq_buf ?
1614198331Smav		    SID_ANSI_REV(inq_buf) : cpi.protocol_version;
1615195534Sscottl	}
1616198331Smav	path->device->transport_version = ident_buf ?
1617198331Smav	    ata_version(ident_buf->version_major) : cpi.transport_version;
1618195534Sscottl
1619195534Sscottl	/* Tell the controller what we think */
1620203108Smav	xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
1621195534Sscottl	cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
1622195534Sscottl	cts.type = CTS_TYPE_CURRENT_SETTINGS;
1623195534Sscottl	cts.transport = path->device->transport;
1624195534Sscottl	cts.transport_version = path->device->transport_version;
1625195534Sscottl	cts.protocol = path->device->protocol;
1626195534Sscottl	cts.protocol_version = path->device->protocol_version;
1627195534Sscottl	cts.proto_specific.valid = 0;
1628203376Smav	if (ident_buf) {
1629203376Smav		if (path->device->transport == XPORT_ATA) {
1630223019Smav			cts.xport_specific.ata.atapi =
1631223019Smav			    (ident_buf->config == ATA_PROTO_CFA) ? 0 :
1632203376Smav			    ((ident_buf->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_16) ? 16 :
1633203376Smav			    ((ident_buf->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12) ? 12 : 0;
1634203376Smav			cts.xport_specific.ata.valid = CTS_ATA_VALID_ATAPI;
1635203376Smav		} else {
1636223019Smav			cts.xport_specific.sata.atapi =
1637223019Smav			    (ident_buf->config == ATA_PROTO_CFA) ? 0 :
1638203376Smav			    ((ident_buf->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_16) ? 16 :
1639203376Smav			    ((ident_buf->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12) ? 12 : 0;
1640203376Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_ATAPI;
1641203376Smav		}
1642203376Smav	} else
1643203376Smav		cts.xport_specific.valid = 0;
1644195534Sscottl	xpt_action((union ccb *)&cts);
1645195534Sscottl}
1646195534Sscottl
1647195534Sscottlstatic void
1648223443Swillata_dev_advinfo(union ccb *start_ccb)
1649223443Swill{
1650223443Swill	struct cam_ed *device;
1651223443Swill	struct ccb_dev_advinfo *cdai;
1652223443Swill	off_t amt;
1653223443Swill
1654223443Swill	start_ccb->ccb_h.status = CAM_REQ_INVALID;
1655223443Swill	device = start_ccb->ccb_h.path->device;
1656223443Swill	cdai = &start_ccb->cdai;
1657223443Swill	switch(cdai->buftype) {
1658235897Smav	case CDAI_TYPE_SCSI_DEVID:
1659235897Smav		if (cdai->flags & CDAI_FLAG_STORE)
1660235897Smav			return;
1661235897Smav		cdai->provsiz = device->device_id_len;
1662235897Smav		if (device->device_id_len == 0)
1663235897Smav			break;
1664235897Smav		amt = device->device_id_len;
1665235897Smav		if (cdai->provsiz > cdai->bufsiz)
1666235897Smav			amt = cdai->bufsiz;
1667235897Smav		memcpy(cdai->buf, device->device_id, amt);
1668235897Smav		break;
1669223443Swill	case CDAI_TYPE_SERIAL_NUM:
1670223443Swill		if (cdai->flags & CDAI_FLAG_STORE)
1671235897Smav			return;
1672223443Swill		cdai->provsiz = device->serial_num_len;
1673223443Swill		if (device->serial_num_len == 0)
1674223443Swill			break;
1675223443Swill		amt = device->serial_num_len;
1676223443Swill		if (cdai->provsiz > cdai->bufsiz)
1677223443Swill			amt = cdai->bufsiz;
1678223443Swill		memcpy(cdai->buf, device->serial_num, amt);
1679223443Swill		break;
1680235897Smav	case CDAI_TYPE_PHYS_PATH:
1681235897Smav		if (cdai->flags & CDAI_FLAG_STORE) {
1682235897Smav			if (device->physpath != NULL)
1683235897Smav				free(device->physpath, M_CAMXPT);
1684235897Smav			device->physpath_len = cdai->bufsiz;
1685235897Smav			/* Clear existing buffer if zero length */
1686235897Smav			if (cdai->bufsiz == 0)
1687235897Smav				break;
1688235897Smav			device->physpath = malloc(cdai->bufsiz, M_CAMXPT, M_NOWAIT);
1689235897Smav			if (device->physpath == NULL) {
1690235897Smav				start_ccb->ccb_h.status = CAM_REQ_ABORTED;
1691235897Smav				return;
1692235897Smav			}
1693235897Smav			memcpy(device->physpath, cdai->buf, cdai->bufsiz);
1694235897Smav		} else {
1695235897Smav			cdai->provsiz = device->physpath_len;
1696235897Smav			if (device->physpath_len == 0)
1697235897Smav				break;
1698235897Smav			amt = device->physpath_len;
1699235897Smav			if (cdai->provsiz > cdai->bufsiz)
1700235897Smav				amt = cdai->bufsiz;
1701235897Smav			memcpy(cdai->buf, device->physpath, amt);
1702235897Smav		}
1703235897Smav		break;
1704223443Swill	default:
1705235897Smav		return;
1706223443Swill	}
1707235897Smav	start_ccb->ccb_h.status = CAM_REQ_CMP;
1708235897Smav
1709235897Smav	if (cdai->flags & CDAI_FLAG_STORE) {
1710235897Smav		int owned;
1711235897Smav
1712235897Smav		owned = mtx_owned(start_ccb->ccb_h.path->bus->sim->mtx);
1713235897Smav		if (owned == 0)
1714235897Smav			mtx_lock(start_ccb->ccb_h.path->bus->sim->mtx);
1715235897Smav		xpt_async(AC_ADVINFO_CHANGED, start_ccb->ccb_h.path,
1716235897Smav			  (void *)(uintptr_t)cdai->buftype);
1717235897Smav		if (owned == 0)
1718235897Smav			mtx_unlock(start_ccb->ccb_h.path->bus->sim->mtx);
1719235897Smav	}
1720223443Swill}
1721223443Swill
1722223443Swillstatic void
1723195534Sscottlata_action(union ccb *start_ccb)
1724195534Sscottl{
1725195534Sscottl
1726195534Sscottl	switch (start_ccb->ccb_h.func_code) {
1727195534Sscottl	case XPT_SET_TRAN_SETTINGS:
1728195534Sscottl	{
1729199178Smav		ata_set_transfer_settings(&start_ccb->cts,
1730195534Sscottl					   start_ccb->ccb_h.path->device,
1731195534Sscottl					   /*async_update*/FALSE);
1732195534Sscottl		break;
1733195534Sscottl	}
1734195534Sscottl	case XPT_SCAN_BUS:
1735208582Smjacob	case XPT_SCAN_TGT:
1736195534Sscottl		ata_scan_bus(start_ccb->ccb_h.path->periph, start_ccb);
1737195534Sscottl		break;
1738195534Sscottl	case XPT_SCAN_LUN:
1739195534Sscottl		ata_scan_lun(start_ccb->ccb_h.path->periph,
1740195534Sscottl			      start_ccb->ccb_h.path, start_ccb->crcn.flags,
1741195534Sscottl			      start_ccb);
1742195534Sscottl		break;
1743195534Sscottl	case XPT_GET_TRAN_SETTINGS:
1744195534Sscottl	{
1745236437Smav		ata_get_transfer_settings(&start_ccb->cts);
1746195534Sscottl		break;
1747195534Sscottl	}
1748203376Smav	case XPT_SCSI_IO:
1749203376Smav	{
1750203376Smav		struct cam_ed *device;
1751203376Smav		u_int	maxlen = 0;
1752203376Smav
1753203376Smav		device = start_ccb->ccb_h.path->device;
1754203376Smav		if (device->protocol == PROTO_SCSI &&
1755203376Smav		    (device->flags & CAM_DEV_IDENTIFY_DATA_VALID)) {
1756203376Smav			uint16_t p =
1757203376Smav			    device->ident_data.config & ATA_PROTO_MASK;
1758203376Smav
1759223019Smav			maxlen =
1760223019Smav			    (device->ident_data.config == ATA_PROTO_CFA) ? 0 :
1761223019Smav			    (p == ATA_PROTO_ATAPI_16) ? 16 :
1762203376Smav			    (p == ATA_PROTO_ATAPI_12) ? 12 : 0;
1763203376Smav		}
1764203376Smav		if (start_ccb->csio.cdb_len > maxlen) {
1765203376Smav			start_ccb->ccb_h.status = CAM_REQ_INVALID;
1766203376Smav			xpt_done(start_ccb);
1767203376Smav			break;
1768203376Smav		}
1769223475Smav		xpt_action_default(start_ccb);
1770223475Smav		break;
1771203376Smav	}
1772223443Swill	case XPT_DEV_ADVINFO:
1773223443Swill	{
1774223443Swill		ata_dev_advinfo(start_ccb);
1775223443Swill		break;
1776223443Swill	}
1777195534Sscottl	default:
1778195534Sscottl		xpt_action_default(start_ccb);
1779195534Sscottl		break;
1780195534Sscottl	}
1781195534Sscottl}
1782195534Sscottl
1783195534Sscottlstatic void
1784236437Smavata_get_transfer_settings(struct ccb_trans_settings *cts)
1785236437Smav{
1786236437Smav	struct	ccb_trans_settings_ata *ata;
1787236437Smav	struct	ccb_trans_settings_scsi *scsi;
1788236437Smav	struct	cam_ed *device;
1789236437Smav	struct	cam_sim *sim;
1790236437Smav
1791236437Smav	device = cts->ccb_h.path->device;
1792236437Smav	sim = cts->ccb_h.path->bus->sim;
1793236437Smav	(*(sim->sim_action))(sim, (union ccb *)cts);
1794236437Smav
1795236666Smav	if (cts->protocol == PROTO_UNKNOWN ||
1796236666Smav	    cts->protocol == PROTO_UNSPECIFIED) {
1797236666Smav		cts->protocol = device->protocol;
1798236666Smav		cts->protocol_version = device->protocol_version;
1799236666Smav	}
1800236666Smav
1801236437Smav	if (cts->protocol == PROTO_ATA) {
1802236437Smav		ata = &cts->proto_specific.ata;
1803236437Smav		if ((ata->valid & CTS_ATA_VALID_TQ) == 0) {
1804236437Smav			ata->valid |= CTS_ATA_VALID_TQ;
1805236437Smav			if (cts->type == CTS_TYPE_USER_SETTINGS ||
1806236437Smav			    (device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 ||
1807236437Smav			    (device->inq_flags & SID_CmdQue) != 0)
1808236437Smav				ata->flags |= CTS_ATA_FLAGS_TAG_ENB;
1809236437Smav		}
1810236437Smav	}
1811236437Smav	if (cts->protocol == PROTO_SCSI) {
1812236437Smav		scsi = &cts->proto_specific.scsi;
1813236437Smav		if ((scsi->valid & CTS_SCSI_VALID_TQ) == 0) {
1814236437Smav			scsi->valid |= CTS_SCSI_VALID_TQ;
1815236437Smav			if (cts->type == CTS_TYPE_USER_SETTINGS ||
1816236437Smav			    (device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 ||
1817236437Smav			    (device->inq_flags & SID_CmdQue) != 0)
1818236437Smav				scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
1819236437Smav		}
1820236437Smav	}
1821236666Smav
1822236666Smav	if (cts->transport == XPORT_UNKNOWN ||
1823236666Smav	    cts->transport == XPORT_UNSPECIFIED) {
1824236666Smav		cts->transport = device->transport;
1825236666Smav		cts->transport_version = device->transport_version;
1826236666Smav	}
1827236437Smav}
1828236437Smav
1829236437Smavstatic void
1830199178Smavata_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device,
1831195534Sscottl			   int async_update)
1832195534Sscottl{
1833195534Sscottl	struct	ccb_pathinq cpi;
1834236437Smav	struct	ccb_trans_settings_ata *ata;
1835195534Sscottl	struct	ccb_trans_settings_scsi *scsi;
1836195534Sscottl	struct	cam_sim *sim;
1837236437Smav	struct	ata_params *ident_data;
1838195534Sscottl	struct	scsi_inquiry_data *inq_data;
1839195534Sscottl
1840195534Sscottl	if (device == NULL) {
1841195534Sscottl		cts->ccb_h.status = CAM_PATH_INVALID;
1842195534Sscottl		xpt_done((union ccb *)cts);
1843195534Sscottl		return;
1844195534Sscottl	}
1845195534Sscottl
1846195534Sscottl	if (cts->protocol == PROTO_UNKNOWN
1847195534Sscottl	 || cts->protocol == PROTO_UNSPECIFIED) {
1848195534Sscottl		cts->protocol = device->protocol;
1849195534Sscottl		cts->protocol_version = device->protocol_version;
1850195534Sscottl	}
1851195534Sscottl
1852195534Sscottl	if (cts->protocol_version == PROTO_VERSION_UNKNOWN
1853195534Sscottl	 || cts->protocol_version == PROTO_VERSION_UNSPECIFIED)
1854195534Sscottl		cts->protocol_version = device->protocol_version;
1855195534Sscottl
1856195534Sscottl	if (cts->protocol != device->protocol) {
1857195534Sscottl		xpt_print(cts->ccb_h.path, "Uninitialized Protocol %x:%x?\n",
1858195534Sscottl		       cts->protocol, device->protocol);
1859195534Sscottl		cts->protocol = device->protocol;
1860195534Sscottl	}
1861195534Sscottl
1862195534Sscottl	if (cts->protocol_version > device->protocol_version) {
1863195534Sscottl		if (bootverbose) {
1864195534Sscottl			xpt_print(cts->ccb_h.path, "Down reving Protocol "
1865195534Sscottl			    "Version from %d to %d?\n", cts->protocol_version,
1866195534Sscottl			    device->protocol_version);
1867195534Sscottl		}
1868195534Sscottl		cts->protocol_version = device->protocol_version;
1869195534Sscottl	}
1870195534Sscottl
1871195534Sscottl	if (cts->transport == XPORT_UNKNOWN
1872195534Sscottl	 || cts->transport == XPORT_UNSPECIFIED) {
1873195534Sscottl		cts->transport = device->transport;
1874195534Sscottl		cts->transport_version = device->transport_version;
1875195534Sscottl	}
1876195534Sscottl
1877195534Sscottl	if (cts->transport_version == XPORT_VERSION_UNKNOWN
1878195534Sscottl	 || cts->transport_version == XPORT_VERSION_UNSPECIFIED)
1879195534Sscottl		cts->transport_version = device->transport_version;
1880195534Sscottl
1881195534Sscottl	if (cts->transport != device->transport) {
1882195534Sscottl		xpt_print(cts->ccb_h.path, "Uninitialized Transport %x:%x?\n",
1883195534Sscottl		    cts->transport, device->transport);
1884195534Sscottl		cts->transport = device->transport;
1885195534Sscottl	}
1886195534Sscottl
1887195534Sscottl	if (cts->transport_version > device->transport_version) {
1888195534Sscottl		if (bootverbose) {
1889195534Sscottl			xpt_print(cts->ccb_h.path, "Down reving Transport "
1890195534Sscottl			    "Version from %d to %d?\n", cts->transport_version,
1891195534Sscottl			    device->transport_version);
1892195534Sscottl		}
1893195534Sscottl		cts->transport_version = device->transport_version;
1894195534Sscottl	}
1895195534Sscottl
1896195534Sscottl	sim = cts->ccb_h.path->bus->sim;
1897236437Smav	ident_data = &device->ident_data;
1898195534Sscottl	inq_data = &device->inq_data;
1899236437Smav	if (cts->protocol == PROTO_ATA)
1900236437Smav		ata = &cts->proto_specific.ata;
1901236437Smav	else
1902236437Smav		ata = NULL;
1903236437Smav	if (cts->protocol == PROTO_SCSI)
1904236437Smav		scsi = &cts->proto_specific.scsi;
1905236437Smav	else
1906236437Smav		scsi = NULL;
1907203108Smav	xpt_setup_ccb(&cpi.ccb_h, cts->ccb_h.path, CAM_PRIORITY_NONE);
1908195534Sscottl	cpi.ccb_h.func_code = XPT_PATH_INQ;
1909195534Sscottl	xpt_action((union ccb *)&cpi);
1910195534Sscottl
1911236437Smav	/* Sanity checking */
1912195534Sscottl	if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0
1913236437Smav	 || (ata && (ident_data->satacapabilities & ATA_SUPPORT_NCQ) == 0)
1914236437Smav	 || (scsi && (INQ_DATA_TQ_ENABLED(inq_data)) == 0)
1915195534Sscottl	 || (device->queue_flags & SCP_QUEUE_DQUE) != 0
1916195534Sscottl	 || (device->mintags == 0)) {
1917195534Sscottl		/*
1918195534Sscottl		 * Can't tag on hardware that doesn't support tags,
1919195534Sscottl		 * doesn't have it enabled, or has broken tag support.
1920195534Sscottl		 */
1921236437Smav		if (ata)
1922236437Smav			ata->flags &= ~CTS_ATA_FLAGS_TAG_ENB;
1923236437Smav		if (scsi)
1924195534Sscottl			scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
1925195534Sscottl	}
1926195534Sscottl
1927236437Smav	/* Start/stop tags use. */
1928236437Smav	if (cts->type == CTS_TYPE_CURRENT_SETTINGS &&
1929236437Smav	    ((ata && (ata->valid & CTS_ATA_VALID_TQ) != 0) ||
1930236437Smav	     (scsi && (scsi->valid & CTS_SCSI_VALID_TQ) != 0))) {
1931236437Smav		int nowt, newt = 0;
1932195534Sscottl
1933236437Smav		nowt = ((device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 ||
1934236437Smav			(device->inq_flags & SID_CmdQue) != 0);
1935236437Smav		if (ata)
1936236437Smav			newt = (ata->flags & CTS_ATA_FLAGS_TAG_ENB) != 0;
1937236437Smav		if (scsi)
1938236437Smav			newt = (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0;
1939195534Sscottl
1940236437Smav		if (newt && !nowt) {
1941236437Smav			/*
1942236437Smav			 * Delay change to use tags until after a
1943236437Smav			 * few commands have gone to this device so
1944236437Smav			 * the controller has time to perform transfer
1945236437Smav			 * negotiations without tagged messages getting
1946236437Smav			 * in the way.
1947236437Smav			 */
1948236437Smav			device->tag_delay_count = CAM_TAG_DELAY_COUNT;
1949236437Smav			device->flags |= CAM_DEV_TAG_AFTER_COUNT;
1950236437Smav		} else if (nowt && !newt)
1951236437Smav			xpt_stop_tags(cts->ccb_h.path);
1952236437Smav	}
1953195534Sscottl
1954195534Sscottl	if (async_update == FALSE)
1955195534Sscottl		(*(sim->sim_action))(sim, (union ccb *)cts);
1956195534Sscottl}
1957195534Sscottl
1958195534Sscottl/*
1959195534Sscottl * Handle any per-device event notifications that require action by the XPT.
1960195534Sscottl */
1961195534Sscottlstatic void
1962195534Sscottlata_dev_async(u_int32_t async_code, struct cam_eb *bus, struct cam_et *target,
1963195534Sscottl	      struct cam_ed *device, void *async_arg)
1964195534Sscottl{
1965195534Sscottl	cam_status status;
1966195534Sscottl	struct cam_path newpath;
1967195534Sscottl
1968195534Sscottl	/*
1969195534Sscottl	 * We only need to handle events for real devices.
1970195534Sscottl	 */
1971195534Sscottl	if (target->target_id == CAM_TARGET_WILDCARD
1972195534Sscottl	 || device->lun_id == CAM_LUN_WILDCARD)
1973195534Sscottl		return;
1974195534Sscottl
1975195534Sscottl	/*
1976195534Sscottl	 * We need our own path with wildcards expanded to
1977195534Sscottl	 * handle certain types of events.
1978195534Sscottl	 */
1979195534Sscottl	if ((async_code == AC_SENT_BDR)
1980195534Sscottl	 || (async_code == AC_BUS_RESET)
1981195534Sscottl	 || (async_code == AC_INQ_CHANGED))
1982195534Sscottl		status = xpt_compile_path(&newpath, NULL,
1983195534Sscottl					  bus->path_id,
1984195534Sscottl					  target->target_id,
1985195534Sscottl					  device->lun_id);
1986195534Sscottl	else
1987195534Sscottl		status = CAM_REQ_CMP_ERR;
1988195534Sscottl
1989195534Sscottl	if (status == CAM_REQ_CMP) {
1990195534Sscottl		if (async_code == AC_INQ_CHANGED) {
1991195534Sscottl			/*
1992195534Sscottl			 * We've sent a start unit command, or
1993195534Sscottl			 * something similar to a device that
1994195534Sscottl			 * may have caused its inquiry data to
1995195534Sscottl			 * change. So we re-scan the device to
1996195534Sscottl			 * refresh the inquiry data for it.
1997195534Sscottl			 */
1998195534Sscottl			ata_scan_lun(newpath.periph, &newpath,
1999195534Sscottl				     CAM_EXPECT_INQ_CHANGE, NULL);
2000203108Smav		} else {
2001203108Smav			/* We need to reinitialize device after reset. */
2002203108Smav			ata_scan_lun(newpath.periph, &newpath,
2003203108Smav				     0, NULL);
2004195534Sscottl		}
2005195534Sscottl		xpt_release_path(&newpath);
2006198748Smav	} else if (async_code == AC_LOST_DEVICE &&
2007198748Smav	    (device->flags & CAM_DEV_UNCONFIGURED) == 0) {
2008195534Sscottl		device->flags |= CAM_DEV_UNCONFIGURED;
2009198748Smav		xpt_release_device(device);
2010195534Sscottl	} else if (async_code == AC_TRANSFER_NEG) {
2011195534Sscottl		struct ccb_trans_settings *settings;
2012195534Sscottl
2013195534Sscottl		settings = (struct ccb_trans_settings *)async_arg;
2014199178Smav		ata_set_transfer_settings(settings, device,
2015195534Sscottl					  /*async_update*/TRUE);
2016195534Sscottl	}
2017195534Sscottl}
2018195534Sscottl
2019204220Smavstatic void
2020204220Smavata_announce_periph(struct cam_periph *periph)
2021204220Smav{
2022204220Smav	struct	ccb_pathinq cpi;
2023204220Smav	struct	ccb_trans_settings cts;
2024204220Smav	struct	cam_path *path = periph->path;
2025204220Smav	u_int	speed;
2026204220Smav	u_int	mb;
2027204220Smav
2028204220Smav	mtx_assert(periph->sim->mtx, MA_OWNED);
2029204220Smav
2030204220Smav	xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
2031204220Smav	cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
2032204220Smav	cts.type = CTS_TYPE_CURRENT_SETTINGS;
2033204220Smav	xpt_action((union ccb*)&cts);
2034204220Smav	if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
2035204220Smav		return;
2036204220Smav	/* Ask the SIM for its base transfer speed */
2037204220Smav	xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL);
2038204220Smav	cpi.ccb_h.func_code = XPT_PATH_INQ;
2039204220Smav	xpt_action((union ccb *)&cpi);
2040204220Smav	/* Report connection speed */
2041204220Smav	speed = cpi.base_transfer_speed;
2042204220Smav	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_ATA) {
2043236437Smav		struct	ccb_trans_settings_pata *pata =
2044204220Smav		    &cts.xport_specific.ata;
2045204220Smav
2046236437Smav		if (pata->valid & CTS_ATA_VALID_MODE)
2047236437Smav			speed = ata_mode2speed(pata->mode);
2048204220Smav	}
2049204220Smav	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SATA) {
2050204220Smav		struct	ccb_trans_settings_sata *sata =
2051204220Smav		    &cts.xport_specific.sata;
2052204220Smav
2053204220Smav		if (sata->valid & CTS_SATA_VALID_REVISION)
2054204220Smav			speed = ata_revision2speed(sata->revision);
2055204220Smav	}
2056204220Smav	mb = speed / 1000;
2057204220Smav	if (mb > 0)
2058204220Smav		printf("%s%d: %d.%03dMB/s transfers",
2059204220Smav		       periph->periph_name, periph->unit_number,
2060204220Smav		       mb, speed % 1000);
2061204220Smav	else
2062204220Smav		printf("%s%d: %dKB/s transfers", periph->periph_name,
2063204220Smav		       periph->unit_number, speed);
2064204220Smav	/* Report additional information about connection */
2065204220Smav	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_ATA) {
2066236437Smav		struct ccb_trans_settings_pata *pata =
2067204220Smav		    &cts.xport_specific.ata;
2068204220Smav
2069204220Smav		printf(" (");
2070236437Smav		if (pata->valid & CTS_ATA_VALID_MODE)
2071236437Smav			printf("%s, ", ata_mode2string(pata->mode));
2072236437Smav		if ((pata->valid & CTS_ATA_VALID_ATAPI) && pata->atapi != 0)
2073236437Smav			printf("ATAPI %dbytes, ", pata->atapi);
2074236437Smav		if (pata->valid & CTS_ATA_VALID_BYTECOUNT)
2075236437Smav			printf("PIO %dbytes", pata->bytecount);
2076204220Smav		printf(")");
2077204220Smav	}
2078204220Smav	if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SATA) {
2079204220Smav		struct ccb_trans_settings_sata *sata =
2080204220Smav		    &cts.xport_specific.sata;
2081204220Smav
2082204220Smav		printf(" (");
2083204220Smav		if (sata->valid & CTS_SATA_VALID_REVISION)
2084204220Smav			printf("SATA %d.x, ", sata->revision);
2085204220Smav		else
2086204220Smav			printf("SATA, ");
2087204220Smav		if (sata->valid & CTS_SATA_VALID_MODE)
2088204220Smav			printf("%s, ", ata_mode2string(sata->mode));
2089204220Smav		if ((sata->valid & CTS_ATA_VALID_ATAPI) && sata->atapi != 0)
2090204220Smav			printf("ATAPI %dbytes, ", sata->atapi);
2091204220Smav		if (sata->valid & CTS_SATA_VALID_BYTECOUNT)
2092204220Smav			printf("PIO %dbytes", sata->bytecount);
2093204220Smav		printf(")");
2094204220Smav	}
2095204220Smav	printf("\n");
2096204220Smav}
2097204220Smav
2098