ata_xpt.c revision 199799
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 199799 2009-11-25 14:24:14Z 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/md5.h>
41195534Sscottl#include <sys/interrupt.h>
42195534Sscottl#include <sys/sbuf.h>
43195534Sscottl
44195534Sscottl#include <sys/lock.h>
45195534Sscottl#include <sys/mutex.h>
46195534Sscottl#include <sys/sysctl.h>
47195534Sscottl
48195534Sscottl#ifdef PC98
49195534Sscottl#include <pc98/pc98/pc98_machdep.h>	/* geometry translation */
50195534Sscottl#endif
51195534Sscottl
52195534Sscottl#include <cam/cam.h>
53195534Sscottl#include <cam/cam_ccb.h>
54195534Sscottl#include <cam/cam_queue.h>
55195534Sscottl#include <cam/cam_periph.h>
56195534Sscottl#include <cam/cam_sim.h>
57195534Sscottl#include <cam/cam_xpt.h>
58195534Sscottl#include <cam/cam_xpt_sim.h>
59195534Sscottl#include <cam/cam_xpt_periph.h>
60195534Sscottl#include <cam/cam_xpt_internal.h>
61195534Sscottl#include <cam/cam_debug.h>
62195534Sscottl
63195534Sscottl#include <cam/scsi/scsi_all.h>
64195534Sscottl#include <cam/scsi/scsi_message.h>
65195534Sscottl#include <cam/ata/ata_all.h>
66195534Sscottl#include <machine/stdarg.h>	/* for xpt_print below */
67195534Sscottl#include "opt_cam.h"
68195534Sscottl
69199178Smavstruct ata_quirk_entry {
70195534Sscottl	struct scsi_inquiry_pattern inq_pat;
71195534Sscottl	u_int8_t quirks;
72199178Smav#define	CAM_QUIRK_MAXTAGS	0x01
73195534Sscottl	u_int maxtags;
74195534Sscottl};
75195534Sscottl
76195534Sscottlstatic periph_init_t probe_periph_init;
77195534Sscottl
78195534Sscottlstatic struct periph_driver probe_driver =
79195534Sscottl{
80195653Smav	probe_periph_init, "aprobe",
81198708Smav	TAILQ_HEAD_INITIALIZER(probe_driver.units), /* generation */ 0,
82198708Smav	CAM_PERIPH_DRV_EARLY
83195534Sscottl};
84195534Sscottl
85195653SmavPERIPHDRIVER_DECLARE(aprobe, probe_driver);
86195534Sscottl
87195534Sscottltypedef enum {
88195534Sscottl	PROBE_RESET,
89195534Sscottl	PROBE_IDENTIFY,
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",
102195534Sscottl	"PROBE_SETMODE",
103198708Smav	"PROBE_SET_MULTI",
104195534Sscottl	"PROBE_INQUIRY",
105195534Sscottl	"PROBE_FULL_INQUIRY",
106195534Sscottl	"PROBE_PM_PID",
107195534Sscottl	"PROBE_PM_PRV",
108195534Sscottl	"PROBE_INVALID"
109195534Sscottl};
110195534Sscottl
111195534Sscottl#define PROBE_SET_ACTION(softc, newaction)	\
112195534Sscottldo {									\
113195534Sscottl	char **text;							\
114195534Sscottl	text = probe_action_text;					\
115195534Sscottl	CAM_DEBUG((softc)->periph->path, CAM_DEBUG_INFO,		\
116195534Sscottl	    ("Probe %s to %s\n", text[(softc)->action],			\
117195534Sscottl	    text[(newaction)]));					\
118195534Sscottl	(softc)->action = (newaction);					\
119195534Sscottl} while(0)
120195534Sscottl
121195534Sscottltypedef enum {
122195534Sscottl	PROBE_NO_ANNOUNCE	= 0x04
123195534Sscottl} probe_flags;
124195534Sscottl
125195534Sscottltypedef struct {
126195534Sscottl	TAILQ_HEAD(, ccb_hdr) request_ccbs;
127195534Sscottl	probe_action	action;
128195534Sscottl	union ccb	saved_ccb;
129195534Sscottl	probe_flags	flags;
130195534Sscottl	u_int8_t	digest[16];
131195534Sscottl	uint32_t	pm_pid;
132195534Sscottl	uint32_t	pm_prv;
133195534Sscottl	struct cam_periph *periph;
134195534Sscottl} probe_softc;
135195534Sscottl
136199178Smavstatic struct ata_quirk_entry ata_quirk_table[] =
137195534Sscottl{
138195534Sscottl	{
139195534Sscottl		/* Default tagged queuing parameters for all devices */
140195534Sscottl		{
141195534Sscottl		  T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED,
142195534Sscottl		  /*vendor*/"*", /*product*/"*", /*revision*/"*"
143195534Sscottl		},
144199178Smav		/*quirks*/0, /*maxtags*/0
145195534Sscottl	},
146195534Sscottl};
147195534Sscottl
148199178Smavstatic const int ata_quirk_table_size =
149199178Smav	sizeof(ata_quirk_table) / sizeof(*ata_quirk_table);
150195534Sscottl
151195534Sscottlstatic cam_status	proberegister(struct cam_periph *periph,
152195534Sscottl				      void *arg);
153195534Sscottlstatic void	 probeschedule(struct cam_periph *probe_periph);
154195534Sscottlstatic void	 probestart(struct cam_periph *periph, union ccb *start_ccb);
155195534Sscottl//static void	 proberequestdefaultnegotiation(struct cam_periph *periph);
156195534Sscottl//static int       proberequestbackoff(struct cam_periph *periph,
157195534Sscottl//				     struct cam_ed *device);
158195534Sscottlstatic void	 probedone(struct cam_periph *periph, union ccb *done_ccb);
159195534Sscottlstatic void	 probecleanup(struct cam_periph *periph);
160199178Smavstatic void	 ata_find_quirk(struct cam_ed *device);
161195534Sscottlstatic void	 ata_scan_bus(struct cam_periph *periph, union ccb *ccb);
162195534Sscottlstatic void	 ata_scan_lun(struct cam_periph *periph,
163195534Sscottl			       struct cam_path *path, cam_flags flags,
164195534Sscottl			       union ccb *ccb);
165195534Sscottlstatic void	 xptscandone(struct cam_periph *periph, union ccb *done_ccb);
166195534Sscottlstatic struct cam_ed *
167195534Sscottl		 ata_alloc_device(struct cam_eb *bus, struct cam_et *target,
168195534Sscottl				   lun_id_t lun_id);
169195534Sscottlstatic void	 ata_device_transport(struct cam_path *path);
170199178Smavstatic void	 ata_set_transfer_settings(struct ccb_trans_settings *cts,
171195534Sscottl					    struct cam_ed *device,
172195534Sscottl					    int async_update);
173195534Sscottlstatic void	 ata_dev_async(u_int32_t async_code,
174195534Sscottl				struct cam_eb *bus,
175195534Sscottl				struct cam_et *target,
176195534Sscottl				struct cam_ed *device,
177195534Sscottl				void *async_arg);
178195534Sscottlstatic void	 ata_action(union ccb *start_ccb);
179195534Sscottl
180195534Sscottlstatic struct xpt_xport ata_xport = {
181195534Sscottl	.alloc_device = ata_alloc_device,
182195534Sscottl	.action = ata_action,
183195534Sscottl	.async = ata_dev_async,
184195534Sscottl};
185195534Sscottl
186195534Sscottlstruct xpt_xport *
187195534Sscottlata_get_xport(void)
188195534Sscottl{
189195534Sscottl	return (&ata_xport);
190195534Sscottl}
191195534Sscottl
192195534Sscottlstatic void
193195534Sscottlprobe_periph_init()
194195534Sscottl{
195195534Sscottl}
196195534Sscottl
197195534Sscottlstatic cam_status
198195534Sscottlproberegister(struct cam_periph *periph, void *arg)
199195534Sscottl{
200195534Sscottl	union ccb *request_ccb;	/* CCB representing the probe request */
201195534Sscottl	cam_status status;
202195534Sscottl	probe_softc *softc;
203195534Sscottl
204195534Sscottl	request_ccb = (union ccb *)arg;
205195534Sscottl	if (periph == NULL) {
206195534Sscottl		printf("proberegister: periph was NULL!!\n");
207195534Sscottl		return(CAM_REQ_CMP_ERR);
208195534Sscottl	}
209195534Sscottl
210195534Sscottl	if (request_ccb == NULL) {
211195534Sscottl		printf("proberegister: no probe CCB, "
212195534Sscottl		       "can't register device\n");
213195534Sscottl		return(CAM_REQ_CMP_ERR);
214195534Sscottl	}
215195534Sscottl
216195534Sscottl	softc = (probe_softc *)malloc(sizeof(*softc), M_CAMXPT, M_NOWAIT);
217195534Sscottl
218195534Sscottl	if (softc == NULL) {
219195534Sscottl		printf("proberegister: Unable to probe new device. "
220195534Sscottl		       "Unable to allocate softc\n");
221195534Sscottl		return(CAM_REQ_CMP_ERR);
222195534Sscottl	}
223195534Sscottl	TAILQ_INIT(&softc->request_ccbs);
224195534Sscottl	TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h,
225195534Sscottl			  periph_links.tqe);
226195534Sscottl	softc->flags = 0;
227195534Sscottl	periph->softc = softc;
228195534Sscottl	softc->periph = periph;
229195534Sscottl	softc->action = PROBE_INVALID;
230195534Sscottl	status = cam_periph_acquire(periph);
231195534Sscottl	if (status != CAM_REQ_CMP) {
232195534Sscottl		return (status);
233195534Sscottl	}
234195534Sscottl
235195534Sscottl
236195534Sscottl	/*
237195534Sscottl	 * Ensure we've waited at least a bus settle
238195534Sscottl	 * delay before attempting to probe the device.
239195534Sscottl	 * For HBAs that don't do bus resets, this won't make a difference.
240195534Sscottl	 */
241195534Sscottl	cam_periph_freeze_after_event(periph, &periph->path->bus->last_reset,
242195534Sscottl				      scsi_delay);
243195534Sscottl	probeschedule(periph);
244195534Sscottl	return(CAM_REQ_CMP);
245195534Sscottl}
246195534Sscottl
247195534Sscottlstatic void
248195534Sscottlprobeschedule(struct cam_periph *periph)
249195534Sscottl{
250195534Sscottl	struct ccb_pathinq cpi;
251195534Sscottl	union ccb *ccb;
252195534Sscottl	probe_softc *softc;
253195534Sscottl
254195534Sscottl	softc = (probe_softc *)periph->softc;
255195534Sscottl	ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs);
256195534Sscottl
257198382Smav	xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
258195534Sscottl	cpi.ccb_h.func_code = XPT_PATH_INQ;
259195534Sscottl	xpt_action((union ccb *)&cpi);
260195534Sscottl
261198389Smav	if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) ||
262198389Smav	    periph->path->device->protocol == PROTO_SATAPM)
263195534Sscottl		PROBE_SET_ACTION(softc, PROBE_RESET);
264195534Sscottl	else
265195534Sscottl		PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
266195534Sscottl
267195534Sscottl	if (ccb->crcn.flags & CAM_EXPECT_INQ_CHANGE)
268195534Sscottl		softc->flags |= PROBE_NO_ANNOUNCE;
269195534Sscottl	else
270195534Sscottl		softc->flags &= ~PROBE_NO_ANNOUNCE;
271195534Sscottl
272195534Sscottl	xpt_schedule(periph, ccb->ccb_h.pinfo.priority);
273195534Sscottl}
274195534Sscottl
275195534Sscottlstatic void
276195534Sscottlprobestart(struct cam_periph *periph, union ccb *start_ccb)
277195534Sscottl{
278199747Smav	struct ccb_trans_settings cts;
279195534Sscottl	struct ccb_ataio *ataio;
280195534Sscottl	struct ccb_scsiio *csio;
281195534Sscottl	probe_softc *softc;
282198708Smav	struct cam_path *path;
283198708Smav	struct ata_params *ident_buf;
284195534Sscottl
285195534Sscottl	CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probestart\n"));
286195534Sscottl
287195534Sscottl	softc = (probe_softc *)periph->softc;
288198708Smav	path = start_ccb->ccb_h.path;
289195534Sscottl	ataio = &start_ccb->ataio;
290195534Sscottl	csio = &start_ccb->csio;
291198708Smav	ident_buf = &periph->path->device->ident_data;
292195534Sscottl
293195534Sscottl	switch (softc->action) {
294195534Sscottl	case PROBE_RESET:
295195534Sscottl		cam_fill_ataio(ataio,
296195534Sscottl		      0,
297195534Sscottl		      probedone,
298195534Sscottl		      /*flags*/CAM_DIR_NONE,
299198389Smav		      0,
300195534Sscottl		      /*data_ptr*/NULL,
301195534Sscottl		      /*dxfer_len*/0,
302195534Sscottl		      (start_ccb->ccb_h.target_id == 15 ? 3 : 15) * 1000);
303195534Sscottl		ata_reset_cmd(ataio);
304195534Sscottl		break;
305195534Sscottl	case PROBE_IDENTIFY:
306195534Sscottl		if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) {
307195534Sscottl			/* Prepare check that it is the same device. */
308195534Sscottl			MD5_CTX context;
309195534Sscottl
310195534Sscottl			MD5Init(&context);
311195534Sscottl			MD5Update(&context,
312195534Sscottl			    (unsigned char *)ident_buf->model,
313195534Sscottl			    sizeof(ident_buf->model));
314195534Sscottl			MD5Update(&context,
315195534Sscottl			    (unsigned char *)ident_buf->revision,
316195534Sscottl			    sizeof(ident_buf->revision));
317195534Sscottl			MD5Update(&context,
318195534Sscottl			    (unsigned char *)ident_buf->serial,
319195534Sscottl			    sizeof(ident_buf->serial));
320195534Sscottl			MD5Final(softc->digest, &context);
321195534Sscottl		}
322195534Sscottl		cam_fill_ataio(ataio,
323195534Sscottl		      1,
324195534Sscottl		      probedone,
325195534Sscottl		      /*flags*/CAM_DIR_IN,
326198389Smav		      0,
327195534Sscottl		      /*data_ptr*/(u_int8_t *)ident_buf,
328195534Sscottl		      /*dxfer_len*/sizeof(struct ata_params),
329195534Sscottl		      30 * 1000);
330195534Sscottl		if (periph->path->device->protocol == PROTO_ATA)
331196659Smav			ata_28bit_cmd(ataio, ATA_ATA_IDENTIFY, 0, 0, 0);
332195534Sscottl		else
333196659Smav			ata_28bit_cmd(ataio, ATA_ATAPI_IDENTIFY, 0, 0, 0);
334195534Sscottl		break;
335195534Sscottl	case PROBE_SETMODE:
336199747Smav	{
337199747Smav		int mode, wantmode;
338199747Smav
339199747Smav		mode = 0;
340199747Smav		/* Fetch user modes from SIM. */
341199747Smav		bzero(&cts, sizeof(cts));
342199747Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
343199747Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
344199747Smav		cts.type = CTS_TYPE_USER_SETTINGS;
345199747Smav		xpt_action((union ccb *)&cts);
346199747Smav		if (path->device->transport == XPORT_ATA) {
347199747Smav			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_MODE)
348199747Smav				mode = cts.xport_specific.ata.mode;
349199747Smav		} else {
350199799Smav			if (cts.xport_specific.sata.valid & CTS_SATA_VALID_MODE)
351199747Smav				mode = cts.xport_specific.sata.mode;
352199747Smav		}
353199747Smavnegotiate:
354199747Smav		/* Honor device capabilities. */
355199747Smav		wantmode = mode = ata_max_mode(ident_buf, mode);
356199747Smav		/* Report modes to SIM. */
357199747Smav		bzero(&cts, sizeof(cts));
358199747Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
359199747Smav		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
360199747Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
361199747Smav		if (path->device->transport == XPORT_ATA) {
362199747Smav			cts.xport_specific.ata.mode = mode;
363199747Smav			cts.xport_specific.ata.valid = CTS_ATA_VALID_MODE;
364199747Smav		} else {
365199747Smav			cts.xport_specific.sata.mode = mode;
366199747Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_MODE;
367199747Smav		}
368199747Smav		xpt_action((union ccb *)&cts);
369199747Smav		/* Fetch user modes from SIM. */
370199747Smav		bzero(&cts, sizeof(cts));
371199747Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
372199747Smav		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
373199747Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
374199747Smav		xpt_action((union ccb *)&cts);
375199747Smav		if (path->device->transport == XPORT_ATA) {
376199747Smav			if (cts.xport_specific.ata.valid & CTS_ATA_VALID_MODE)
377199747Smav				mode = cts.xport_specific.ata.mode;
378199747Smav		} else {
379199747Smav			if (cts.xport_specific.ata.valid & CTS_SATA_VALID_MODE)
380199747Smav				mode = cts.xport_specific.sata.mode;
381199747Smav		}
382199747Smav		/* If SIM disagree - renegotiate. */
383199747Smav		if (mode != wantmode)
384199747Smav			goto negotiate;
385195534Sscottl		cam_fill_ataio(ataio,
386195534Sscottl		      1,
387195534Sscottl		      probedone,
388196353Smav		      /*flags*/CAM_DIR_NONE,
389196353Smav		      0,
390196353Smav		      /*data_ptr*/NULL,
391196353Smav		      /*dxfer_len*/0,
392195534Sscottl		      30 * 1000);
393199747Smav		ata_28bit_cmd(ataio, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
394195534Sscottl		break;
395199747Smav	}
396198708Smav	case PROBE_SET_MULTI:
397198708Smav	{
398198708Smav		u_int sectors;
399198708Smav
400198708Smav		sectors = max(1, min(ident_buf->sectors_intr & 0xff, 16));
401198708Smav
402198708Smav		/* Report bytecount to SIM. */
403198708Smav		bzero(&cts, sizeof(cts));
404198708Smav		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
405198708Smav		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
406198708Smav		cts.type = CTS_TYPE_CURRENT_SETTINGS;
407198708Smav		if (path->device->transport == XPORT_ATA) {
408198897Smav			cts.xport_specific.ata.bytecount = sectors *
409198897Smav			    ata_logical_sector_size(ident_buf);
410198708Smav			cts.xport_specific.ata.valid = CTS_ATA_VALID_BYTECOUNT;
411198708Smav		} else {
412198897Smav			cts.xport_specific.sata.bytecount = sectors *
413198897Smav			    ata_logical_sector_size(ident_buf);
414198708Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_BYTECOUNT;
415198708Smav		}
416198708Smav		xpt_action((union ccb *)&cts);
417198708Smav
418198708Smav		cam_fill_ataio(ataio,
419198708Smav		    1,
420198708Smav		    probedone,
421198708Smav		    CAM_DIR_NONE,
422198708Smav		    0,
423198708Smav		    NULL,
424198708Smav		    0,
425198708Smav		    30*1000);
426198708Smav		ata_28bit_cmd(ataio, ATA_SET_MULTI, 0, 0, sectors);
427198708Smav		break;
428195534Sscottl	}
429195534Sscottl	case PROBE_INQUIRY:
430195534Sscottl	case PROBE_FULL_INQUIRY:
431195534Sscottl	{
432195534Sscottl		u_int inquiry_len;
433195534Sscottl		struct scsi_inquiry_data *inq_buf =
434195534Sscottl		    &periph->path->device->inq_data;
435195534Sscottl
436195534Sscottl		if (softc->action == PROBE_INQUIRY)
437195534Sscottl			inquiry_len = SHORT_INQUIRY_LENGTH;
438195534Sscottl		else
439195534Sscottl			inquiry_len = SID_ADDITIONAL_LENGTH(inq_buf);
440195534Sscottl		/*
441195534Sscottl		 * Some parallel SCSI devices fail to send an
442195534Sscottl		 * ignore wide residue message when dealing with
443195534Sscottl		 * odd length inquiry requests.  Round up to be
444195534Sscottl		 * safe.
445195534Sscottl		 */
446195534Sscottl		inquiry_len = roundup2(inquiry_len, 2);
447195534Sscottl		scsi_inquiry(csio,
448195534Sscottl			     /*retries*/1,
449195534Sscottl			     probedone,
450195534Sscottl			     MSG_SIMPLE_Q_TAG,
451195534Sscottl			     (u_int8_t *)inq_buf,
452195534Sscottl			     inquiry_len,
453195534Sscottl			     /*evpd*/FALSE,
454195534Sscottl			     /*page_code*/0,
455195534Sscottl			     SSD_MIN_SIZE,
456195534Sscottl			     /*timeout*/60 * 1000);
457195534Sscottl		break;
458195534Sscottl	}
459195534Sscottl	case PROBE_PM_PID:
460195534Sscottl		cam_fill_ataio(ataio,
461195534Sscottl		      1,
462195534Sscottl		      probedone,
463195534Sscottl		      /*flags*/CAM_DIR_NONE,
464198389Smav		      0,
465195534Sscottl		      /*data_ptr*/NULL,
466195534Sscottl		      /*dxfer_len*/0,
467195534Sscottl		      10 * 1000);
468195534Sscottl		ata_pm_read_cmd(ataio, 0, 15);
469195534Sscottl		break;
470195534Sscottl	case PROBE_PM_PRV:
471195534Sscottl		cam_fill_ataio(ataio,
472195534Sscottl		      1,
473195534Sscottl		      probedone,
474195534Sscottl		      /*flags*/CAM_DIR_NONE,
475198389Smav		      0,
476195534Sscottl		      /*data_ptr*/NULL,
477195534Sscottl		      /*dxfer_len*/0,
478195534Sscottl		      10 * 1000);
479195534Sscottl		ata_pm_read_cmd(ataio, 1, 15);
480195534Sscottl		break;
481195534Sscottl	case PROBE_INVALID:
482198708Smav		CAM_DEBUG(path, CAM_DEBUG_INFO,
483195534Sscottl		    ("probestart: invalid action state\n"));
484195534Sscottl	default:
485195534Sscottl		break;
486195534Sscottl	}
487195534Sscottl	xpt_action(start_ccb);
488195534Sscottl}
489195534Sscottl#if 0
490195534Sscottlstatic void
491195534Sscottlproberequestdefaultnegotiation(struct cam_periph *periph)
492195534Sscottl{
493195534Sscottl	struct ccb_trans_settings cts;
494195534Sscottl
495198382Smav	xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
496195534Sscottl	cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
497195534Sscottl	cts.type = CTS_TYPE_USER_SETTINGS;
498195534Sscottl	xpt_action((union ccb *)&cts);
499195534Sscottl	if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
500195534Sscottl		return;
501195534Sscottl	}
502195534Sscottl	cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
503195534Sscottl	cts.type = CTS_TYPE_CURRENT_SETTINGS;
504195534Sscottl	xpt_action((union ccb *)&cts);
505195534Sscottl}
506195534Sscottl
507195534Sscottl/*
508195534Sscottl * Backoff Negotiation Code- only pertinent for SPI devices.
509195534Sscottl */
510195534Sscottlstatic int
511195534Sscottlproberequestbackoff(struct cam_periph *periph, struct cam_ed *device)
512195534Sscottl{
513195534Sscottl	struct ccb_trans_settings cts;
514195534Sscottl	struct ccb_trans_settings_spi *spi;
515195534Sscottl
516195534Sscottl	memset(&cts, 0, sizeof (cts));
517198382Smav	xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
518195534Sscottl	cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
519195534Sscottl	cts.type = CTS_TYPE_CURRENT_SETTINGS;
520195534Sscottl	xpt_action((union ccb *)&cts);
521195534Sscottl	if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
522195534Sscottl		if (bootverbose) {
523195534Sscottl			xpt_print(periph->path,
524195534Sscottl			    "failed to get current device settings\n");
525195534Sscottl		}
526195534Sscottl		return (0);
527195534Sscottl	}
528195534Sscottl	if (cts.transport != XPORT_SPI) {
529195534Sscottl		if (bootverbose) {
530195534Sscottl			xpt_print(periph->path, "not SPI transport\n");
531195534Sscottl		}
532195534Sscottl		return (0);
533195534Sscottl	}
534195534Sscottl	spi = &cts.xport_specific.spi;
535195534Sscottl
536195534Sscottl	/*
537195534Sscottl	 * We cannot renegotiate sync rate if we don't have one.
538195534Sscottl	 */
539195534Sscottl	if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) {
540195534Sscottl		if (bootverbose) {
541195534Sscottl			xpt_print(periph->path, "no sync rate known\n");
542195534Sscottl		}
543195534Sscottl		return (0);
544195534Sscottl	}
545195534Sscottl
546195534Sscottl	/*
547195534Sscottl	 * We'll assert that we don't have to touch PPR options- the
548195534Sscottl	 * SIM will see what we do with period and offset and adjust
549195534Sscottl	 * the PPR options as appropriate.
550195534Sscottl	 */
551195534Sscottl
552195534Sscottl	/*
553195534Sscottl	 * A sync rate with unknown or zero offset is nonsensical.
554195534Sscottl	 * A sync period of zero means Async.
555195534Sscottl	 */
556195534Sscottl	if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0
557195534Sscottl	 || spi->sync_offset == 0 || spi->sync_period == 0) {
558195534Sscottl		if (bootverbose) {
559195534Sscottl			xpt_print(periph->path, "no sync rate available\n");
560195534Sscottl		}
561195534Sscottl		return (0);
562195534Sscottl	}
563195534Sscottl
564195534Sscottl	if (device->flags & CAM_DEV_DV_HIT_BOTTOM) {
565195534Sscottl		CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
566195534Sscottl		    ("hit async: giving up on DV\n"));
567195534Sscottl		return (0);
568195534Sscottl	}
569195534Sscottl
570195534Sscottl
571195534Sscottl	/*
572195534Sscottl	 * Jump sync_period up by one, but stop at 5MHz and fall back to Async.
573195534Sscottl	 * We don't try to remember 'last' settings to see if the SIM actually
574195534Sscottl	 * gets into the speed we want to set. We check on the SIM telling
575195534Sscottl	 * us that a requested speed is bad, but otherwise don't try and
576195534Sscottl	 * check the speed due to the asynchronous and handshake nature
577195534Sscottl	 * of speed setting.
578195534Sscottl	 */
579195534Sscottl	spi->valid = CTS_SPI_VALID_SYNC_RATE | CTS_SPI_VALID_SYNC_OFFSET;
580195534Sscottl	for (;;) {
581195534Sscottl		spi->sync_period++;
582195534Sscottl		if (spi->sync_period >= 0xf) {
583195534Sscottl			spi->sync_period = 0;
584195534Sscottl			spi->sync_offset = 0;
585195534Sscottl			CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
586195534Sscottl			    ("setting to async for DV\n"));
587195534Sscottl			/*
588195534Sscottl			 * Once we hit async, we don't want to try
589195534Sscottl			 * any more settings.
590195534Sscottl			 */
591195534Sscottl			device->flags |= CAM_DEV_DV_HIT_BOTTOM;
592195534Sscottl		} else if (bootverbose) {
593195534Sscottl			CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
594195534Sscottl			    ("DV: period 0x%x\n", spi->sync_period));
595195534Sscottl			printf("setting period to 0x%x\n", spi->sync_period);
596195534Sscottl		}
597195534Sscottl		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
598195534Sscottl		cts.type = CTS_TYPE_CURRENT_SETTINGS;
599195534Sscottl		xpt_action((union ccb *)&cts);
600195534Sscottl		if ((cts.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
601195534Sscottl			break;
602195534Sscottl		}
603195534Sscottl		CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
604195534Sscottl		    ("DV: failed to set period 0x%x\n", spi->sync_period));
605195534Sscottl		if (spi->sync_period == 0) {
606195534Sscottl			return (0);
607195534Sscottl		}
608195534Sscottl	}
609195534Sscottl	return (1);
610195534Sscottl}
611195534Sscottl#endif
612195534Sscottlstatic void
613195534Sscottlprobedone(struct cam_periph *periph, union ccb *done_ccb)
614195534Sscottl{
615199747Smav	struct ccb_trans_settings cts;
616195534Sscottl	struct ata_params *ident_buf;
617195534Sscottl	probe_softc *softc;
618195534Sscottl	struct cam_path *path;
619195534Sscottl	u_int32_t  priority;
620198389Smav	int found = 1;
621195534Sscottl
622195534Sscottl	CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probedone\n"));
623195534Sscottl
624195534Sscottl	softc = (probe_softc *)periph->softc;
625195534Sscottl	path = done_ccb->ccb_h.path;
626195534Sscottl	priority = done_ccb->ccb_h.pinfo.priority;
627195534Sscottl	ident_buf = &path->device->ident_data;
628195534Sscottl
629198708Smav	if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
630198708Smavdevice_fail:	if (cam_periph_error(done_ccb, 0, 0,
631198708Smav		    &softc->saved_ccb) == ERESTART) {
632195534Sscottl			return;
633195534Sscottl		} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
634195534Sscottl			/* Don't wedge the queue */
635195534Sscottl			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
636195534Sscottl					 /*run_queue*/TRUE);
637195534Sscottl		}
638198708Smav		/* Old PIO2 devices may not support mode setting. */
639198708Smav		if (softc->action == PROBE_SETMODE &&
640198708Smav		    ata_max_pmode(ident_buf) <= ATA_PIO2 &&
641198708Smav		    (ident_buf->capabilities1 & ATA_SUPPORT_IORDY) == 0)
642198708Smav			goto noerror;
643198708Smav		/*
644198708Smav		 * If we get to this point, we got an error status back
645198708Smav		 * from the inquiry and the error status doesn't require
646198708Smav		 * automatically retrying the command.  Therefore, the
647198708Smav		 * inquiry failed.  If we had inquiry information before
648198708Smav		 * for this device, but this latest inquiry command failed,
649198708Smav		 * the device has probably gone away.  If this device isn't
650198708Smav		 * already marked unconfigured, notify the peripheral
651198708Smav		 * drivers that this device is no more.
652198708Smav		 */
653198708Smav		if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0)
654198708Smav			xpt_async(AC_LOST_DEVICE, path, NULL);
655198708Smav		found = 0;
656198708Smav		goto done;
657198708Smav	}
658198708Smavnoerror:
659198708Smav	switch (softc->action) {
660198708Smav	case PROBE_RESET:
661195534Sscottl	{
662198708Smav		int sign = (done_ccb->ataio.res.lba_high << 8) +
663198708Smav		    done_ccb->ataio.res.lba_mid;
664198708Smav		xpt_print(path, "SIGNATURE: %04x\n", sign);
665198708Smav		if (sign == 0x0000 &&
666198708Smav		    done_ccb->ccb_h.target_id != 15) {
667198708Smav			path->device->protocol = PROTO_ATA;
668198708Smav			PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
669198708Smav		} else if (sign == 0x9669 &&
670198708Smav		    done_ccb->ccb_h.target_id == 15) {
671199747Smav			/* Report SIM that PM is present. */
672198708Smav			bzero(&cts, sizeof(cts));
673198708Smav			xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
674198708Smav			cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
675198708Smav			cts.type = CTS_TYPE_CURRENT_SETTINGS;
676198708Smav			cts.xport_specific.sata.pm_present = 1;
677198708Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_PM;
678198708Smav			xpt_action((union ccb *)&cts);
679198708Smav			path->device->protocol = PROTO_SATAPM;
680198708Smav			PROBE_SET_ACTION(softc, PROBE_PM_PID);
681198708Smav		} else if (sign == 0xeb14 &&
682198708Smav		    done_ccb->ccb_h.target_id != 15) {
683198708Smav			path->device->protocol = PROTO_SCSI;
684198708Smav			PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
685198708Smav		} else {
686198708Smav			if (done_ccb->ccb_h.target_id != 15) {
687198708Smav				xpt_print(path,
688198708Smav				    "Unexpected signature 0x%04x\n", sign);
689195534Sscottl			}
690198708Smav			goto device_fail;
691198708Smav		}
692198708Smav		xpt_release_ccb(done_ccb);
693198708Smav		xpt_schedule(periph, priority);
694198708Smav		return;
695198708Smav	}
696198708Smav	case PROBE_IDENTIFY:
697198708Smav	{
698198708Smav		int16_t *ptr;
699195534Sscottl
700198708Smav		for (ptr = (int16_t *)ident_buf;
701198708Smav		     ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) {
702198708Smav			*ptr = le16toh(*ptr);
703198708Smav		}
704198708Smav		if (strncmp(ident_buf->model, "FX", 2) &&
705198708Smav		    strncmp(ident_buf->model, "NEC", 3) &&
706198708Smav		    strncmp(ident_buf->model, "Pioneer", 7) &&
707198708Smav		    strncmp(ident_buf->model, "SHARP", 5)) {
708198708Smav			ata_bswap(ident_buf->model, sizeof(ident_buf->model));
709198708Smav			ata_bswap(ident_buf->revision, sizeof(ident_buf->revision));
710198708Smav			ata_bswap(ident_buf->serial, sizeof(ident_buf->serial));
711198708Smav		}
712198708Smav		ata_btrim(ident_buf->model, sizeof(ident_buf->model));
713198708Smav		ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model));
714198708Smav		ata_btrim(ident_buf->revision, sizeof(ident_buf->revision));
715198708Smav		ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision));
716198708Smav		ata_btrim(ident_buf->serial, sizeof(ident_buf->serial));
717198708Smav		ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial));
718195534Sscottl
719198708Smav		if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) {
720198708Smav			/* Check that it is the same device. */
721198708Smav			MD5_CTX context;
722198708Smav			u_int8_t digest[16];
723198708Smav
724198708Smav			MD5Init(&context);
725198708Smav			MD5Update(&context,
726198708Smav			    (unsigned char *)ident_buf->model,
727198708Smav			    sizeof(ident_buf->model));
728198708Smav			MD5Update(&context,
729198708Smav			    (unsigned char *)ident_buf->revision,
730198708Smav			    sizeof(ident_buf->revision));
731198708Smav			MD5Update(&context,
732198708Smav			    (unsigned char *)ident_buf->serial,
733198708Smav			    sizeof(ident_buf->serial));
734198708Smav			MD5Final(digest, &context);
735198708Smav			if (bcmp(digest, softc->digest, sizeof(digest))) {
736198708Smav				/* Device changed. */
737198708Smav				xpt_async(AC_LOST_DEVICE, path, NULL);
738195534Sscottl			}
739198708Smav		} else {
740195534Sscottl			/* Clean up from previous instance of this device */
741195534Sscottl			if (path->device->serial_num != NULL) {
742195534Sscottl				free(path->device->serial_num, M_CAMXPT);
743195534Sscottl				path->device->serial_num = NULL;
744195534Sscottl				path->device->serial_num_len = 0;
745195534Sscottl			}
746195534Sscottl			path->device->serial_num =
747195534Sscottl				(u_int8_t *)malloc((sizeof(ident_buf->serial) + 1),
748198708Smav					   M_CAMXPT, M_NOWAIT);
749195534Sscottl			if (path->device->serial_num != NULL) {
750195534Sscottl				bcopy(ident_buf->serial,
751195534Sscottl				      path->device->serial_num,
752195534Sscottl				      sizeof(ident_buf->serial));
753195534Sscottl				path->device->serial_num[sizeof(ident_buf->serial)]
754195534Sscottl				    = '\0';
755195534Sscottl				path->device->serial_num_len =
756195534Sscottl				    strlen(path->device->serial_num);
757195534Sscottl			}
758195534Sscottl
759198331Smav			path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID;
760195534Sscottl		}
761199178Smav		if (ident_buf->satacapabilities & ATA_SUPPORT_NCQ) {
762199178Smav			path->device->mintags = path->device->maxtags =
763199178Smav			    ATA_QUEUE_LEN(ident_buf->queue) + 1;
764199178Smav		}
765199178Smav		ata_find_quirk(path->device);
766199263Smav		if (path->device->mintags != 0 &&
767199263Smav		    path->bus->sim->max_tagged_dev_openings != 0) {
768199747Smav			/* Report SIM which tags are allowed. */
769199747Smav			bzero(&cts, sizeof(cts));
770199747Smav			xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
771199747Smav			cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
772199747Smav			cts.type = CTS_TYPE_CURRENT_SETTINGS;
773199747Smav			cts.xport_specific.sata.tags = path->device->maxtags;
774199747Smav			cts.xport_specific.sata.valid = CTS_SATA_VALID_TAGS;
775199747Smav			xpt_action((union ccb *)&cts);
776199747Smav			/* Reconfigure queues for tagged queueing. */
777199178Smav			xpt_start_tags(path);
778199178Smav		}
779198708Smav		ata_device_transport(path);
780198708Smav		PROBE_SET_ACTION(softc, PROBE_SETMODE);
781195534Sscottl		xpt_release_ccb(done_ccb);
782198708Smav		xpt_schedule(periph, priority);
783198708Smav		return;
784195534Sscottl	}
785195534Sscottl	case PROBE_SETMODE:
786198708Smav		if (path->device->protocol == PROTO_ATA) {
787198708Smav			PROBE_SET_ACTION(softc, PROBE_SET_MULTI);
788198708Smav		} else {
789198708Smav			PROBE_SET_ACTION(softc, PROBE_INQUIRY);
790195534Sscottl		}
791198708Smav		xpt_release_ccb(done_ccb);
792198708Smav		xpt_schedule(periph, priority);
793198708Smav		return;
794198708Smav	case PROBE_SET_MULTI:
795198708Smav		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
796198708Smav			path->device->flags &= ~CAM_DEV_UNCONFIGURED;
797198748Smav			xpt_acquire_device(path->device);
798198708Smav			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
799198708Smav			xpt_action(done_ccb);
800198708Smav			xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path,
801198708Smav			    done_ccb);
802198708Smav		}
803198708Smav		break;
804195534Sscottl	case PROBE_INQUIRY:
805195534Sscottl	case PROBE_FULL_INQUIRY:
806195534Sscottl	{
807198708Smav		struct scsi_inquiry_data *inq_buf;
808198708Smav		u_int8_t periph_qual, len;
809195534Sscottl
810198708Smav		path->device->flags |= CAM_DEV_INQUIRY_DATA_VALID;
811198708Smav		inq_buf = &path->device->inq_data;
812195534Sscottl
813198708Smav		periph_qual = SID_QUAL(inq_buf);
814195534Sscottl
815198708Smav		if (periph_qual != SID_QUAL_LU_CONNECTED)
816198708Smav			break;
817195534Sscottl
818198708Smav		/*
819198708Smav		 * We conservatively request only
820198708Smav		 * SHORT_INQUIRY_LEN bytes of inquiry
821198708Smav		 * information during our first try
822198708Smav		 * at sending an INQUIRY. If the device
823198708Smav		 * has more information to give,
824198708Smav		 * perform a second request specifying
825198708Smav		 * the amount of information the device
826198708Smav		 * is willing to give.
827198708Smav		 */
828198708Smav		len = inq_buf->additional_length
829198708Smav		    + offsetof(struct scsi_inquiry_data, additional_length) + 1;
830198708Smav		if (softc->action == PROBE_INQUIRY
831198708Smav		    && len > SHORT_INQUIRY_LENGTH) {
832198708Smav			PROBE_SET_ACTION(softc, PROBE_FULL_INQUIRY);
833198708Smav			xpt_release_ccb(done_ccb);
834198708Smav			xpt_schedule(periph, priority);
835195534Sscottl			return;
836195534Sscottl		}
837198708Smav
838198708Smav		ata_device_transport(path);
839198708Smav		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
840198708Smav			path->device->flags &= ~CAM_DEV_UNCONFIGURED;
841198748Smav			xpt_acquire_device(path->device);
842198708Smav			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
843198708Smav			xpt_action(done_ccb);
844198708Smav			xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, done_ccb);
845198708Smav		}
846198708Smav		break;
847195534Sscottl	}
848195534Sscottl	case PROBE_PM_PID:
849198708Smav		if ((path->device->flags & CAM_DEV_IDENTIFY_DATA_VALID) == 0)
850198708Smav			bzero(ident_buf, sizeof(*ident_buf));
851198708Smav		softc->pm_pid = (done_ccb->ataio.res.lba_high << 24) +
852198708Smav		    (done_ccb->ataio.res.lba_mid << 16) +
853198708Smav		    (done_ccb->ataio.res.lba_low << 8) +
854198708Smav		    done_ccb->ataio.res.sector_count;
855198708Smav		((uint32_t *)ident_buf)[0] = softc->pm_pid;
856198708Smav		printf("PM Product ID: %08x\n", softc->pm_pid);
857198708Smav		snprintf(ident_buf->model, sizeof(ident_buf->model),
858198708Smav		    "Port Multiplier %08x", softc->pm_pid);
859198708Smav		PROBE_SET_ACTION(softc, PROBE_PM_PRV);
860198708Smav		xpt_release_ccb(done_ccb);
861198708Smav		xpt_schedule(periph, priority);
862198708Smav		return;
863195534Sscottl	case PROBE_PM_PRV:
864198708Smav		softc->pm_prv = (done_ccb->ataio.res.lba_high << 24) +
865198708Smav		    (done_ccb->ataio.res.lba_mid << 16) +
866198708Smav		    (done_ccb->ataio.res.lba_low << 8) +
867198708Smav		    done_ccb->ataio.res.sector_count;
868198708Smav		((uint32_t *)ident_buf)[1] = softc->pm_prv;
869198708Smav		printf("PM Revision: %08x\n", softc->pm_prv);
870198708Smav		snprintf(ident_buf->revision, sizeof(ident_buf->revision),
871198708Smav		    "%04x", softc->pm_prv);
872198708Smav		path->device->flags |= CAM_DEV_IDENTIFY_DATA_VALID;
873198708Smav		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
874198708Smav			path->device->flags &= ~CAM_DEV_UNCONFIGURED;
875198748Smav			xpt_acquire_device(path->device);
876198708Smav			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
877198708Smav			xpt_action(done_ccb);
878198708Smav			xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path,
879198708Smav			    done_ccb);
880198708Smav		} else {
881198708Smav			done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
882198708Smav			xpt_action(done_ccb);
883198708Smav			xpt_async(AC_SCSI_AEN, done_ccb->ccb_h.path, done_ccb);
884195534Sscottl		}
885198708Smav		break;
886195534Sscottl	case PROBE_INVALID:
887195534Sscottl		CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_INFO,
888195534Sscottl		    ("probedone: invalid action state\n"));
889195534Sscottl	default:
890195534Sscottl		break;
891195534Sscottl	}
892198708Smavdone:
893198708Smav	xpt_release_ccb(done_ccb);
894195534Sscottl	done_ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs);
895195534Sscottl	TAILQ_REMOVE(&softc->request_ccbs, &done_ccb->ccb_h, periph_links.tqe);
896195534Sscottl	done_ccb->ccb_h.status = CAM_REQ_CMP;
897195534Sscottl	done_ccb->ccb_h.ppriv_field1 = found;
898195534Sscottl	xpt_done(done_ccb);
899195534Sscottl	if (TAILQ_FIRST(&softc->request_ccbs) == NULL) {
900195534Sscottl		cam_periph_invalidate(periph);
901195534Sscottl		cam_periph_release_locked(periph);
902195534Sscottl	} else {
903195534Sscottl		probeschedule(periph);
904195534Sscottl	}
905195534Sscottl}
906195534Sscottl
907195534Sscottlstatic void
908195534Sscottlprobecleanup(struct cam_periph *periph)
909195534Sscottl{
910195534Sscottl	free(periph->softc, M_CAMXPT);
911195534Sscottl}
912195534Sscottl
913195534Sscottlstatic void
914199178Smavata_find_quirk(struct cam_ed *device)
915195534Sscottl{
916199178Smav	struct ata_quirk_entry *quirk;
917195534Sscottl	caddr_t	match;
918195534Sscottl
919199178Smav	match = cam_quirkmatch((caddr_t)&device->ident_data,
920199178Smav			       (caddr_t)ata_quirk_table,
921199178Smav			       ata_quirk_table_size,
922199178Smav			       sizeof(*ata_quirk_table), ata_identify_match);
923195534Sscottl
924195534Sscottl	if (match == NULL)
925195534Sscottl		panic("xpt_find_quirk: device didn't match wildcard entry!!");
926195534Sscottl
927199178Smav	quirk = (struct ata_quirk_entry *)match;
928195534Sscottl	device->quirk = quirk;
929199178Smav	if (quirk->quirks & CAM_QUIRK_MAXTAGS)
930199178Smav		device->mintags = device->maxtags = quirk->maxtags;
931195534Sscottl}
932195534Sscottl
933195534Sscottltypedef struct {
934195534Sscottl	union	ccb *request_ccb;
935195534Sscottl	struct 	ccb_pathinq *cpi;
936195534Sscottl	int	counter;
937195534Sscottl	int	found;
938195534Sscottl} ata_scan_bus_info;
939195534Sscottl
940195534Sscottl/*
941195534Sscottl * To start a scan, request_ccb is an XPT_SCAN_BUS ccb.
942195534Sscottl * As the scan progresses, xpt_scan_bus is used as the
943195534Sscottl * callback on completion function.
944195534Sscottl */
945195534Sscottlstatic void
946195534Sscottlata_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
947195534Sscottl{
948195534Sscottl	struct	cam_path *path;
949195534Sscottl	ata_scan_bus_info *scan_info;
950195534Sscottl	union	ccb *work_ccb;
951195534Sscottl	cam_status status;
952195534Sscottl
953195534Sscottl	CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE,
954195534Sscottl		  ("xpt_scan_bus\n"));
955195534Sscottl	switch (request_ccb->ccb_h.func_code) {
956195534Sscottl	case XPT_SCAN_BUS:
957195534Sscottl		/* Find out the characteristics of the bus */
958195534Sscottl		work_ccb = xpt_alloc_ccb_nowait();
959195534Sscottl		if (work_ccb == NULL) {
960195534Sscottl			request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
961195534Sscottl			xpt_done(request_ccb);
962195534Sscottl			return;
963195534Sscottl		}
964195534Sscottl		xpt_setup_ccb(&work_ccb->ccb_h, request_ccb->ccb_h.path,
965195534Sscottl			      request_ccb->ccb_h.pinfo.priority);
966195534Sscottl		work_ccb->ccb_h.func_code = XPT_PATH_INQ;
967195534Sscottl		xpt_action(work_ccb);
968195534Sscottl		if (work_ccb->ccb_h.status != CAM_REQ_CMP) {
969195534Sscottl			request_ccb->ccb_h.status = work_ccb->ccb_h.status;
970195534Sscottl			xpt_free_ccb(work_ccb);
971195534Sscottl			xpt_done(request_ccb);
972195534Sscottl			return;
973195534Sscottl		}
974195534Sscottl
975195534Sscottl		/* Save some state for use while we probe for devices */
976195534Sscottl		scan_info = (ata_scan_bus_info *)
977195534Sscottl		    malloc(sizeof(ata_scan_bus_info), M_CAMXPT, M_NOWAIT);
978195534Sscottl		if (scan_info == NULL) {
979195534Sscottl			request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
980195534Sscottl			xpt_done(request_ccb);
981195534Sscottl			return;
982195534Sscottl		}
983195534Sscottl		scan_info->request_ccb = request_ccb;
984195534Sscottl		scan_info->cpi = &work_ccb->cpi;
985198331Smav		if (scan_info->cpi->transport == XPORT_ATA)
986198331Smav			scan_info->found = 0x0003;
987198331Smav		else
988198331Smav			scan_info->found = 0x8001;
989195534Sscottl		scan_info->counter = 0;
990195534Sscottl		/* If PM supported, probe it first. */
991195534Sscottl		if (scan_info->cpi->hba_inquiry & PI_SATAPM)
992195534Sscottl			scan_info->counter = 15;
993195534Sscottl
994195534Sscottl		work_ccb = xpt_alloc_ccb_nowait();
995195534Sscottl		if (work_ccb == NULL) {
996195534Sscottl			free(scan_info, M_CAMXPT);
997195534Sscottl			request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
998195534Sscottl			xpt_done(request_ccb);
999195534Sscottl			break;
1000195534Sscottl		}
1001195534Sscottl		goto scan_next;
1002195534Sscottl	case XPT_SCAN_LUN:
1003195534Sscottl		work_ccb = request_ccb;
1004195534Sscottl		/* Reuse the same CCB to query if a device was really found */
1005195534Sscottl		scan_info = (ata_scan_bus_info *)work_ccb->ccb_h.ppriv_ptr0;
1006195534Sscottl		/* Free the current request path- we're done with it. */
1007195534Sscottl		xpt_free_path(work_ccb->ccb_h.path);
1008198389Smav		/* If there is PMP... */
1009195534Sscottl		if (scan_info->counter == 15) {
1010195534Sscottl			if (work_ccb->ccb_h.ppriv_field1 != 0) {
1011198389Smav				/* everything else willbe probed by it */
1012198389Smav				scan_info->found = 0x8000;
1013195534Sscottl			} else {
1014195534Sscottl				struct ccb_trans_settings cts;
1015195534Sscottl
1016195534Sscottl				/* Report SIM that PM is absent. */
1017195534Sscottl				bzero(&cts, sizeof(cts));
1018195534Sscottl				xpt_setup_ccb(&cts.ccb_h,
1019195534Sscottl				    scan_info->request_ccb->ccb_h.path, 1);
1020195534Sscottl				cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
1021195534Sscottl				cts.type = CTS_TYPE_CURRENT_SETTINGS;
1022195665Smav				cts.xport_specific.sata.pm_present = 0;
1023195534Sscottl				cts.xport_specific.sata.valid = CTS_SATA_VALID_PM;
1024195534Sscottl				xpt_action((union ccb *)&cts);
1025195534Sscottl			}
1026195534Sscottl		}
1027195534Sscottltake_next:
1028195534Sscottl		/* Take next device. Wrap from 15 (PM) to 0. */
1029195534Sscottl		scan_info->counter = (scan_info->counter + 1 ) & 0x0f;
1030198322Smav		if (scan_info->counter > scan_info->cpi->max_target -
1031198322Smav		    ((scan_info->cpi->hba_inquiry & PI_SATAPM) ? 1 : 0)) {
1032195534Sscottl			xpt_free_ccb(work_ccb);
1033195534Sscottl			xpt_free_ccb((union ccb *)scan_info->cpi);
1034195534Sscottl			request_ccb = scan_info->request_ccb;
1035195534Sscottl			free(scan_info, M_CAMXPT);
1036195534Sscottl			request_ccb->ccb_h.status = CAM_REQ_CMP;
1037195534Sscottl			xpt_done(request_ccb);
1038195534Sscottl			break;
1039195534Sscottl		}
1040195534Sscottlscan_next:
1041198389Smav		if ((scan_info->found & (1 << scan_info->counter)) == 0)
1042198389Smav			goto take_next;
1043195534Sscottl		status = xpt_create_path(&path, xpt_periph,
1044195534Sscottl		    scan_info->request_ccb->ccb_h.path_id,
1045195534Sscottl		    scan_info->counter, 0);
1046195534Sscottl		if (status != CAM_REQ_CMP) {
1047195534Sscottl			printf("xpt_scan_bus: xpt_create_path failed"
1048195534Sscottl			    " with status %#x, bus scan halted\n",
1049195534Sscottl			    status);
1050195534Sscottl			xpt_free_ccb(work_ccb);
1051195534Sscottl			xpt_free_ccb((union ccb *)scan_info->cpi);
1052195534Sscottl			request_ccb = scan_info->request_ccb;
1053195534Sscottl			free(scan_info, M_CAMXPT);
1054195534Sscottl			request_ccb->ccb_h.status = status;
1055195534Sscottl			xpt_done(request_ccb);
1056195534Sscottl			break;
1057195534Sscottl		}
1058195534Sscottl		xpt_setup_ccb(&work_ccb->ccb_h, path,
1059195534Sscottl		    scan_info->request_ccb->ccb_h.pinfo.priority);
1060195534Sscottl		work_ccb->ccb_h.func_code = XPT_SCAN_LUN;
1061195534Sscottl		work_ccb->ccb_h.cbfcnp = ata_scan_bus;
1062195534Sscottl		work_ccb->ccb_h.ppriv_ptr0 = scan_info;
1063195534Sscottl		work_ccb->crcn.flags = scan_info->request_ccb->crcn.flags;
1064195534Sscottl		xpt_action(work_ccb);
1065195534Sscottl		break;
1066195534Sscottl	default:
1067195534Sscottl		break;
1068195534Sscottl	}
1069195534Sscottl}
1070195534Sscottl
1071195534Sscottlstatic void
1072195534Sscottlata_scan_lun(struct cam_periph *periph, struct cam_path *path,
1073195534Sscottl	     cam_flags flags, union ccb *request_ccb)
1074195534Sscottl{
1075195534Sscottl	struct ccb_pathinq cpi;
1076195534Sscottl	cam_status status;
1077195534Sscottl	struct cam_path *new_path;
1078195534Sscottl	struct cam_periph *old_periph;
1079195534Sscottl
1080195534Sscottl	CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE,
1081195534Sscottl		  ("xpt_scan_lun\n"));
1082195534Sscottl
1083198382Smav	xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL);
1084195534Sscottl	cpi.ccb_h.func_code = XPT_PATH_INQ;
1085195534Sscottl	xpt_action((union ccb *)&cpi);
1086195534Sscottl
1087195534Sscottl	if (cpi.ccb_h.status != CAM_REQ_CMP) {
1088195534Sscottl		if (request_ccb != NULL) {
1089195534Sscottl			request_ccb->ccb_h.status = cpi.ccb_h.status;
1090195534Sscottl			xpt_done(request_ccb);
1091195534Sscottl		}
1092195534Sscottl		return;
1093195534Sscottl	}
1094195534Sscottl
1095195534Sscottl	if (request_ccb == NULL) {
1096195534Sscottl		request_ccb = malloc(sizeof(union ccb), M_CAMXPT, M_NOWAIT);
1097195534Sscottl		if (request_ccb == NULL) {
1098195534Sscottl			xpt_print(path, "xpt_scan_lun: can't allocate CCB, "
1099195534Sscottl			    "can't continue\n");
1100195534Sscottl			return;
1101195534Sscottl		}
1102195534Sscottl		new_path = malloc(sizeof(*new_path), M_CAMXPT, M_NOWAIT);
1103195534Sscottl		if (new_path == NULL) {
1104195534Sscottl			xpt_print(path, "xpt_scan_lun: can't allocate path, "
1105195534Sscottl			    "can't continue\n");
1106195534Sscottl			free(request_ccb, M_CAMXPT);
1107195534Sscottl			return;
1108195534Sscottl		}
1109195534Sscottl		status = xpt_compile_path(new_path, xpt_periph,
1110195534Sscottl					  path->bus->path_id,
1111195534Sscottl					  path->target->target_id,
1112195534Sscottl					  path->device->lun_id);
1113195534Sscottl
1114195534Sscottl		if (status != CAM_REQ_CMP) {
1115195534Sscottl			xpt_print(path, "xpt_scan_lun: can't compile path, "
1116195534Sscottl			    "can't continue\n");
1117195534Sscottl			free(request_ccb, M_CAMXPT);
1118195534Sscottl			free(new_path, M_CAMXPT);
1119195534Sscottl			return;
1120195534Sscottl		}
1121198382Smav		xpt_setup_ccb(&request_ccb->ccb_h, new_path, CAM_PRIORITY_NORMAL);
1122195534Sscottl		request_ccb->ccb_h.cbfcnp = xptscandone;
1123195534Sscottl		request_ccb->ccb_h.func_code = XPT_SCAN_LUN;
1124195534Sscottl		request_ccb->crcn.flags = flags;
1125195534Sscottl	}
1126195534Sscottl
1127195653Smav	if ((old_periph = cam_periph_find(path, "aprobe")) != NULL) {
1128195534Sscottl		probe_softc *softc;
1129195534Sscottl
1130195534Sscottl		softc = (probe_softc *)old_periph->softc;
1131195534Sscottl		TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h,
1132195534Sscottl				  periph_links.tqe);
1133195534Sscottl	} else {
1134195534Sscottl		status = cam_periph_alloc(proberegister, NULL, probecleanup,
1135195653Smav					  probestart, "aprobe",
1136195534Sscottl					  CAM_PERIPH_BIO,
1137195534Sscottl					  request_ccb->ccb_h.path, NULL, 0,
1138195534Sscottl					  request_ccb);
1139195534Sscottl
1140195534Sscottl		if (status != CAM_REQ_CMP) {
1141195534Sscottl			xpt_print(path, "xpt_scan_lun: cam_alloc_periph "
1142195534Sscottl			    "returned an error, can't continue probe\n");
1143195534Sscottl			request_ccb->ccb_h.status = status;
1144195534Sscottl			xpt_done(request_ccb);
1145195534Sscottl		}
1146195534Sscottl	}
1147195534Sscottl}
1148195534Sscottl
1149195534Sscottlstatic void
1150195534Sscottlxptscandone(struct cam_periph *periph, union ccb *done_ccb)
1151195534Sscottl{
1152195534Sscottl	xpt_release_path(done_ccb->ccb_h.path);
1153195534Sscottl	free(done_ccb->ccb_h.path, M_CAMXPT);
1154195534Sscottl	free(done_ccb, M_CAMXPT);
1155195534Sscottl}
1156195534Sscottl
1157195534Sscottlstatic struct cam_ed *
1158195534Sscottlata_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id)
1159195534Sscottl{
1160195534Sscottl	struct cam_path path;
1161199178Smav	struct ata_quirk_entry *quirk;
1162195534Sscottl	struct cam_ed *device;
1163195534Sscottl	struct cam_ed *cur_device;
1164195534Sscottl
1165195534Sscottl	device = xpt_alloc_device(bus, target, lun_id);
1166195534Sscottl	if (device == NULL)
1167195534Sscottl		return (NULL);
1168195534Sscottl
1169195534Sscottl	/*
1170195534Sscottl	 * Take the default quirk entry until we have inquiry
1171195534Sscottl	 * data and can determine a better quirk to use.
1172195534Sscottl	 */
1173199178Smav	quirk = &ata_quirk_table[ata_quirk_table_size - 1];
1174195534Sscottl	device->quirk = (void *)quirk;
1175199178Smav	device->mintags = 0;
1176199178Smav	device->maxtags = 0;
1177195534Sscottl	bzero(&device->inq_data, sizeof(device->inq_data));
1178195534Sscottl	device->inq_flags = 0;
1179195534Sscottl	device->queue_flags = 0;
1180195534Sscottl	device->serial_num = NULL;
1181195534Sscottl	device->serial_num_len = 0;
1182195534Sscottl
1183195534Sscottl	/*
1184195534Sscottl	 * XXX should be limited by number of CCBs this bus can
1185195534Sscottl	 * do.
1186195534Sscottl	 */
1187195534Sscottl	bus->sim->max_ccbs += device->ccbq.devq_openings;
1188195534Sscottl	/* Insertion sort into our target's device list */
1189195534Sscottl	cur_device = TAILQ_FIRST(&target->ed_entries);
1190195534Sscottl	while (cur_device != NULL && cur_device->lun_id < lun_id)
1191195534Sscottl		cur_device = TAILQ_NEXT(cur_device, links);
1192195534Sscottl	if (cur_device != NULL) {
1193195534Sscottl		TAILQ_INSERT_BEFORE(cur_device, device, links);
1194195534Sscottl	} else {
1195195534Sscottl		TAILQ_INSERT_TAIL(&target->ed_entries, device, links);
1196195534Sscottl	}
1197195534Sscottl	target->generation++;
1198195534Sscottl	if (lun_id != CAM_LUN_WILDCARD) {
1199195534Sscottl		xpt_compile_path(&path,
1200195534Sscottl				 NULL,
1201195534Sscottl				 bus->path_id,
1202195534Sscottl				 target->target_id,
1203195534Sscottl				 lun_id);
1204195534Sscottl		ata_device_transport(&path);
1205195534Sscottl		xpt_release_path(&path);
1206195534Sscottl	}
1207195534Sscottl
1208195534Sscottl	return (device);
1209195534Sscottl}
1210195534Sscottl
1211195534Sscottlstatic void
1212195534Sscottlata_device_transport(struct cam_path *path)
1213195534Sscottl{
1214195534Sscottl	struct ccb_pathinq cpi;
1215198331Smav	struct ccb_trans_settings cts;
1216198331Smav	struct scsi_inquiry_data *inq_buf = NULL;
1217198331Smav	struct ata_params *ident_buf = NULL;
1218195534Sscottl
1219195534Sscottl	/* Get transport information from the SIM */
1220198382Smav	xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL);
1221195534Sscottl	cpi.ccb_h.func_code = XPT_PATH_INQ;
1222195534Sscottl	xpt_action((union ccb *)&cpi);
1223195534Sscottl
1224195534Sscottl	path->device->transport = cpi.transport;
1225198331Smav	if ((path->device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0)
1226198331Smav		inq_buf = &path->device->inq_data;
1227198331Smav	if ((path->device->flags & CAM_DEV_IDENTIFY_DATA_VALID) != 0)
1228198331Smav		ident_buf = &path->device->ident_data;
1229198331Smav	if (path->device->protocol == PROTO_ATA) {
1230198331Smav		path->device->protocol_version = ident_buf ?
1231198331Smav		    ata_version(ident_buf->version_major) : cpi.protocol_version;
1232198331Smav	} else if (path->device->protocol == PROTO_SCSI) {
1233198331Smav		path->device->protocol_version = inq_buf ?
1234198331Smav		    SID_ANSI_REV(inq_buf) : cpi.protocol_version;
1235195534Sscottl	}
1236198331Smav	path->device->transport_version = ident_buf ?
1237198331Smav	    ata_version(ident_buf->version_major) : cpi.transport_version;
1238195534Sscottl
1239195534Sscottl	/* Tell the controller what we think */
1240198382Smav	xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
1241195534Sscottl	cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
1242195534Sscottl	cts.type = CTS_TYPE_CURRENT_SETTINGS;
1243195534Sscottl	cts.transport = path->device->transport;
1244195534Sscottl	cts.transport_version = path->device->transport_version;
1245195534Sscottl	cts.protocol = path->device->protocol;
1246195534Sscottl	cts.protocol_version = path->device->protocol_version;
1247195534Sscottl	cts.proto_specific.valid = 0;
1248195534Sscottl	cts.xport_specific.valid = 0;
1249195534Sscottl	xpt_action((union ccb *)&cts);
1250195534Sscottl}
1251195534Sscottl
1252195534Sscottlstatic void
1253195534Sscottlata_action(union ccb *start_ccb)
1254195534Sscottl{
1255195534Sscottl
1256195534Sscottl	switch (start_ccb->ccb_h.func_code) {
1257195534Sscottl	case XPT_SET_TRAN_SETTINGS:
1258195534Sscottl	{
1259199178Smav		ata_set_transfer_settings(&start_ccb->cts,
1260195534Sscottl					   start_ccb->ccb_h.path->device,
1261195534Sscottl					   /*async_update*/FALSE);
1262195534Sscottl		break;
1263195534Sscottl	}
1264195534Sscottl	case XPT_SCAN_BUS:
1265195534Sscottl		ata_scan_bus(start_ccb->ccb_h.path->periph, start_ccb);
1266195534Sscottl		break;
1267195534Sscottl	case XPT_SCAN_LUN:
1268195534Sscottl		ata_scan_lun(start_ccb->ccb_h.path->periph,
1269195534Sscottl			      start_ccb->ccb_h.path, start_ccb->crcn.flags,
1270195534Sscottl			      start_ccb);
1271195534Sscottl		break;
1272195534Sscottl	case XPT_GET_TRAN_SETTINGS:
1273195534Sscottl	{
1274195534Sscottl		struct cam_sim *sim;
1275195534Sscottl
1276195534Sscottl		sim = start_ccb->ccb_h.path->bus->sim;
1277195534Sscottl		(*(sim->sim_action))(sim, start_ccb);
1278195534Sscottl		break;
1279195534Sscottl	}
1280195534Sscottl	default:
1281195534Sscottl		xpt_action_default(start_ccb);
1282195534Sscottl		break;
1283195534Sscottl	}
1284195534Sscottl}
1285195534Sscottl
1286195534Sscottlstatic void
1287199178Smavata_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device,
1288195534Sscottl			   int async_update)
1289195534Sscottl{
1290195534Sscottl	struct	ccb_pathinq cpi;
1291195534Sscottl	struct	ccb_trans_settings cur_cts;
1292195534Sscottl	struct	ccb_trans_settings_scsi *scsi;
1293195534Sscottl	struct	ccb_trans_settings_scsi *cur_scsi;
1294195534Sscottl	struct	cam_sim *sim;
1295195534Sscottl	struct	scsi_inquiry_data *inq_data;
1296195534Sscottl
1297195534Sscottl	if (device == NULL) {
1298195534Sscottl		cts->ccb_h.status = CAM_PATH_INVALID;
1299195534Sscottl		xpt_done((union ccb *)cts);
1300195534Sscottl		return;
1301195534Sscottl	}
1302195534Sscottl
1303195534Sscottl	if (cts->protocol == PROTO_UNKNOWN
1304195534Sscottl	 || cts->protocol == PROTO_UNSPECIFIED) {
1305195534Sscottl		cts->protocol = device->protocol;
1306195534Sscottl		cts->protocol_version = device->protocol_version;
1307195534Sscottl	}
1308195534Sscottl
1309195534Sscottl	if (cts->protocol_version == PROTO_VERSION_UNKNOWN
1310195534Sscottl	 || cts->protocol_version == PROTO_VERSION_UNSPECIFIED)
1311195534Sscottl		cts->protocol_version = device->protocol_version;
1312195534Sscottl
1313195534Sscottl	if (cts->protocol != device->protocol) {
1314195534Sscottl		xpt_print(cts->ccb_h.path, "Uninitialized Protocol %x:%x?\n",
1315195534Sscottl		       cts->protocol, device->protocol);
1316195534Sscottl		cts->protocol = device->protocol;
1317195534Sscottl	}
1318195534Sscottl
1319195534Sscottl	if (cts->protocol_version > device->protocol_version) {
1320195534Sscottl		if (bootverbose) {
1321195534Sscottl			xpt_print(cts->ccb_h.path, "Down reving Protocol "
1322195534Sscottl			    "Version from %d to %d?\n", cts->protocol_version,
1323195534Sscottl			    device->protocol_version);
1324195534Sscottl		}
1325195534Sscottl		cts->protocol_version = device->protocol_version;
1326195534Sscottl	}
1327195534Sscottl
1328195534Sscottl	if (cts->transport == XPORT_UNKNOWN
1329195534Sscottl	 || cts->transport == XPORT_UNSPECIFIED) {
1330195534Sscottl		cts->transport = device->transport;
1331195534Sscottl		cts->transport_version = device->transport_version;
1332195534Sscottl	}
1333195534Sscottl
1334195534Sscottl	if (cts->transport_version == XPORT_VERSION_UNKNOWN
1335195534Sscottl	 || cts->transport_version == XPORT_VERSION_UNSPECIFIED)
1336195534Sscottl		cts->transport_version = device->transport_version;
1337195534Sscottl
1338195534Sscottl	if (cts->transport != device->transport) {
1339195534Sscottl		xpt_print(cts->ccb_h.path, "Uninitialized Transport %x:%x?\n",
1340195534Sscottl		    cts->transport, device->transport);
1341195534Sscottl		cts->transport = device->transport;
1342195534Sscottl	}
1343195534Sscottl
1344195534Sscottl	if (cts->transport_version > device->transport_version) {
1345195534Sscottl		if (bootverbose) {
1346195534Sscottl			xpt_print(cts->ccb_h.path, "Down reving Transport "
1347195534Sscottl			    "Version from %d to %d?\n", cts->transport_version,
1348195534Sscottl			    device->transport_version);
1349195534Sscottl		}
1350195534Sscottl		cts->transport_version = device->transport_version;
1351195534Sscottl	}
1352195534Sscottl
1353195534Sscottl	sim = cts->ccb_h.path->bus->sim;
1354195534Sscottl
1355195534Sscottl	/*
1356195534Sscottl	 * Nothing more of interest to do unless
1357195534Sscottl	 * this is a device connected via the
1358195534Sscottl	 * SCSI protocol.
1359195534Sscottl	 */
1360195534Sscottl	if (cts->protocol != PROTO_SCSI) {
1361195534Sscottl		if (async_update == FALSE)
1362195534Sscottl			(*(sim->sim_action))(sim, (union ccb *)cts);
1363195534Sscottl		return;
1364195534Sscottl	}
1365195534Sscottl
1366195534Sscottl	inq_data = &device->inq_data;
1367195534Sscottl	scsi = &cts->proto_specific.scsi;
1368198382Smav	xpt_setup_ccb(&cpi.ccb_h, cts->ccb_h.path, CAM_PRIORITY_NORMAL);
1369195534Sscottl	cpi.ccb_h.func_code = XPT_PATH_INQ;
1370195534Sscottl	xpt_action((union ccb *)&cpi);
1371195534Sscottl
1372195534Sscottl	/* SCSI specific sanity checking */
1373195534Sscottl	if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0
1374195534Sscottl	 || (INQ_DATA_TQ_ENABLED(inq_data)) == 0
1375195534Sscottl	 || (device->queue_flags & SCP_QUEUE_DQUE) != 0
1376195534Sscottl	 || (device->mintags == 0)) {
1377195534Sscottl		/*
1378195534Sscottl		 * Can't tag on hardware that doesn't support tags,
1379195534Sscottl		 * doesn't have it enabled, or has broken tag support.
1380195534Sscottl		 */
1381195534Sscottl		scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
1382195534Sscottl	}
1383195534Sscottl
1384195534Sscottl	if (async_update == FALSE) {
1385195534Sscottl		/*
1386195534Sscottl		 * Perform sanity checking against what the
1387195534Sscottl		 * controller and device can do.
1388195534Sscottl		 */
1389198382Smav		xpt_setup_ccb(&cur_cts.ccb_h, cts->ccb_h.path, CAM_PRIORITY_NORMAL);
1390195534Sscottl		cur_cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
1391195534Sscottl		cur_cts.type = cts->type;
1392195534Sscottl		xpt_action((union ccb *)&cur_cts);
1393195534Sscottl		if ((cur_cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1394195534Sscottl			return;
1395195534Sscottl		}
1396195534Sscottl		cur_scsi = &cur_cts.proto_specific.scsi;
1397195534Sscottl		if ((scsi->valid & CTS_SCSI_VALID_TQ) == 0) {
1398195534Sscottl			scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
1399195534Sscottl			scsi->flags |= cur_scsi->flags & CTS_SCSI_FLAGS_TAG_ENB;
1400195534Sscottl		}
1401195534Sscottl		if ((cur_scsi->valid & CTS_SCSI_VALID_TQ) == 0)
1402195534Sscottl			scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
1403195534Sscottl	}
1404195534Sscottl
1405195534Sscottl	if (cts->type == CTS_TYPE_CURRENT_SETTINGS
1406195534Sscottl	 && (scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
1407195534Sscottl		int device_tagenb;
1408195534Sscottl
1409195534Sscottl		/*
1410195534Sscottl		 * If we are transitioning from tags to no-tags or
1411195534Sscottl		 * vice-versa, we need to carefully freeze and restart
1412195534Sscottl		 * the queue so that we don't overlap tagged and non-tagged
1413195534Sscottl		 * commands.  We also temporarily stop tags if there is
1414195534Sscottl		 * a change in transfer negotiation settings to allow
1415195534Sscottl		 * "tag-less" negotiation.
1416195534Sscottl		 */
1417195534Sscottl		if ((device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0
1418195534Sscottl		 || (device->inq_flags & SID_CmdQue) != 0)
1419195534Sscottl			device_tagenb = TRUE;
1420195534Sscottl		else
1421195534Sscottl			device_tagenb = FALSE;
1422195534Sscottl
1423195534Sscottl		if (((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0
1424195534Sscottl		  && device_tagenb == FALSE)
1425195534Sscottl		 || ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) == 0
1426195534Sscottl		  && device_tagenb == TRUE)) {
1427195534Sscottl
1428195534Sscottl			if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) {
1429195534Sscottl				/*
1430195534Sscottl				 * Delay change to use tags until after a
1431195534Sscottl				 * few commands have gone to this device so
1432195534Sscottl				 * the controller has time to perform transfer
1433195534Sscottl				 * negotiations without tagged messages getting
1434195534Sscottl				 * in the way.
1435195534Sscottl				 */
1436195534Sscottl				device->tag_delay_count = CAM_TAG_DELAY_COUNT;
1437195534Sscottl				device->flags |= CAM_DEV_TAG_AFTER_COUNT;
1438195534Sscottl			} else {
1439199178Smav				xpt_stop_tags(cts->ccb_h.path);
1440195534Sscottl			}
1441195534Sscottl		}
1442195534Sscottl	}
1443195534Sscottl	if (async_update == FALSE)
1444195534Sscottl		(*(sim->sim_action))(sim, (union ccb *)cts);
1445195534Sscottl}
1446195534Sscottl
1447195534Sscottl/*
1448195534Sscottl * Handle any per-device event notifications that require action by the XPT.
1449195534Sscottl */
1450195534Sscottlstatic void
1451195534Sscottlata_dev_async(u_int32_t async_code, struct cam_eb *bus, struct cam_et *target,
1452195534Sscottl	      struct cam_ed *device, void *async_arg)
1453195534Sscottl{
1454195534Sscottl	cam_status status;
1455195534Sscottl	struct cam_path newpath;
1456195534Sscottl
1457195534Sscottl	/*
1458195534Sscottl	 * We only need to handle events for real devices.
1459195534Sscottl	 */
1460195534Sscottl	if (target->target_id == CAM_TARGET_WILDCARD
1461195534Sscottl	 || device->lun_id == CAM_LUN_WILDCARD)
1462195534Sscottl		return;
1463195534Sscottl
1464195534Sscottl	/*
1465195534Sscottl	 * We need our own path with wildcards expanded to
1466195534Sscottl	 * handle certain types of events.
1467195534Sscottl	 */
1468195534Sscottl	if ((async_code == AC_SENT_BDR)
1469195534Sscottl	 || (async_code == AC_BUS_RESET)
1470195534Sscottl	 || (async_code == AC_INQ_CHANGED))
1471195534Sscottl		status = xpt_compile_path(&newpath, NULL,
1472195534Sscottl					  bus->path_id,
1473195534Sscottl					  target->target_id,
1474195534Sscottl					  device->lun_id);
1475195534Sscottl	else
1476195534Sscottl		status = CAM_REQ_CMP_ERR;
1477195534Sscottl
1478195534Sscottl	if (status == CAM_REQ_CMP) {
1479195534Sscottl		if (async_code == AC_INQ_CHANGED) {
1480195534Sscottl			/*
1481195534Sscottl			 * We've sent a start unit command, or
1482195534Sscottl			 * something similar to a device that
1483195534Sscottl			 * may have caused its inquiry data to
1484195534Sscottl			 * change. So we re-scan the device to
1485195534Sscottl			 * refresh the inquiry data for it.
1486195534Sscottl			 */
1487195534Sscottl			ata_scan_lun(newpath.periph, &newpath,
1488195534Sscottl				     CAM_EXPECT_INQ_CHANGE, NULL);
1489195534Sscottl		}
1490195534Sscottl		xpt_release_path(&newpath);
1491198748Smav	} else if (async_code == AC_LOST_DEVICE &&
1492198748Smav	    (device->flags & CAM_DEV_UNCONFIGURED) == 0) {
1493195534Sscottl		device->flags |= CAM_DEV_UNCONFIGURED;
1494198748Smav		xpt_release_device(device);
1495195534Sscottl	} else if (async_code == AC_TRANSFER_NEG) {
1496195534Sscottl		struct ccb_trans_settings *settings;
1497195534Sscottl
1498195534Sscottl		settings = (struct ccb_trans_settings *)async_arg;
1499199178Smav		ata_set_transfer_settings(settings, device,
1500195534Sscottl					  /*async_update*/TRUE);
1501195534Sscottl	}
1502195534Sscottl}
1503195534Sscottl
1504