ata_xpt.c revision 203421
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 203421 2010-02-03 10:06:03Z 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#ifdef PC98
48195534Sscottl#include <pc98/pc98/pc98_machdep.h>	/* geometry translation */
49195534Sscottl#endif
50195534Sscottl
51195534Sscottl#include <cam/cam.h>
52195534Sscottl#include <cam/cam_ccb.h>
53195534Sscottl#include <cam/cam_queue.h>
54195534Sscottl#include <cam/cam_periph.h>
55195534Sscottl#include <cam/cam_sim.h>
56195534Sscottl#include <cam/cam_xpt.h>
57195534Sscottl#include <cam/cam_xpt_sim.h>
58195534Sscottl#include <cam/cam_xpt_periph.h>
59195534Sscottl#include <cam/cam_xpt_internal.h>
60195534Sscottl#include <cam/cam_debug.h>
61195534Sscottl
62195534Sscottl#include <cam/scsi/scsi_all.h>
63195534Sscottl#include <cam/scsi/scsi_message.h>
64195534Sscottl#include <cam/ata/ata_all.h>
65195534Sscottl#include <machine/stdarg.h>	/* for xpt_print below */
66195534Sscottl#include "opt_cam.h"
67195534Sscottl
68199178Smavstruct ata_quirk_entry {
69195534Sscottl	struct scsi_inquiry_pattern inq_pat;
70195534Sscottl	u_int8_t quirks;
71199178Smav#define	CAM_QUIRK_MAXTAGS	0x01
72195534Sscottl	u_int maxtags;
73195534Sscottl};
74195534Sscottl
75195534Sscottlstatic periph_init_t probe_periph_init;
76195534Sscottl
77195534Sscottlstatic struct periph_driver probe_driver =
78195534Sscottl{
79195653Smav	probe_periph_init, "aprobe",
80198708Smav	TAILQ_HEAD_INITIALIZER(probe_driver.units), /* generation */ 0,
81198708Smav	CAM_PERIPH_DRV_EARLY
82195534Sscottl};
83195534Sscottl
84195653SmavPERIPHDRIVER_DECLARE(aprobe, probe_driver);
85195534Sscottl
86195534Sscottltypedef enum {
87195534Sscottl	PROBE_RESET,
88195534Sscottl	PROBE_IDENTIFY,
89203421Smav	PROBE_SPINUP,
90195534Sscottl	PROBE_SETMODE,
91198708Smav	PROBE_SET_MULTI,
92195534Sscottl	PROBE_INQUIRY,
93195534Sscottl	PROBE_FULL_INQUIRY,
94195534Sscottl	PROBE_PM_PID,
95195534Sscottl	PROBE_PM_PRV,
96195534Sscottl	PROBE_INVALID
97195534Sscottl} probe_action;
98195534Sscottl
99195534Sscottlstatic char *probe_action_text[] = {
100195534Sscottl	"PROBE_RESET",
101195534Sscottl	"PROBE_IDENTIFY",
102203421Smav	"PROBE_SPINUP",
103195534Sscottl	"PROBE_SETMODE",
104198708Smav	"PROBE_SET_MULTI",
105195534Sscottl	"PROBE_INQUIRY",
106195534Sscottl	"PROBE_FULL_INQUIRY",
107195534Sscottl	"PROBE_PM_PID",
108195534Sscottl	"PROBE_PM_PRV",
109195534Sscottl	"PROBE_INVALID"
110195534Sscottl};
111195534Sscottl
112195534Sscottl#define PROBE_SET_ACTION(softc, newaction)	\
113195534Sscottldo {									\
114195534Sscottl	char **text;							\
115195534Sscottl	text = probe_action_text;					\
116195534Sscottl	CAM_DEBUG((softc)->periph->path, CAM_DEBUG_INFO,		\
117195534Sscottl	    ("Probe %s to %s\n", text[(softc)->action],			\
118195534Sscottl	    text[(newaction)]));					\
119195534Sscottl	(softc)->action = (newaction);					\
120195534Sscottl} while(0)
121195534Sscottl
122195534Sscottltypedef enum {
123195534Sscottl	PROBE_NO_ANNOUNCE	= 0x04
124195534Sscottl} probe_flags;
125195534Sscottl
126195534Sscottltypedef struct {
127195534Sscottl	TAILQ_HEAD(, ccb_hdr) request_ccbs;
128203385Smav	struct ata_params	ident_data;
129195534Sscottl	probe_action	action;
130195534Sscottl	probe_flags	flags;
131195534Sscottl	uint32_t	pm_pid;
132195534Sscottl	uint32_t	pm_prv;
133203108Smav	int		restart;
134203421Smav	int		spinup;
135195534Sscottl	struct cam_periph *periph;
136195534Sscottl} probe_softc;
137195534Sscottl
138199178Smavstatic struct ata_quirk_entry ata_quirk_table[] =
139195534Sscottl{
140195534Sscottl	{
141195534Sscottl		/* Default tagged queuing parameters for all devices */
142195534Sscottl		{
143195534Sscottl		  T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED,
144195534Sscottl		  /*vendor*/"*", /*product*/"*", /*revision*/"*"
145195534Sscottl		},
146199178Smav		/*quirks*/0, /*maxtags*/0
147195534Sscottl	},
148195534Sscottl};
149195534Sscottl
150199178Smavstatic const int ata_quirk_table_size =
151199178Smav	sizeof(ata_quirk_table) / sizeof(*ata_quirk_table);
152195534Sscottl
153195534Sscottlstatic cam_status	proberegister(struct cam_periph *periph,
154195534Sscottl				      void *arg);
155195534Sscottlstatic void	 probeschedule(struct cam_periph *probe_periph);
156195534Sscottlstatic void	 probestart(struct cam_periph *periph, union ccb *start_ccb);
157195534Sscottl//static void	 proberequestdefaultnegotiation(struct cam_periph *periph);
158195534Sscottl//static int       proberequestbackoff(struct cam_periph *periph,
159195534Sscottl//				     struct cam_ed *device);
160195534Sscottlstatic void	 probedone(struct cam_periph *periph, union ccb *done_ccb);
161195534Sscottlstatic void	 probecleanup(struct cam_periph *periph);
162199178Smavstatic void	 ata_find_quirk(struct cam_ed *device);
163195534Sscottlstatic void	 ata_scan_bus(struct cam_periph *periph, union ccb *ccb);
164195534Sscottlstatic void	 ata_scan_lun(struct cam_periph *periph,
165195534Sscottl			       struct cam_path *path, cam_flags flags,
166195534Sscottl			       union ccb *ccb);
167195534Sscottlstatic void	 xptscandone(struct cam_periph *periph, union ccb *done_ccb);
168195534Sscottlstatic struct cam_ed *
169195534Sscottl		 ata_alloc_device(struct cam_eb *bus, struct cam_et *target,
170195534Sscottl				   lun_id_t lun_id);
171195534Sscottlstatic void	 ata_device_transport(struct cam_path *path);
172199178Smavstatic void	 ata_set_transfer_settings(struct ccb_trans_settings *cts,
173195534Sscottl					    struct cam_ed *device,
174195534Sscottl					    int async_update);
175195534Sscottlstatic void	 ata_dev_async(u_int32_t async_code,
176195534Sscottl				struct cam_eb *bus,
177195534Sscottl				struct cam_et *target,
178195534Sscottl				struct cam_ed *device,
179195534Sscottl				void *async_arg);
180195534Sscottlstatic void	 ata_action(union ccb *start_ccb);
181195534Sscottl
182195534Sscottlstatic struct xpt_xport ata_xport = {
183195534Sscottl	.alloc_device = ata_alloc_device,
184195534Sscottl	.action = ata_action,
185195534Sscottl	.async = ata_dev_async,
186195534Sscottl};
187195534Sscottl
188195534Sscottlstruct xpt_xport *
189195534Sscottlata_get_xport(void)
190195534Sscottl{
191195534Sscottl	return (&ata_xport);
192195534Sscottl}
193195534Sscottl
194195534Sscottlstatic void
195195534Sscottlprobe_periph_init()
196195534Sscottl{
197195534Sscottl}
198195534Sscottl
199195534Sscottlstatic cam_status
200195534Sscottlproberegister(struct cam_periph *periph, void *arg)
201195534Sscottl{
202195534Sscottl	union ccb *request_ccb;	/* CCB representing the probe request */
203195534Sscottl	cam_status status;
204195534Sscottl	probe_softc *softc;
205195534Sscottl
206195534Sscottl	request_ccb = (union ccb *)arg;
207195534Sscottl	if (periph == NULL) {
208195534Sscottl		printf("proberegister: periph was NULL!!\n");
209195534Sscottl		return(CAM_REQ_CMP_ERR);
210195534Sscottl	}
211195534Sscottl
212195534Sscottl	if (request_ccb == NULL) {
213195534Sscottl		printf("proberegister: no probe CCB, "
214195534Sscottl		       "can't register device\n");
215195534Sscottl		return(CAM_REQ_CMP_ERR);
216195534Sscottl	}
217195534Sscottl
218203421Smav	softc = (probe_softc *)malloc(sizeof(*softc), M_CAMXPT, M_ZERO | M_NOWAIT);
219195534Sscottl
220195534Sscottl	if (softc == NULL) {
221195534Sscottl		printf("proberegister: Unable to probe new device. "
222195534Sscottl		       "Unable to allocate softc\n");
223195534Sscottl		return(CAM_REQ_CMP_ERR);
224195534Sscottl	}
225195534Sscottl	TAILQ_INIT(&softc->request_ccbs);
226195534Sscottl	TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h,
227195534Sscottl			  periph_links.tqe);
228195534Sscottl	softc->flags = 0;
229195534Sscottl	periph->softc = softc;
230195534Sscottl	softc->periph = periph;
231195534Sscottl	softc->action = PROBE_INVALID;
232195534Sscottl	status = cam_periph_acquire(periph);
233195534Sscottl	if (status != CAM_REQ_CMP) {
234195534Sscottl		return (status);
235195534Sscottl	}
236195534Sscottl	/*
237203108Smav	 * Ensure nobody slip in until probe finish.
238195534Sscottl	 */
239203108Smav	cam_freeze_devq_arg(periph->path,
240203108Smav	    RELSIM_RELEASE_RUNLEVEL, CAM_RL_XPT + 1);
241195534Sscottl	probeschedule(periph);
242195534Sscottl	return(CAM_REQ_CMP);
243195534Sscottl}
244195534Sscottl
245195534Sscottlstatic void
246195534Sscottlprobeschedule(struct cam_periph *periph)
247195534Sscottl{
248195534Sscottl	union ccb *ccb;
249195534Sscottl	probe_softc *softc;
250195534Sscottl
251195534Sscottl	softc = (probe_softc *)periph->softc;
252195534Sscottl	ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs);
253195534Sscottl
254198389Smav	if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) ||
255198389Smav	    periph->path->device->protocol == PROTO_SATAPM)
256195534Sscottl		PROBE_SET_ACTION(softc, PROBE_RESET);
257195534Sscottl	else
258195534Sscottl		PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
259195534Sscottl
260195534Sscottl	if (ccb->crcn.flags & CAM_EXPECT_INQ_CHANGE)
261195534Sscottl		softc->flags |= PROBE_NO_ANNOUNCE;
262195534Sscottl	else
263195534Sscottl		softc->flags &= ~PROBE_NO_ANNOUNCE;
264195534Sscottl
265203108Smav	xpt_schedule(periph, CAM_PRIORITY_XPT);
266195534Sscottl}
267195534Sscottl
268195534Sscottlstatic void
269195534Sscottlprobestart(struct cam_periph *periph, union ccb *start_ccb)
270195534Sscottl{
271199747Smav	struct ccb_trans_settings cts;
272195534Sscottl	struct ccb_ataio *ataio;
273195534Sscottl	struct ccb_scsiio *csio;
274195534Sscottl	probe_softc *softc;
275198708Smav	struct cam_path *path;
276198708Smav	struct ata_params *ident_buf;
277195534Sscottl
278195534Sscottl	CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probestart\n"));
279195534Sscottl
280195534Sscottl	softc = (probe_softc *)periph->softc;
281198708Smav	path = start_ccb->ccb_h.path;
282195534Sscottl	ataio = &start_ccb->ataio;
283195534Sscottl	csio = &start_ccb->csio;
284198708Smav	ident_buf = &periph->path->device->ident_data;
285195534Sscottl
286203108Smav	if (softc->restart) {
287203108Smav		softc->restart = 0;
288203108Smav		if ((path->device->flags & CAM_DEV_UNCONFIGURED) ||
289203108Smav		    path->device->protocol == PROTO_SATAPM)
290203108Smav			softc->action = PROBE_RESET;
291203108Smav		else
292203108Smav			softc->action = PROBE_IDENTIFY;
293203108Smav	}
294195534Sscottl	switch (softc->action) {
295195534Sscottl	case PROBE_RESET:
296195534Sscottl		cam_fill_ataio(ataio,
297195534Sscottl		      0,
298195534Sscottl		      probedone,
299195534Sscottl		      /*flags*/CAM_DIR_NONE,
300198389Smav		      0,
301195534Sscottl		      /*data_ptr*/NULL,
302195534Sscottl		      /*dxfer_len*/0,
303203108Smav		      15 * 1000);
304195534Sscottl		ata_reset_cmd(ataio);
305195534Sscottl		break;
306195534Sscottl	case PROBE_IDENTIFY:
307195534Sscottl		cam_fill_ataio(ataio,
308195534Sscottl		      1,
309195534Sscottl		      probedone,
310195534Sscottl		      /*flags*/CAM_DIR_IN,
311198389Smav		      0,
312203385Smav		      /*data_ptr*/(u_int8_t *)&softc->ident_data,
313203385Smav		      /*dxfer_len*/sizeof(softc->ident_data),
314195534Sscottl		      30 * 1000);
315195534Sscottl		if (periph->path->device->protocol == PROTO_ATA)
316196659Smav			ata_28bit_cmd(ataio, ATA_ATA_IDENTIFY, 0, 0, 0);
317195534Sscottl		else
318196659Smav			ata_28bit_cmd(ataio, ATA_ATAPI_IDENTIFY, 0, 0, 0);
319195534Sscottl		break;
320203421Smav	case PROBE_SPINUP:
321203421Smav		if (bootverbose)
322203421Smav			xpt_print(path, "Spinning up device\n");
323203421Smav		cam_fill_ataio(ataio,
324203421Smav		      1,
325203421Smav		      probedone,
326203421Smav		      /*flags*/CAM_DIR_NONE | CAM_HIGH_POWER,
327203421Smav		      0,
328203421Smav		      /*data_ptr*/NULL,
329203421Smav		      /*dxfer_len*/0,
330203421Smav		      30 * 1000);
331203421Smav		ata_28bit_cmd(ataio, ATA_SETFEATURES, ATA_SF_PUIS_SPINUP, 0, 0);
332203421Smav		break;
333195534Sscottl	case PROBE_SETMODE:
334199747Smav	{
335199747Smav		int mode, wantmode;
336199747Smav
337199747Smav		mode = 0;
338199747Smav		/* Fetch user modes from SIM. */
339199747Smav		bzero(&cts, sizeof(cts));
340203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
341199747Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
342199747Smav		cts.type = CTS_TYPE_USER_SETTINGS;
343199747Smav		xpt_action((union ccb *)&cts);
344199747Smav		if (path->device->transport == XPORT_ATA) {
345199747Smav			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_MODE)
346199747Smav				mode = cts.xport_specific.ata.mode;
347199747Smav		} else {
348199799Smav			if (cts.xport_specific.sata.valid & CTS_SATA_VALID_MODE)
349199747Smav				mode = cts.xport_specific.sata.mode;
350199747Smav		}
351199747Smavnegotiate:
352199747Smav		/* Honor device capabilities. */
353199747Smav		wantmode = mode = ata_max_mode(ident_buf, mode);
354199747Smav		/* Report modes to SIM. */
355199747Smav		bzero(&cts, sizeof(cts));
356203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
357199747Smav		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
358199747Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
359199747Smav		if (path->device->transport == XPORT_ATA) {
360199747Smav			cts.xport_specific.ata.mode = mode;
361199747Smav			cts.xport_specific.ata.valid = CTS_ATA_VALID_MODE;
362199747Smav		} else {
363199747Smav			cts.xport_specific.sata.mode = mode;
364199747Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_MODE;
365199747Smav		}
366199747Smav		xpt_action((union ccb *)&cts);
367200171Smav		/* Fetch current modes from SIM. */
368199747Smav		bzero(&cts, sizeof(cts));
369203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
370199747Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
371199747Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
372199747Smav		xpt_action((union ccb *)&cts);
373199747Smav		if (path->device->transport == XPORT_ATA) {
374199747Smav			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_MODE)
375199747Smav				mode = cts.xport_specific.ata.mode;
376199747Smav		} else {
377199747Smav			if (cts.xport_specific.ata.valid & CTS_SATA_VALID_MODE)
378199747Smav				mode = cts.xport_specific.sata.mode;
379199747Smav		}
380199747Smav		/* If SIM disagree - renegotiate. */
381199747Smav		if (mode != wantmode)
382199747Smav			goto negotiate;
383195534Sscottl		cam_fill_ataio(ataio,
384195534Sscottl		      1,
385195534Sscottl		      probedone,
386196353Smav		      /*flags*/CAM_DIR_NONE,
387196353Smav		      0,
388196353Smav		      /*data_ptr*/NULL,
389196353Smav		      /*dxfer_len*/0,
390195534Sscottl		      30 * 1000);
391199747Smav		ata_28bit_cmd(ataio, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
392195534Sscottl		break;
393199747Smav	}
394198708Smav	case PROBE_SET_MULTI:
395198708Smav	{
396200171Smav		u_int sectors, bytecount;
397198708Smav
398200171Smav		bytecount = 8192;	/* SATA maximum */
399200171Smav		/* Fetch user bytecount from SIM. */
400200171Smav		bzero(&cts, sizeof(cts));
401203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
402200171Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
403200171Smav		cts.type = CTS_TYPE_USER_SETTINGS;
404200171Smav		xpt_action((union ccb *)&cts);
405200171Smav		if (path->device->transport == XPORT_ATA) {
406200171Smav			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_BYTECOUNT)
407200171Smav				bytecount = cts.xport_specific.ata.bytecount;
408200171Smav		} else {
409200171Smav			if (cts.xport_specific.sata.valid & CTS_SATA_VALID_BYTECOUNT)
410200171Smav				bytecount = cts.xport_specific.sata.bytecount;
411200171Smav		}
412200171Smav		/* Honor device capabilities. */
413200171Smav		sectors = max(1, min(ident_buf->sectors_intr & 0xff,
414200171Smav		    bytecount / ata_logical_sector_size(ident_buf)));
415198708Smav		/* Report bytecount to SIM. */
416198708Smav		bzero(&cts, sizeof(cts));
417203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
418198708Smav		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
419198708Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
420198708Smav		if (path->device->transport == XPORT_ATA) {
421198897Smav			cts.xport_specific.ata.bytecount = sectors *
422198897Smav			    ata_logical_sector_size(ident_buf);
423198708Smav			cts.xport_specific.ata.valid = CTS_ATA_VALID_BYTECOUNT;
424198708Smav		} else {
425198897Smav			cts.xport_specific.sata.bytecount = sectors *
426198897Smav			    ata_logical_sector_size(ident_buf);
427198708Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_BYTECOUNT;
428198708Smav		}
429198708Smav		xpt_action((union ccb *)&cts);
430200171Smav		/* Fetch current bytecount from SIM. */
431200171Smav		bzero(&cts, sizeof(cts));
432203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
433200171Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
434200171Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
435200171Smav		xpt_action((union ccb *)&cts);
436200171Smav		if (path->device->transport == XPORT_ATA) {
437200171Smav			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_BYTECOUNT)
438200171Smav				bytecount = cts.xport_specific.ata.bytecount;
439200171Smav		} else {
440200171Smav			if (cts.xport_specific.sata.valid & CTS_SATA_VALID_BYTECOUNT)
441200171Smav				bytecount = cts.xport_specific.sata.bytecount;
442200171Smav		}
443200171Smav		sectors = bytecount / ata_logical_sector_size(ident_buf);
444198708Smav
445198708Smav		cam_fill_ataio(ataio,
446198708Smav		    1,
447198708Smav		    probedone,
448198708Smav		    CAM_DIR_NONE,
449198708Smav		    0,
450198708Smav		    NULL,
451198708Smav		    0,
452198708Smav		    30*1000);
453198708Smav		ata_28bit_cmd(ataio, ATA_SET_MULTI, 0, 0, sectors);
454198708Smav		break;
455195534Sscottl	}
456195534Sscottl	case PROBE_INQUIRY:
457200171Smav	{
458200171Smav		u_int bytecount;
459200171Smav
460200171Smav		bytecount = 8192;	/* SATA maximum */
461200171Smav		/* Fetch user bytecount from SIM. */
462200171Smav		bzero(&cts, sizeof(cts));
463203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
464200171Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
465200171Smav		cts.type = CTS_TYPE_USER_SETTINGS;
466200171Smav		xpt_action((union ccb *)&cts);
467200171Smav		if (path->device->transport == XPORT_ATA) {
468200171Smav			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_BYTECOUNT)
469200171Smav				bytecount = cts.xport_specific.ata.bytecount;
470200171Smav		} else {
471200171Smav			if (cts.xport_specific.sata.valid & CTS_SATA_VALID_BYTECOUNT)
472200171Smav				bytecount = cts.xport_specific.sata.bytecount;
473200171Smav		}
474200171Smav		/* Honor device capabilities. */
475200171Smav		bytecount &= ~1;
476200171Smav		bytecount = max(2, min(65534, bytecount));
477200171Smav		if (ident_buf->satacapabilities != 0x0000 &&
478200171Smav		    ident_buf->satacapabilities != 0xffff) {
479200171Smav			bytecount = min(8192, bytecount);
480200171Smav		}
481200171Smav		/* Report bytecount to SIM. */
482200171Smav		bzero(&cts, sizeof(cts));
483203108Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
484200171Smav		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
485200171Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
486200171Smav		if (path->device->transport == XPORT_ATA) {
487200171Smav			cts.xport_specific.ata.bytecount = bytecount;
488200171Smav			cts.xport_specific.ata.valid = CTS_ATA_VALID_BYTECOUNT;
489200171Smav		} else {
490200171Smav			cts.xport_specific.sata.bytecount = bytecount;
491200171Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_BYTECOUNT;
492200171Smav		}
493200171Smav		xpt_action((union ccb *)&cts);
494200171Smav		/* FALLTHROUGH */
495200171Smav	}
496195534Sscottl	case PROBE_FULL_INQUIRY:
497195534Sscottl	{
498195534Sscottl		u_int inquiry_len;
499195534Sscottl		struct scsi_inquiry_data *inq_buf =
500195534Sscottl		    &periph->path->device->inq_data;
501195534Sscottl
502195534Sscottl		if (softc->action == PROBE_INQUIRY)
503195534Sscottl			inquiry_len = SHORT_INQUIRY_LENGTH;
504195534Sscottl		else
505195534Sscottl			inquiry_len = SID_ADDITIONAL_LENGTH(inq_buf);
506195534Sscottl		/*
507195534Sscottl		 * Some parallel SCSI devices fail to send an
508195534Sscottl		 * ignore wide residue message when dealing with
509195534Sscottl		 * odd length inquiry requests.  Round up to be
510195534Sscottl		 * safe.
511195534Sscottl		 */
512195534Sscottl		inquiry_len = roundup2(inquiry_len, 2);
513195534Sscottl		scsi_inquiry(csio,
514195534Sscottl			     /*retries*/1,
515195534Sscottl			     probedone,
516195534Sscottl			     MSG_SIMPLE_Q_TAG,
517195534Sscottl			     (u_int8_t *)inq_buf,
518195534Sscottl			     inquiry_len,
519195534Sscottl			     /*evpd*/FALSE,
520195534Sscottl			     /*page_code*/0,
521195534Sscottl			     SSD_MIN_SIZE,
522195534Sscottl			     /*timeout*/60 * 1000);
523195534Sscottl		break;
524195534Sscottl	}
525195534Sscottl	case PROBE_PM_PID:
526195534Sscottl		cam_fill_ataio(ataio,
527195534Sscottl		      1,
528195534Sscottl		      probedone,
529195534Sscottl		      /*flags*/CAM_DIR_NONE,
530198389Smav		      0,
531195534Sscottl		      /*data_ptr*/NULL,
532195534Sscottl		      /*dxfer_len*/0,
533195534Sscottl		      10 * 1000);
534195534Sscottl		ata_pm_read_cmd(ataio, 0, 15);
535195534Sscottl		break;
536195534Sscottl	case PROBE_PM_PRV:
537195534Sscottl		cam_fill_ataio(ataio,
538195534Sscottl		      1,
539195534Sscottl		      probedone,
540195534Sscottl		      /*flags*/CAM_DIR_NONE,
541198389Smav		      0,
542195534Sscottl		      /*data_ptr*/NULL,
543195534Sscottl		      /*dxfer_len*/0,
544195534Sscottl		      10 * 1000);
545195534Sscottl		ata_pm_read_cmd(ataio, 1, 15);
546195534Sscottl		break;
547195534Sscottl	case PROBE_INVALID:
548198708Smav		CAM_DEBUG(path, CAM_DEBUG_INFO,
549195534Sscottl		    ("probestart: invalid action state\n"));
550195534Sscottl	default:
551195534Sscottl		break;
552195534Sscottl	}
553195534Sscottl	xpt_action(start_ccb);
554195534Sscottl}
555195534Sscottl#if 0
556195534Sscottlstatic void
557195534Sscottlproberequestdefaultnegotiation(struct cam_periph *periph)
558195534Sscottl{
559195534Sscottl	struct ccb_trans_settings cts;
560195534Sscottl
561203108Smav	xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NONE);
562195534Sscottl	cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
563195534Sscottl	cts.type = CTS_TYPE_USER_SETTINGS;
564195534Sscottl	xpt_action((union ccb *)&cts);
565195534Sscottl	if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
566195534Sscottl		return;
567195534Sscottl	}
568195534Sscottl	cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
569195534Sscottl	cts.type = CTS_TYPE_CURRENT_SETTINGS;
570195534Sscottl	xpt_action((union ccb *)&cts);
571195534Sscottl}
572195534Sscottl
573195534Sscottl/*
574195534Sscottl * Backoff Negotiation Code- only pertinent for SPI devices.
575195534Sscottl */
576195534Sscottlstatic int
577195534Sscottlproberequestbackoff(struct cam_periph *periph, struct cam_ed *device)
578195534Sscottl{
579195534Sscottl	struct ccb_trans_settings cts;
580195534Sscottl	struct ccb_trans_settings_spi *spi;
581195534Sscottl
582195534Sscottl	memset(&cts, 0, sizeof (cts));
583203108Smav	xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NONE);
584195534Sscottl	cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
585195534Sscottl	cts.type = CTS_TYPE_CURRENT_SETTINGS;
586195534Sscottl	xpt_action((union ccb *)&cts);
587195534Sscottl	if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
588195534Sscottl		if (bootverbose) {
589195534Sscottl			xpt_print(periph->path,
590195534Sscottl			    "failed to get current device settings\n");
591195534Sscottl		}
592195534Sscottl		return (0);
593195534Sscottl	}
594195534Sscottl	if (cts.transport != XPORT_SPI) {
595195534Sscottl		if (bootverbose) {
596195534Sscottl			xpt_print(periph->path, "not SPI transport\n");
597195534Sscottl		}
598195534Sscottl		return (0);
599195534Sscottl	}
600195534Sscottl	spi = &cts.xport_specific.spi;
601195534Sscottl
602195534Sscottl	/*
603195534Sscottl	 * We cannot renegotiate sync rate if we don't have one.
604195534Sscottl	 */
605195534Sscottl	if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) {
606195534Sscottl		if (bootverbose) {
607195534Sscottl			xpt_print(periph->path, "no sync rate known\n");
608195534Sscottl		}
609195534Sscottl		return (0);
610195534Sscottl	}
611195534Sscottl
612195534Sscottl	/*
613195534Sscottl	 * We'll assert that we don't have to touch PPR options- the
614195534Sscottl	 * SIM will see what we do with period and offset and adjust
615195534Sscottl	 * the PPR options as appropriate.
616195534Sscottl	 */
617195534Sscottl
618195534Sscottl	/*
619195534Sscottl	 * A sync rate with unknown or zero offset is nonsensical.
620195534Sscottl	 * A sync period of zero means Async.
621195534Sscottl	 */
622195534Sscottl	if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0
623195534Sscottl	 || spi->sync_offset == 0 || spi->sync_period == 0) {
624195534Sscottl		if (bootverbose) {
625195534Sscottl			xpt_print(periph->path, "no sync rate available\n");
626195534Sscottl		}
627195534Sscottl		return (0);
628195534Sscottl	}
629195534Sscottl
630195534Sscottl	if (device->flags & CAM_DEV_DV_HIT_BOTTOM) {
631195534Sscottl		CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
632195534Sscottl		    ("hit async: giving up on DV\n"));
633195534Sscottl		return (0);
634195534Sscottl	}
635195534Sscottl
636195534Sscottl
637195534Sscottl	/*
638195534Sscottl	 * Jump sync_period up by one, but stop at 5MHz and fall back to Async.
639195534Sscottl	 * We don't try to remember 'last' settings to see if the SIM actually
640195534Sscottl	 * gets into the speed we want to set. We check on the SIM telling
641195534Sscottl	 * us that a requested speed is bad, but otherwise don't try and
642195534Sscottl	 * check the speed due to the asynchronous and handshake nature
643195534Sscottl	 * of speed setting.
644195534Sscottl	 */
645195534Sscottl	spi->valid = CTS_SPI_VALID_SYNC_RATE | CTS_SPI_VALID_SYNC_OFFSET;
646195534Sscottl	for (;;) {
647195534Sscottl		spi->sync_period++;
648195534Sscottl		if (spi->sync_period >= 0xf) {
649195534Sscottl			spi->sync_period = 0;
650195534Sscottl			spi->sync_offset = 0;
651195534Sscottl			CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
652195534Sscottl			    ("setting to async for DV\n"));
653195534Sscottl			/*
654195534Sscottl			 * Once we hit async, we don't want to try
655195534Sscottl			 * any more settings.
656195534Sscottl			 */
657195534Sscottl			device->flags |= CAM_DEV_DV_HIT_BOTTOM;
658195534Sscottl		} else if (bootverbose) {
659195534Sscottl			CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
660195534Sscottl			    ("DV: period 0x%x\n", spi->sync_period));
661195534Sscottl			printf("setting period to 0x%x\n", spi->sync_period);
662195534Sscottl		}
663195534Sscottl		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
664195534Sscottl		cts.type = CTS_TYPE_CURRENT_SETTINGS;
665195534Sscottl		xpt_action((union ccb *)&cts);
666195534Sscottl		if ((cts.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
667195534Sscottl			break;
668195534Sscottl		}
669195534Sscottl		CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
670195534Sscottl		    ("DV: failed to set period 0x%x\n", spi->sync_period));
671195534Sscottl		if (spi->sync_period == 0) {
672195534Sscottl			return (0);
673195534Sscottl		}
674195534Sscottl	}
675195534Sscottl	return (1);
676195534Sscottl}
677195534Sscottl#endif
678195534Sscottlstatic void
679195534Sscottlprobedone(struct cam_periph *periph, union ccb *done_ccb)
680195534Sscottl{
681199747Smav	struct ccb_trans_settings cts;
682195534Sscottl	struct ata_params *ident_buf;
683195534Sscottl	probe_softc *softc;
684195534Sscottl	struct cam_path *path;
685195534Sscottl	u_int32_t  priority;
686198389Smav	int found = 1;
687195534Sscottl
688195534Sscottl	CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probedone\n"));
689195534Sscottl
690195534Sscottl	softc = (probe_softc *)periph->softc;
691195534Sscottl	path = done_ccb->ccb_h.path;
692195534Sscottl	priority = done_ccb->ccb_h.pinfo.priority;
693195534Sscottl	ident_buf = &path->device->ident_data;
694195534Sscottl
695198708Smav	if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
696203385Smavdevice_fail:	if (cam_periph_error(done_ccb, 0, 0, NULL) == ERESTART) {
697195534Sscottl			return;
698195534Sscottl		} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
699195534Sscottl			/* Don't wedge the queue */
700195534Sscottl			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
701195534Sscottl					 /*run_queue*/TRUE);
702195534Sscottl		}
703198708Smav		/* Old PIO2 devices may not support mode setting. */
704198708Smav		if (softc->action == PROBE_SETMODE &&
705198708Smav		    ata_max_pmode(ident_buf) <= ATA_PIO2 &&
706198708Smav		    (ident_buf->capabilities1 & ATA_SUPPORT_IORDY) == 0)
707198708Smav			goto noerror;
708198708Smav		/*
709198708Smav		 * If we get to this point, we got an error status back
710198708Smav		 * from the inquiry and the error status doesn't require
711198708Smav		 * automatically retrying the command.  Therefore, the
712198708Smav		 * inquiry failed.  If we had inquiry information before
713198708Smav		 * for this device, but this latest inquiry command failed,
714198708Smav		 * the device has probably gone away.  If this device isn't
715198708Smav		 * already marked unconfigured, notify the peripheral
716198708Smav		 * drivers that this device is no more.
717198708Smav		 */
718198708Smav		if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0)
719198708Smav			xpt_async(AC_LOST_DEVICE, path, NULL);
720198708Smav		found = 0;
721198708Smav		goto done;
722198708Smav	}
723198708Smavnoerror:
724203385Smav	if (softc->restart)
725203385Smav		goto done;
726198708Smav	switch (softc->action) {
727198708Smav	case PROBE_RESET:
728195534Sscottl	{
729198708Smav		int sign = (done_ccb->ataio.res.lba_high << 8) +
730198708Smav		    done_ccb->ataio.res.lba_mid;
731200218Smav		if (bootverbose)
732200218Smav			xpt_print(path, "SIGNATURE: %04x\n", sign);
733198708Smav		if (sign == 0x0000 &&
734198708Smav		    done_ccb->ccb_h.target_id != 15) {
735198708Smav			path->device->protocol = PROTO_ATA;
736198708Smav			PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
737198708Smav		} else if (sign == 0x9669 &&
738198708Smav		    done_ccb->ccb_h.target_id == 15) {
739199747Smav			/* Report SIM that PM is present. */
740198708Smav			bzero(&cts, sizeof(cts));
741203108Smav			xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
742198708Smav			cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
743198708Smav			cts.type = CTS_TYPE_CURRENT_SETTINGS;
744198708Smav			cts.xport_specific.sata.pm_present = 1;
745198708Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_PM;
746198708Smav			xpt_action((union ccb *)&cts);
747198708Smav			path->device->protocol = PROTO_SATAPM;
748198708Smav			PROBE_SET_ACTION(softc, PROBE_PM_PID);
749198708Smav		} else if (sign == 0xeb14 &&
750198708Smav		    done_ccb->ccb_h.target_id != 15) {
751198708Smav			path->device->protocol = PROTO_SCSI;
752198708Smav			PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
753198708Smav		} else {
754198708Smav			if (done_ccb->ccb_h.target_id != 15) {
755198708Smav				xpt_print(path,
756198708Smav				    "Unexpected signature 0x%04x\n", sign);
757195534Sscottl			}
758198708Smav			goto device_fail;
759198708Smav		}
760198708Smav		xpt_release_ccb(done_ccb);
761198708Smav		xpt_schedule(periph, priority);
762198708Smav		return;
763198708Smav	}
764198708Smav	case PROBE_IDENTIFY:
765198708Smav	{
766198708Smav		int16_t *ptr;
767195534Sscottl
768203385Smav		ident_buf = &softc->ident_data;
769198708Smav		for (ptr = (int16_t *)ident_buf;
770198708Smav		     ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) {
771198708Smav			*ptr = le16toh(*ptr);
772198708Smav		}
773198708Smav		if (strncmp(ident_buf->model, "FX", 2) &&
774198708Smav		    strncmp(ident_buf->model, "NEC", 3) &&
775198708Smav		    strncmp(ident_buf->model, "Pioneer", 7) &&
776198708Smav		    strncmp(ident_buf->model, "SHARP", 5)) {
777198708Smav			ata_bswap(ident_buf->model, sizeof(ident_buf->model));
778198708Smav			ata_bswap(ident_buf->revision, sizeof(ident_buf->revision));
779198708Smav			ata_bswap(ident_buf->serial, sizeof(ident_buf->serial));
780198708Smav		}
781198708Smav		ata_btrim(ident_buf->model, sizeof(ident_buf->model));
782198708Smav		ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model));
783198708Smav		ata_btrim(ident_buf->revision, sizeof(ident_buf->revision));
784198708Smav		ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision));
785198708Smav		ata_btrim(ident_buf->serial, sizeof(ident_buf->serial));
786198708Smav		ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial));
787203421Smav		/* Device may need spin-up before IDENTIFY become valid. */
788203421Smav		if ((ident_buf->config & ATA_RESP_INCOMPLETE) ||
789203421Smav		    ((ident_buf->support.command2 & ATA_SUPPORT_STANDBY) &&
790203421Smav		     (ident_buf->enabled.command2 & ATA_SUPPORT_STANDBY) &&
791203421Smav		     (ident_buf->support.command2 & ATA_SUPPORT_SPINUP) &&
792203421Smav		      softc->spinup == 0)) {
793203421Smav			PROBE_SET_ACTION(softc, PROBE_SPINUP);
794203421Smav			xpt_release_ccb(done_ccb);
795203421Smav			xpt_schedule(periph, priority);
796203421Smav			return;
797203421Smav		}
798203385Smav		ident_buf = &path->device->ident_data;
799198708Smav		if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) {
800198708Smav			/* Check that it is the same device. */
801203385Smav			if (bcmp(softc->ident_data.model, ident_buf->model,
802203385Smav			     sizeof(ident_buf->model)) ||
803203385Smav			    bcmp(softc->ident_data.revision, ident_buf->revision,
804203385Smav			     sizeof(ident_buf->revision)) ||
805203385Smav			    bcmp(softc->ident_data.serial, ident_buf->serial,
806203385Smav			     sizeof(ident_buf->serial))) {
807198708Smav				/* Device changed. */
808198708Smav				xpt_async(AC_LOST_DEVICE, path, NULL);
809203385Smav			} else
810203385Smav				bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params));
811198708Smav		} else {
812203385Smav			bcopy(&softc->ident_data, ident_buf, sizeof(struct ata_params));
813195534Sscottl			/* Clean up from previous instance of this device */
814195534Sscottl			if (path->device->serial_num != NULL) {
815195534Sscottl				free(path->device->serial_num, M_CAMXPT);
816195534Sscottl				path->device->serial_num = NULL;
817195534Sscottl				path->device->serial_num_len = 0;
818195534Sscottl			}
819195534Sscottl			path->device->serial_num =
820195534Sscottl				(u_int8_t *)malloc((sizeof(ident_buf->serial) + 1),
821198708Smav					   M_CAMXPT, M_NOWAIT);
822195534Sscottl			if (path->device->serial_num != NULL) {
823195534Sscottl				bcopy(ident_buf->serial,
824195534Sscottl				      path->device->serial_num,
825195534Sscottl				      sizeof(ident_buf->serial));
826195534Sscottl				path->device->serial_num[sizeof(ident_buf->serial)]
827195534Sscottl				    = '\0';
828195534Sscottl				path->device->serial_num_len =
829195534Sscottl				    strlen(path->device->serial_num);
830195534Sscottl			}
831195534Sscottl
832198331Smav			path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID;
833195534Sscottl		}
834199178Smav		if (ident_buf->satacapabilities & ATA_SUPPORT_NCQ) {
835199178Smav			path->device->mintags = path->device->maxtags =
836199178Smav			    ATA_QUEUE_LEN(ident_buf->queue) + 1;
837199178Smav		}
838199178Smav		ata_find_quirk(path->device);
839199263Smav		if (path->device->mintags != 0 &&
840199263Smav		    path->bus->sim->max_tagged_dev_openings != 0) {
841199747Smav			/* Report SIM which tags are allowed. */
842199747Smav			bzero(&cts, sizeof(cts));
843203108Smav			xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
844199747Smav			cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
845199747Smav			cts.type = CTS_TYPE_CURRENT_SETTINGS;
846199747Smav			cts.xport_specific.sata.tags = path->device->maxtags;
847199747Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_TAGS;
848199747Smav			xpt_action((union ccb *)&cts);
849199747Smav			/* Reconfigure queues for tagged queueing. */
850199178Smav			xpt_start_tags(path);
851199178Smav		}
852198708Smav		ata_device_transport(path);
853198708Smav		PROBE_SET_ACTION(softc, PROBE_SETMODE);
854195534Sscottl		xpt_release_ccb(done_ccb);
855198708Smav		xpt_schedule(periph, priority);
856198708Smav		return;
857195534Sscottl	}
858203421Smav	case PROBE_SPINUP:
859203421Smav		if (bootverbose)
860203421Smav			xpt_print(path, "Spin-up done\n");
861203421Smav		softc->spinup = 1;
862203421Smav		PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
863203421Smav		xpt_release_ccb(done_ccb);
864203421Smav		xpt_schedule(periph, priority);
865203421Smav		return;
866195534Sscottl	case PROBE_SETMODE:
867198708Smav		if (path->device->protocol == PROTO_ATA) {
868198708Smav			PROBE_SET_ACTION(softc, PROBE_SET_MULTI);
869198708Smav		} else {
870198708Smav			PROBE_SET_ACTION(softc, PROBE_INQUIRY);
871195534Sscottl		}
872198708Smav		xpt_release_ccb(done_ccb);
873198708Smav		xpt_schedule(periph, priority);
874198708Smav		return;
875198708Smav	case PROBE_SET_MULTI:
876198708Smav		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
877198708Smav			path->device->flags &= ~CAM_DEV_UNCONFIGURED;
878198748Smav			xpt_acquire_device(path->device);
879198708Smav			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
880198708Smav			xpt_action(done_ccb);
881198708Smav			xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path,
882198708Smav			    done_ccb);
883198708Smav		}
884198708Smav		break;
885195534Sscottl	case PROBE_INQUIRY:
886195534Sscottl	case PROBE_FULL_INQUIRY:
887195534Sscottl	{
888198708Smav		struct scsi_inquiry_data *inq_buf;
889198708Smav		u_int8_t periph_qual, len;
890195534Sscottl
891198708Smav		path->device->flags |= CAM_DEV_INQUIRY_DATA_VALID;
892198708Smav		inq_buf = &path->device->inq_data;
893195534Sscottl
894198708Smav		periph_qual = SID_QUAL(inq_buf);
895195534Sscottl
896198708Smav		if (periph_qual != SID_QUAL_LU_CONNECTED)
897198708Smav			break;
898195534Sscottl
899198708Smav		/*
900198708Smav		 * We conservatively request only
901198708Smav		 * SHORT_INQUIRY_LEN bytes of inquiry
902198708Smav		 * information during our first try
903198708Smav		 * at sending an INQUIRY. If the device
904198708Smav		 * has more information to give,
905198708Smav		 * perform a second request specifying
906198708Smav		 * the amount of information the device
907198708Smav		 * is willing to give.
908198708Smav		 */
909198708Smav		len = inq_buf->additional_length
910198708Smav		    + offsetof(struct scsi_inquiry_data, additional_length) + 1;
911198708Smav		if (softc->action == PROBE_INQUIRY
912198708Smav		    && len > SHORT_INQUIRY_LENGTH) {
913198708Smav			PROBE_SET_ACTION(softc, PROBE_FULL_INQUIRY);
914198708Smav			xpt_release_ccb(done_ccb);
915198708Smav			xpt_schedule(periph, priority);
916195534Sscottl			return;
917195534Sscottl		}
918198708Smav
919198708Smav		ata_device_transport(path);
920198708Smav		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
921198708Smav			path->device->flags &= ~CAM_DEV_UNCONFIGURED;
922198748Smav			xpt_acquire_device(path->device);
923198708Smav			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
924198708Smav			xpt_action(done_ccb);
925198708Smav			xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, done_ccb);
926198708Smav		}
927198708Smav		break;
928195534Sscottl	}
929195534Sscottl	case PROBE_PM_PID:
930198708Smav		if ((path->device->flags & CAM_DEV_IDENTIFY_DATA_VALID) == 0)
931198708Smav			bzero(ident_buf, sizeof(*ident_buf));
932198708Smav		softc->pm_pid = (done_ccb->ataio.res.lba_high << 24) +
933198708Smav		    (done_ccb->ataio.res.lba_mid << 16) +
934198708Smav		    (done_ccb->ataio.res.lba_low << 8) +
935198708Smav		    done_ccb->ataio.res.sector_count;
936198708Smav		((uint32_t *)ident_buf)[0] = softc->pm_pid;
937198708Smav		snprintf(ident_buf->model, sizeof(ident_buf->model),
938198708Smav		    "Port Multiplier %08x", softc->pm_pid);
939198708Smav		PROBE_SET_ACTION(softc, PROBE_PM_PRV);
940198708Smav		xpt_release_ccb(done_ccb);
941198708Smav		xpt_schedule(periph, priority);
942198708Smav		return;
943195534Sscottl	case PROBE_PM_PRV:
944198708Smav		softc->pm_prv = (done_ccb->ataio.res.lba_high << 24) +
945198708Smav		    (done_ccb->ataio.res.lba_mid << 16) +
946198708Smav		    (done_ccb->ataio.res.lba_low << 8) +
947198708Smav		    done_ccb->ataio.res.sector_count;
948198708Smav		((uint32_t *)ident_buf)[1] = softc->pm_prv;
949198708Smav		snprintf(ident_buf->revision, sizeof(ident_buf->revision),
950198708Smav		    "%04x", softc->pm_prv);
951198708Smav		path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID;
952198708Smav		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
953198708Smav			path->device->flags &= ~CAM_DEV_UNCONFIGURED;
954198748Smav			xpt_acquire_device(path->device);
955198708Smav			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
956198708Smav			xpt_action(done_ccb);
957198708Smav			xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path,
958198708Smav			    done_ccb);
959198708Smav		} else {
960198708Smav			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
961198708Smav			xpt_action(done_ccb);
962198708Smav			xpt_async(AC_SCSI_AEN, done_ccb->ccb_h.path, done_ccb);
963195534Sscottl		}
964198708Smav		break;
965195534Sscottl	case PROBE_INVALID:
966195534Sscottl		CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_INFO,
967195534Sscottl		    ("probedone: invalid action state\n"));
968195534Sscottl	default:
969195534Sscottl		break;
970195534Sscottl	}
971198708Smavdone:
972203108Smav	if (softc->restart) {
973203108Smav		softc->restart = 0;
974203108Smav		xpt_release_ccb(done_ccb);
975195534Sscottl		probeschedule(periph);
976203108Smav		return;
977195534Sscottl	}
978203108Smav	xpt_release_ccb(done_ccb);
979203108Smav	while ((done_ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs))) {
980203108Smav		TAILQ_REMOVE(&softc->request_ccbs,
981203108Smav		    &done_ccb->ccb_h, periph_links.tqe);
982203108Smav		done_ccb->ccb_h.status = found ? CAM_REQ_CMP : CAM_REQ_CMP_ERR;
983203108Smav		xpt_done(done_ccb);
984203108Smav	}
985203108Smav	cam_release_devq(periph->path,
986203108Smav	    RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_XPT + 1, FALSE);
987203108Smav	cam_periph_invalidate(periph);
988203108Smav	cam_periph_release_locked(periph);
989195534Sscottl}
990195534Sscottl
991195534Sscottlstatic void
992195534Sscottlprobecleanup(struct cam_periph *periph)
993195534Sscottl{
994195534Sscottl	free(periph->softc, M_CAMXPT);
995195534Sscottl}
996195534Sscottl
997195534Sscottlstatic void
998199178Smavata_find_quirk(struct cam_ed *device)
999195534Sscottl{
1000199178Smav	struct ata_quirk_entry *quirk;
1001195534Sscottl	caddr_t	match;
1002195534Sscottl
1003199178Smav	match = cam_quirkmatch((caddr_t)&device->ident_data,
1004199178Smav			       (caddr_t)ata_quirk_table,
1005199178Smav			       ata_quirk_table_size,
1006199178Smav			       sizeof(*ata_quirk_table), ata_identify_match);
1007195534Sscottl
1008195534Sscottl	if (match == NULL)
1009195534Sscottl		panic("xpt_find_quirk: device didn't match wildcard entry!!");
1010195534Sscottl
1011199178Smav	quirk = (struct ata_quirk_entry *)match;
1012195534Sscottl	device->quirk = quirk;
1013199178Smav	if (quirk->quirks & CAM_QUIRK_MAXTAGS)
1014199178Smav		device->mintags = device->maxtags = quirk->maxtags;
1015195534Sscottl}
1016195534Sscottl
1017195534Sscottltypedef struct {
1018195534Sscottl	union	ccb *request_ccb;
1019195534Sscottl	struct 	ccb_pathinq *cpi;
1020195534Sscottl	int	counter;
1021195534Sscottl} ata_scan_bus_info;
1022195534Sscottl
1023195534Sscottl/*
1024195534Sscottl * To start a scan, request_ccb is an XPT_SCAN_BUS ccb.
1025195534Sscottl * As the scan progresses, xpt_scan_bus is used as the
1026195534Sscottl * callback on completion function.
1027195534Sscottl */
1028195534Sscottlstatic void
1029195534Sscottlata_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
1030195534Sscottl{
1031195534Sscottl	struct	cam_path *path;
1032195534Sscottl	ata_scan_bus_info *scan_info;
1033203108Smav	union	ccb *work_ccb, *reset_ccb;
1034195534Sscottl	cam_status status;
1035195534Sscottl
1036195534Sscottl	CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE,
1037195534Sscottl		  ("xpt_scan_bus\n"));
1038195534Sscottl	switch (request_ccb->ccb_h.func_code) {
1039195534Sscottl	case XPT_SCAN_BUS:
1040195534Sscottl		/* Find out the characteristics of the bus */
1041195534Sscottl		work_ccb = xpt_alloc_ccb_nowait();
1042195534Sscottl		if (work_ccb == NULL) {
1043195534Sscottl			request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1044195534Sscottl			xpt_done(request_ccb);
1045195534Sscottl			return;
1046195534Sscottl		}
1047195534Sscottl		xpt_setup_ccb(&work_ccb->ccb_h, request_ccb->ccb_h.path,
1048195534Sscottl			      request_ccb->ccb_h.pinfo.priority);
1049195534Sscottl		work_ccb->ccb_h.func_code = XPT_PATH_INQ;
1050195534Sscottl		xpt_action(work_ccb);
1051195534Sscottl		if (work_ccb->ccb_h.status != CAM_REQ_CMP) {
1052195534Sscottl			request_ccb->ccb_h.status = work_ccb->ccb_h.status;
1053195534Sscottl			xpt_free_ccb(work_ccb);
1054195534Sscottl			xpt_done(request_ccb);
1055195534Sscottl			return;
1056195534Sscottl		}
1057195534Sscottl
1058203108Smav		/* We may need to reset bus first, if we haven't done it yet. */
1059203108Smav		if ((work_ccb->cpi.hba_inquiry &
1060203108Smav		    (PI_WIDE_32|PI_WIDE_16|PI_SDTR_ABLE)) &&
1061203108Smav		    !(work_ccb->cpi.hba_misc & PIM_NOBUSRESET) &&
1062203108Smav		    !timevalisset(&request_ccb->ccb_h.path->bus->last_reset)) {
1063203108Smav			reset_ccb = xpt_alloc_ccb_nowait();
1064203108Smav			xpt_setup_ccb(&reset_ccb->ccb_h, request_ccb->ccb_h.path,
1065203108Smav			      CAM_PRIORITY_NONE);
1066203108Smav			reset_ccb->ccb_h.func_code = XPT_RESET_BUS;
1067203108Smav			xpt_action(reset_ccb);
1068203108Smav			if (reset_ccb->ccb_h.status != CAM_REQ_CMP) {
1069203108Smav				request_ccb->ccb_h.status = reset_ccb->ccb_h.status;
1070203108Smav				xpt_free_ccb(reset_ccb);
1071203108Smav				xpt_free_ccb(work_ccb);
1072203108Smav				xpt_done(request_ccb);
1073203108Smav				return;
1074203108Smav			}
1075203108Smav			xpt_free_ccb(reset_ccb);
1076203108Smav		}
1077203108Smav
1078195534Sscottl		/* Save some state for use while we probe for devices */
1079195534Sscottl		scan_info = (ata_scan_bus_info *)
1080195534Sscottl		    malloc(sizeof(ata_scan_bus_info), M_CAMXPT, M_NOWAIT);
1081195534Sscottl		if (scan_info == NULL) {
1082195534Sscottl			request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1083195534Sscottl			xpt_done(request_ccb);
1084195534Sscottl			return;
1085195534Sscottl		}
1086195534Sscottl		scan_info->request_ccb = request_ccb;
1087195534Sscottl		scan_info->cpi = &work_ccb->cpi;
1088195534Sscottl		/* If PM supported, probe it first. */
1089195534Sscottl		if (scan_info->cpi->hba_inquiry & PI_SATAPM)
1090201990Smav			scan_info->counter = scan_info->cpi->max_target;
1091201990Smav		else
1092201990Smav			scan_info->counter = 0;
1093195534Sscottl
1094195534Sscottl		work_ccb = xpt_alloc_ccb_nowait();
1095195534Sscottl		if (work_ccb == NULL) {
1096195534Sscottl			free(scan_info, M_CAMXPT);
1097195534Sscottl			request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1098195534Sscottl			xpt_done(request_ccb);
1099195534Sscottl			break;
1100195534Sscottl		}
1101195534Sscottl		goto scan_next;
1102195534Sscottl	case XPT_SCAN_LUN:
1103195534Sscottl		work_ccb = request_ccb;
1104195534Sscottl		/* Reuse the same CCB to query if a device was really found */
1105195534Sscottl		scan_info = (ata_scan_bus_info *)work_ccb->ccb_h.ppriv_ptr0;
1106195534Sscottl		/* Free the current request path- we're done with it. */
1107195534Sscottl		xpt_free_path(work_ccb->ccb_h.path);
1108198389Smav		/* If there is PMP... */
1109201990Smav		if ((scan_info->cpi->hba_inquiry & PI_SATAPM) &&
1110201990Smav		    (scan_info->counter == scan_info->cpi->max_target)) {
1111203108Smav			if (work_ccb->ccb_h.status == CAM_REQ_CMP) {
1112198389Smav				/* everything else willbe probed by it */
1113201990Smav				goto done;
1114195534Sscottl			} else {
1115195534Sscottl				struct ccb_trans_settings cts;
1116195534Sscottl
1117195534Sscottl				/* Report SIM that PM is absent. */
1118195534Sscottl				bzero(&cts, sizeof(cts));
1119195534Sscottl				xpt_setup_ccb(&cts.ccb_h,
1120195534Sscottl				    scan_info->request_ccb->ccb_h.path, 1);
1121195534Sscottl				cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
1122195534Sscottl				cts.type = CTS_TYPE_CURRENT_SETTINGS;
1123195665Smav				cts.xport_specific.sata.pm_present = 0;
1124195534Sscottl				cts.xport_specific.sata.valid = CTS_SATA_VALID_PM;
1125195534Sscottl				xpt_action((union ccb *)&cts);
1126195534Sscottl			}
1127195534Sscottl		}
1128201990Smav		if (scan_info->counter ==
1129201990Smav		    ((scan_info->cpi->hba_inquiry & PI_SATAPM) ?
1130201990Smav		    0 : scan_info->cpi->max_target)) {
1131201990Smavdone:
1132195534Sscottl			xpt_free_ccb(work_ccb);
1133195534Sscottl			xpt_free_ccb((union ccb *)scan_info->cpi);
1134195534Sscottl			request_ccb = scan_info->request_ccb;
1135195534Sscottl			free(scan_info, M_CAMXPT);
1136195534Sscottl			request_ccb->ccb_h.status = CAM_REQ_CMP;
1137195534Sscottl			xpt_done(request_ccb);
1138195534Sscottl			break;
1139195534Sscottl		}
1140201990Smav		/* Take next device. Wrap from max (PMP) to 0. */
1141201990Smav		scan_info->counter = (scan_info->counter + 1 ) %
1142201990Smav		    (scan_info->cpi->max_target + 1);
1143195534Sscottlscan_next:
1144195534Sscottl		status = xpt_create_path(&path, xpt_periph,
1145195534Sscottl		    scan_info->request_ccb->ccb_h.path_id,
1146195534Sscottl		    scan_info->counter, 0);
1147195534Sscottl		if (status != CAM_REQ_CMP) {
1148195534Sscottl			printf("xpt_scan_bus: xpt_create_path failed"
1149195534Sscottl			    " with status %#x, bus scan halted\n",
1150195534Sscottl			    status);
1151195534Sscottl			xpt_free_ccb(work_ccb);
1152195534Sscottl			xpt_free_ccb((union ccb *)scan_info->cpi);
1153195534Sscottl			request_ccb = scan_info->request_ccb;
1154195534Sscottl			free(scan_info, M_CAMXPT);
1155195534Sscottl			request_ccb->ccb_h.status = status;
1156195534Sscottl			xpt_done(request_ccb);
1157195534Sscottl			break;
1158195534Sscottl		}
1159195534Sscottl		xpt_setup_ccb(&work_ccb->ccb_h, path,
1160195534Sscottl		    scan_info->request_ccb->ccb_h.pinfo.priority);
1161195534Sscottl		work_ccb->ccb_h.func_code = XPT_SCAN_LUN;
1162195534Sscottl		work_ccb->ccb_h.cbfcnp = ata_scan_bus;
1163195534Sscottl		work_ccb->ccb_h.ppriv_ptr0 = scan_info;
1164195534Sscottl		work_ccb->crcn.flags = scan_info->request_ccb->crcn.flags;
1165195534Sscottl		xpt_action(work_ccb);
1166195534Sscottl		break;
1167195534Sscottl	default:
1168195534Sscottl		break;
1169195534Sscottl	}
1170195534Sscottl}
1171195534Sscottl
1172195534Sscottlstatic void
1173195534Sscottlata_scan_lun(struct cam_periph *periph, struct cam_path *path,
1174195534Sscottl	     cam_flags flags, union ccb *request_ccb)
1175195534Sscottl{
1176195534Sscottl	struct ccb_pathinq cpi;
1177195534Sscottl	cam_status status;
1178195534Sscottl	struct cam_path *new_path;
1179195534Sscottl	struct cam_periph *old_periph;
1180195534Sscottl
1181203108Smav	CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_scan_lun\n"));
1182195534Sscottl
1183203108Smav	xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE);
1184195534Sscottl	cpi.ccb_h.func_code = XPT_PATH_INQ;
1185195534Sscottl	xpt_action((union ccb *)&cpi);
1186195534Sscottl
1187195534Sscottl	if (cpi.ccb_h.status != CAM_REQ_CMP) {
1188195534Sscottl		if (request_ccb != NULL) {
1189195534Sscottl			request_ccb->ccb_h.status = cpi.ccb_h.status;
1190195534Sscottl			xpt_done(request_ccb);
1191195534Sscottl		}
1192195534Sscottl		return;
1193195534Sscottl	}
1194195534Sscottl
1195195534Sscottl	if (request_ccb == NULL) {
1196195534Sscottl		request_ccb = malloc(sizeof(union ccb), M_CAMXPT, M_NOWAIT);
1197195534Sscottl		if (request_ccb == NULL) {
1198195534Sscottl			xpt_print(path, "xpt_scan_lun: can't allocate CCB, "
1199195534Sscottl			    "can't continue\n");
1200195534Sscottl			return;
1201195534Sscottl		}
1202195534Sscottl		new_path = malloc(sizeof(*new_path), M_CAMXPT, M_NOWAIT);
1203195534Sscottl		if (new_path == NULL) {
1204195534Sscottl			xpt_print(path, "xpt_scan_lun: can't allocate path, "
1205195534Sscottl			    "can't continue\n");
1206195534Sscottl			free(request_ccb, M_CAMXPT);
1207195534Sscottl			return;
1208195534Sscottl		}
1209195534Sscottl		status = xpt_compile_path(new_path, xpt_periph,
1210195534Sscottl					  path->bus->path_id,
1211195534Sscottl					  path->target->target_id,
1212195534Sscottl					  path->device->lun_id);
1213195534Sscottl
1214195534Sscottl		if (status != CAM_REQ_CMP) {
1215195534Sscottl			xpt_print(path, "xpt_scan_lun: can't compile path, "
1216195534Sscottl			    "can't continue\n");
1217195534Sscottl			free(request_ccb, M_CAMXPT);
1218195534Sscottl			free(new_path, M_CAMXPT);
1219195534Sscottl			return;
1220195534Sscottl		}
1221203108Smav		xpt_setup_ccb(&request_ccb->ccb_h, new_path, CAM_PRIORITY_XPT);
1222195534Sscottl		request_ccb->ccb_h.cbfcnp = xptscandone;
1223195534Sscottl		request_ccb->ccb_h.func_code = XPT_SCAN_LUN;
1224195534Sscottl		request_ccb->crcn.flags = flags;
1225195534Sscottl	}
1226195534Sscottl
1227195653Smav	if ((old_periph = cam_periph_find(path, "aprobe")) != NULL) {
1228195534Sscottl		probe_softc *softc;
1229195534Sscottl
1230195534Sscottl		softc = (probe_softc *)old_periph->softc;
1231195534Sscottl		TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h,
1232195534Sscottl				  periph_links.tqe);
1233203108Smav		softc->restart = 1;
1234195534Sscottl	} else {
1235195534Sscottl		status = cam_periph_alloc(proberegister, NULL, probecleanup,
1236195653Smav					  probestart, "aprobe",
1237195534Sscottl					  CAM_PERIPH_BIO,
1238195534Sscottl					  request_ccb->ccb_h.path, NULL, 0,
1239195534Sscottl					  request_ccb);
1240195534Sscottl
1241195534Sscottl		if (status != CAM_REQ_CMP) {
1242195534Sscottl			xpt_print(path, "xpt_scan_lun: cam_alloc_periph "
1243195534Sscottl			    "returned an error, can't continue probe\n");
1244195534Sscottl			request_ccb->ccb_h.status = status;
1245195534Sscottl			xpt_done(request_ccb);
1246195534Sscottl		}
1247195534Sscottl	}
1248195534Sscottl}
1249195534Sscottl
1250195534Sscottlstatic void
1251195534Sscottlxptscandone(struct cam_periph *periph, union ccb *done_ccb)
1252195534Sscottl{
1253195534Sscottl	xpt_release_path(done_ccb->ccb_h.path);
1254195534Sscottl	free(done_ccb->ccb_h.path, M_CAMXPT);
1255195534Sscottl	free(done_ccb, M_CAMXPT);
1256195534Sscottl}
1257195534Sscottl
1258195534Sscottlstatic struct cam_ed *
1259195534Sscottlata_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id)
1260195534Sscottl{
1261195534Sscottl	struct cam_path path;
1262199178Smav	struct ata_quirk_entry *quirk;
1263195534Sscottl	struct cam_ed *device;
1264195534Sscottl	struct cam_ed *cur_device;
1265195534Sscottl
1266195534Sscottl	device = xpt_alloc_device(bus, target, lun_id);
1267195534Sscottl	if (device == NULL)
1268195534Sscottl		return (NULL);
1269195534Sscottl
1270195534Sscottl	/*
1271195534Sscottl	 * Take the default quirk entry until we have inquiry
1272195534Sscottl	 * data and can determine a better quirk to use.
1273195534Sscottl	 */
1274199178Smav	quirk = &ata_quirk_table[ata_quirk_table_size - 1];
1275195534Sscottl	device->quirk = (void *)quirk;
1276199178Smav	device->mintags = 0;
1277199178Smav	device->maxtags = 0;
1278195534Sscottl	bzero(&device->inq_data, sizeof(device->inq_data));
1279195534Sscottl	device->inq_flags = 0;
1280195534Sscottl	device->queue_flags = 0;
1281195534Sscottl	device->serial_num = NULL;
1282195534Sscottl	device->serial_num_len = 0;
1283195534Sscottl
1284195534Sscottl	/*
1285195534Sscottl	 * XXX should be limited by number of CCBs this bus can
1286195534Sscottl	 * do.
1287195534Sscottl	 */
1288195534Sscottl	bus->sim->max_ccbs += device->ccbq.devq_openings;
1289195534Sscottl	/* Insertion sort into our target's device list */
1290195534Sscottl	cur_device = TAILQ_FIRST(&target->ed_entries);
1291195534Sscottl	while (cur_device != NULL && cur_device->lun_id < lun_id)
1292195534Sscottl		cur_device = TAILQ_NEXT(cur_device, links);
1293195534Sscottl	if (cur_device != NULL) {
1294195534Sscottl		TAILQ_INSERT_BEFORE(cur_device, device, links);
1295195534Sscottl	} else {
1296195534Sscottl		TAILQ_INSERT_TAIL(&target->ed_entries, device, links);
1297195534Sscottl	}
1298195534Sscottl	target->generation++;
1299195534Sscottl	if (lun_id != CAM_LUN_WILDCARD) {
1300195534Sscottl		xpt_compile_path(&path,
1301195534Sscottl				 NULL,
1302195534Sscottl				 bus->path_id,
1303195534Sscottl				 target->target_id,
1304195534Sscottl				 lun_id);
1305195534Sscottl		ata_device_transport(&path);
1306195534Sscottl		xpt_release_path(&path);
1307195534Sscottl	}
1308195534Sscottl
1309195534Sscottl	return (device);
1310195534Sscottl}
1311195534Sscottl
1312195534Sscottlstatic void
1313195534Sscottlata_device_transport(struct cam_path *path)
1314195534Sscottl{
1315195534Sscottl	struct ccb_pathinq cpi;
1316198331Smav	struct ccb_trans_settings cts;
1317198331Smav	struct scsi_inquiry_data *inq_buf = NULL;
1318198331Smav	struct ata_params *ident_buf = NULL;
1319195534Sscottl
1320195534Sscottl	/* Get transport information from the SIM */
1321203108Smav	xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE);
1322195534Sscottl	cpi.ccb_h.func_code = XPT_PATH_INQ;
1323195534Sscottl	xpt_action((union ccb *)&cpi);
1324195534Sscottl
1325195534Sscottl	path->device->transport = cpi.transport;
1326198331Smav	if ((path->device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0)
1327198331Smav		inq_buf = &path->device->inq_data;
1328198331Smav	if ((path->device->flags & CAM_DEV_IDENTIFY_DATA_VALID) != 0)
1329198331Smav		ident_buf = &path->device->ident_data;
1330198331Smav	if (path->device->protocol == PROTO_ATA) {
1331198331Smav		path->device->protocol_version = ident_buf ?
1332198331Smav		    ata_version(ident_buf->version_major) : cpi.protocol_version;
1333198331Smav	} else if (path->device->protocol == PROTO_SCSI) {
1334198331Smav		path->device->protocol_version = inq_buf ?
1335198331Smav		    SID_ANSI_REV(inq_buf) : cpi.protocol_version;
1336195534Sscottl	}
1337198331Smav	path->device->transport_version = ident_buf ?
1338198331Smav	    ata_version(ident_buf->version_major) : cpi.transport_version;
1339195534Sscottl
1340195534Sscottl	/* Tell the controller what we think */
1341203108Smav	xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
1342195534Sscottl	cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
1343195534Sscottl	cts.type = CTS_TYPE_CURRENT_SETTINGS;
1344195534Sscottl	cts.transport = path->device->transport;
1345195534Sscottl	cts.transport_version = path->device->transport_version;
1346195534Sscottl	cts.protocol = path->device->protocol;
1347195534Sscottl	cts.protocol_version = path->device->protocol_version;
1348195534Sscottl	cts.proto_specific.valid = 0;
1349203376Smav	if (ident_buf) {
1350203376Smav		if (path->device->transport == XPORT_ATA) {
1351203376Smav			cts.xport_specific.ata.atapi =
1352203376Smav			    ((ident_buf->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_16) ? 16 :
1353203376Smav			    ((ident_buf->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12) ? 12 : 0;
1354203376Smav			cts.xport_specific.ata.valid = CTS_ATA_VALID_ATAPI;
1355203376Smav		} else {
1356203376Smav			cts.xport_specific.sata.atapi =
1357203376Smav			    ((ident_buf->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_16) ? 16 :
1358203376Smav			    ((ident_buf->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12) ? 12 : 0;
1359203376Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_ATAPI;
1360203376Smav		}
1361203376Smav	} else
1362203376Smav		cts.xport_specific.valid = 0;
1363195534Sscottl	xpt_action((union ccb *)&cts);
1364195534Sscottl}
1365195534Sscottl
1366195534Sscottlstatic void
1367195534Sscottlata_action(union ccb *start_ccb)
1368195534Sscottl{
1369195534Sscottl
1370195534Sscottl	switch (start_ccb->ccb_h.func_code) {
1371195534Sscottl	case XPT_SET_TRAN_SETTINGS:
1372195534Sscottl	{
1373199178Smav		ata_set_transfer_settings(&start_ccb->cts,
1374195534Sscottl					   start_ccb->ccb_h.path->device,
1375195534Sscottl					   /*async_update*/FALSE);
1376195534Sscottl		break;
1377195534Sscottl	}
1378195534Sscottl	case XPT_SCAN_BUS:
1379195534Sscottl		ata_scan_bus(start_ccb->ccb_h.path->periph, start_ccb);
1380195534Sscottl		break;
1381195534Sscottl	case XPT_SCAN_LUN:
1382195534Sscottl		ata_scan_lun(start_ccb->ccb_h.path->periph,
1383195534Sscottl			      start_ccb->ccb_h.path, start_ccb->crcn.flags,
1384195534Sscottl			      start_ccb);
1385195534Sscottl		break;
1386195534Sscottl	case XPT_GET_TRAN_SETTINGS:
1387195534Sscottl	{
1388195534Sscottl		struct cam_sim *sim;
1389195534Sscottl
1390195534Sscottl		sim = start_ccb->ccb_h.path->bus->sim;
1391195534Sscottl		(*(sim->sim_action))(sim, start_ccb);
1392195534Sscottl		break;
1393195534Sscottl	}
1394203376Smav	case XPT_SCSI_IO:
1395203376Smav	{
1396203376Smav		struct cam_ed *device;
1397203376Smav		u_int	maxlen = 0;
1398203376Smav
1399203376Smav		device = start_ccb->ccb_h.path->device;
1400203376Smav		if (device->protocol == PROTO_SCSI &&
1401203376Smav		    (device->flags & CAM_DEV_IDENTIFY_DATA_VALID)) {
1402203376Smav			uint16_t p =
1403203376Smav			    device->ident_data.config & ATA_PROTO_MASK;
1404203376Smav
1405203376Smav			maxlen = (p == ATA_PROTO_ATAPI_16) ? 16 :
1406203376Smav			    (p == ATA_PROTO_ATAPI_12) ? 12 : 0;
1407203376Smav		}
1408203376Smav		if (start_ccb->csio.cdb_len > maxlen) {
1409203376Smav			start_ccb->ccb_h.status = CAM_REQ_INVALID;
1410203376Smav			xpt_done(start_ccb);
1411203376Smav			break;
1412203376Smav		}
1413203376Smav		/* FALLTHROUGH */
1414203376Smav	}
1415195534Sscottl	default:
1416195534Sscottl		xpt_action_default(start_ccb);
1417195534Sscottl		break;
1418195534Sscottl	}
1419195534Sscottl}
1420195534Sscottl
1421195534Sscottlstatic void
1422199178Smavata_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device,
1423195534Sscottl			   int async_update)
1424195534Sscottl{
1425195534Sscottl	struct	ccb_pathinq cpi;
1426195534Sscottl	struct	ccb_trans_settings cur_cts;
1427195534Sscottl	struct	ccb_trans_settings_scsi *scsi;
1428195534Sscottl	struct	ccb_trans_settings_scsi *cur_scsi;
1429195534Sscottl	struct	cam_sim *sim;
1430195534Sscottl	struct	scsi_inquiry_data *inq_data;
1431195534Sscottl
1432195534Sscottl	if (device == NULL) {
1433195534Sscottl		cts->ccb_h.status = CAM_PATH_INVALID;
1434195534Sscottl		xpt_done((union ccb *)cts);
1435195534Sscottl		return;
1436195534Sscottl	}
1437195534Sscottl
1438195534Sscottl	if (cts->protocol == PROTO_UNKNOWN
1439195534Sscottl	 || cts->protocol == PROTO_UNSPECIFIED) {
1440195534Sscottl		cts->protocol = device->protocol;
1441195534Sscottl		cts->protocol_version = device->protocol_version;
1442195534Sscottl	}
1443195534Sscottl
1444195534Sscottl	if (cts->protocol_version == PROTO_VERSION_UNKNOWN
1445195534Sscottl	 || cts->protocol_version == PROTO_VERSION_UNSPECIFIED)
1446195534Sscottl		cts->protocol_version = device->protocol_version;
1447195534Sscottl
1448195534Sscottl	if (cts->protocol != device->protocol) {
1449195534Sscottl		xpt_print(cts->ccb_h.path, "Uninitialized Protocol %x:%x?\n",
1450195534Sscottl		       cts->protocol, device->protocol);
1451195534Sscottl		cts->protocol = device->protocol;
1452195534Sscottl	}
1453195534Sscottl
1454195534Sscottl	if (cts->protocol_version > device->protocol_version) {
1455195534Sscottl		if (bootverbose) {
1456195534Sscottl			xpt_print(cts->ccb_h.path, "Down reving Protocol "
1457195534Sscottl			    "Version from %d to %d?\n", cts->protocol_version,
1458195534Sscottl			    device->protocol_version);
1459195534Sscottl		}
1460195534Sscottl		cts->protocol_version = device->protocol_version;
1461195534Sscottl	}
1462195534Sscottl
1463195534Sscottl	if (cts->transport == XPORT_UNKNOWN
1464195534Sscottl	 || cts->transport == XPORT_UNSPECIFIED) {
1465195534Sscottl		cts->transport = device->transport;
1466195534Sscottl		cts->transport_version = device->transport_version;
1467195534Sscottl	}
1468195534Sscottl
1469195534Sscottl	if (cts->transport_version == XPORT_VERSION_UNKNOWN
1470195534Sscottl	 || cts->transport_version == XPORT_VERSION_UNSPECIFIED)
1471195534Sscottl		cts->transport_version = device->transport_version;
1472195534Sscottl
1473195534Sscottl	if (cts->transport != device->transport) {
1474195534Sscottl		xpt_print(cts->ccb_h.path, "Uninitialized Transport %x:%x?\n",
1475195534Sscottl		    cts->transport, device->transport);
1476195534Sscottl		cts->transport = device->transport;
1477195534Sscottl	}
1478195534Sscottl
1479195534Sscottl	if (cts->transport_version > device->transport_version) {
1480195534Sscottl		if (bootverbose) {
1481195534Sscottl			xpt_print(cts->ccb_h.path, "Down reving Transport "
1482195534Sscottl			    "Version from %d to %d?\n", cts->transport_version,
1483195534Sscottl			    device->transport_version);
1484195534Sscottl		}
1485195534Sscottl		cts->transport_version = device->transport_version;
1486195534Sscottl	}
1487195534Sscottl
1488195534Sscottl	sim = cts->ccb_h.path->bus->sim;
1489195534Sscottl
1490195534Sscottl	/*
1491195534Sscottl	 * Nothing more of interest to do unless
1492195534Sscottl	 * this is a device connected via the
1493195534Sscottl	 * SCSI protocol.
1494195534Sscottl	 */
1495195534Sscottl	if (cts->protocol != PROTO_SCSI) {
1496195534Sscottl		if (async_update == FALSE)
1497195534Sscottl			(*(sim->sim_action))(sim, (union ccb *)cts);
1498195534Sscottl		return;
1499195534Sscottl	}
1500195534Sscottl
1501195534Sscottl	inq_data = &device->inq_data;
1502195534Sscottl	scsi = &cts->proto_specific.scsi;
1503203108Smav	xpt_setup_ccb(&cpi.ccb_h, cts->ccb_h.path, CAM_PRIORITY_NONE);
1504195534Sscottl	cpi.ccb_h.func_code = XPT_PATH_INQ;
1505195534Sscottl	xpt_action((union ccb *)&cpi);
1506195534Sscottl
1507195534Sscottl	/* SCSI specific sanity checking */
1508195534Sscottl	if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0
1509195534Sscottl	 || (INQ_DATA_TQ_ENABLED(inq_data)) == 0
1510195534Sscottl	 || (device->queue_flags & SCP_QUEUE_DQUE) != 0
1511195534Sscottl	 || (device->mintags == 0)) {
1512195534Sscottl		/*
1513195534Sscottl		 * Can't tag on hardware that doesn't support tags,
1514195534Sscottl		 * doesn't have it enabled, or has broken tag support.
1515195534Sscottl		 */
1516195534Sscottl		scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
1517195534Sscottl	}
1518195534Sscottl
1519195534Sscottl	if (async_update == FALSE) {
1520195534Sscottl		/*
1521195534Sscottl		 * Perform sanity checking against what the
1522195534Sscottl		 * controller and device can do.
1523195534Sscottl		 */
1524203108Smav		xpt_setup_ccb(&cur_cts.ccb_h, cts->ccb_h.path, CAM_PRIORITY_NONE);
1525195534Sscottl		cur_cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
1526195534Sscottl		cur_cts.type = cts->type;
1527195534Sscottl		xpt_action((union ccb *)&cur_cts);
1528195534Sscottl		if ((cur_cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1529195534Sscottl			return;
1530195534Sscottl		}
1531195534Sscottl		cur_scsi = &cur_cts.proto_specific.scsi;
1532195534Sscottl		if ((scsi->valid & CTS_SCSI_VALID_TQ) == 0) {
1533195534Sscottl			scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
1534195534Sscottl			scsi->flags |= cur_scsi->flags & CTS_SCSI_FLAGS_TAG_ENB;
1535195534Sscottl		}
1536195534Sscottl		if ((cur_scsi->valid & CTS_SCSI_VALID_TQ) == 0)
1537195534Sscottl			scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
1538195534Sscottl	}
1539195534Sscottl
1540195534Sscottl	if (cts->type == CTS_TYPE_CURRENT_SETTINGS
1541195534Sscottl	 && (scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
1542195534Sscottl		int device_tagenb;
1543195534Sscottl
1544195534Sscottl		/*
1545195534Sscottl		 * If we are transitioning from tags to no-tags or
1546195534Sscottl		 * vice-versa, we need to carefully freeze and restart
1547195534Sscottl		 * the queue so that we don't overlap tagged and non-tagged
1548195534Sscottl		 * commands.  We also temporarily stop tags if there is
1549195534Sscottl		 * a change in transfer negotiation settings to allow
1550195534Sscottl		 * "tag-less" negotiation.
1551195534Sscottl		 */
1552195534Sscottl		if ((device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0
1553195534Sscottl		 || (device->inq_flags & SID_CmdQue) != 0)
1554195534Sscottl			device_tagenb = TRUE;
1555195534Sscottl		else
1556195534Sscottl			device_tagenb = FALSE;
1557195534Sscottl
1558195534Sscottl		if (((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0
1559195534Sscottl		  && device_tagenb == FALSE)
1560195534Sscottl		 || ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) == 0
1561195534Sscottl		  && device_tagenb == TRUE)) {
1562195534Sscottl
1563195534Sscottl			if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) {
1564195534Sscottl				/*
1565195534Sscottl				 * Delay change to use tags until after a
1566195534Sscottl				 * few commands have gone to this device so
1567195534Sscottl				 * the controller has time to perform transfer
1568195534Sscottl				 * negotiations without tagged messages getting
1569195534Sscottl				 * in the way.
1570195534Sscottl				 */
1571195534Sscottl				device->tag_delay_count = CAM_TAG_DELAY_COUNT;
1572195534Sscottl				device->flags |= CAM_DEV_TAG_AFTER_COUNT;
1573195534Sscottl			} else {
1574199178Smav				xpt_stop_tags(cts->ccb_h.path);
1575195534Sscottl			}
1576195534Sscottl		}
1577195534Sscottl	}
1578195534Sscottl	if (async_update == FALSE)
1579195534Sscottl		(*(sim->sim_action))(sim, (union ccb *)cts);
1580195534Sscottl}
1581195534Sscottl
1582195534Sscottl/*
1583195534Sscottl * Handle any per-device event notifications that require action by the XPT.
1584195534Sscottl */
1585195534Sscottlstatic void
1586195534Sscottlata_dev_async(u_int32_t async_code, struct cam_eb *bus, struct cam_et *target,
1587195534Sscottl	      struct cam_ed *device, void *async_arg)
1588195534Sscottl{
1589195534Sscottl	cam_status status;
1590195534Sscottl	struct cam_path newpath;
1591195534Sscottl
1592195534Sscottl	/*
1593195534Sscottl	 * We only need to handle events for real devices.
1594195534Sscottl	 */
1595195534Sscottl	if (target->target_id == CAM_TARGET_WILDCARD
1596195534Sscottl	 || device->lun_id == CAM_LUN_WILDCARD)
1597195534Sscottl		return;
1598195534Sscottl
1599195534Sscottl	/*
1600195534Sscottl	 * We need our own path with wildcards expanded to
1601195534Sscottl	 * handle certain types of events.
1602195534Sscottl	 */
1603195534Sscottl	if ((async_code == AC_SENT_BDR)
1604195534Sscottl	 || (async_code == AC_BUS_RESET)
1605195534Sscottl	 || (async_code == AC_INQ_CHANGED))
1606195534Sscottl		status = xpt_compile_path(&newpath, NULL,
1607195534Sscottl					  bus->path_id,
1608195534Sscottl					  target->target_id,
1609195534Sscottl					  device->lun_id);
1610195534Sscottl	else
1611195534Sscottl		status = CAM_REQ_CMP_ERR;
1612195534Sscottl
1613195534Sscottl	if (status == CAM_REQ_CMP) {
1614195534Sscottl		if (async_code == AC_INQ_CHANGED) {
1615195534Sscottl			/*
1616195534Sscottl			 * We've sent a start unit command, or
1617195534Sscottl			 * something similar to a device that
1618195534Sscottl			 * may have caused its inquiry data to
1619195534Sscottl			 * change. So we re-scan the device to
1620195534Sscottl			 * refresh the inquiry data for it.
1621195534Sscottl			 */
1622195534Sscottl			ata_scan_lun(newpath.periph, &newpath,
1623195534Sscottl				     CAM_EXPECT_INQ_CHANGE, NULL);
1624203108Smav		} else {
1625203108Smav			/* We need to reinitialize device after reset. */
1626203108Smav			ata_scan_lun(newpath.periph, &newpath,
1627203108Smav				     0, NULL);
1628195534Sscottl		}
1629195534Sscottl		xpt_release_path(&newpath);
1630198748Smav	} else if (async_code == AC_LOST_DEVICE &&
1631198748Smav	    (device->flags & CAM_DEV_UNCONFIGURED) == 0) {
1632195534Sscottl		device->flags |= CAM_DEV_UNCONFIGURED;
1633198748Smav		xpt_release_device(device);
1634195534Sscottl	} else if (async_code == AC_TRANSFER_NEG) {
1635195534Sscottl		struct ccb_trans_settings *settings;
1636195534Sscottl
1637195534Sscottl		settings = (struct ccb_trans_settings *)async_arg;
1638199178Smav		ata_set_transfer_settings(settings, device,
1639195534Sscottl					  /*async_update*/TRUE);
1640195534Sscottl	}
1641195534Sscottl}
1642195534Sscottl
1643