ata_xpt.c revision 196659
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 196659 2009-08-30 16:31:25Z 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/scsi/scsi_pass.h>
66195534Sscottl#include <cam/ata/ata_all.h>
67195534Sscottl#include <machine/stdarg.h>	/* for xpt_print below */
68195534Sscottl#include "opt_cam.h"
69195534Sscottl
70195534Sscottlstruct scsi_quirk_entry {
71195534Sscottl	struct scsi_inquiry_pattern inq_pat;
72195534Sscottl	u_int8_t quirks;
73195534Sscottl#define	CAM_QUIRK_NOLUNS	0x01
74195534Sscottl#define	CAM_QUIRK_NOSERIAL	0x02
75195534Sscottl#define	CAM_QUIRK_HILUNS	0x04
76195534Sscottl#define	CAM_QUIRK_NOHILUNS	0x08
77195534Sscottl	u_int mintags;
78195534Sscottl	u_int maxtags;
79195534Sscottl};
80195534Sscottl#define SCSI_QUIRK(dev)	((struct scsi_quirk_entry *)((dev)->quirk))
81195534Sscottl
82195534Sscottlstatic periph_init_t probe_periph_init;
83195534Sscottl
84195534Sscottlstatic struct periph_driver probe_driver =
85195534Sscottl{
86195653Smav	probe_periph_init, "aprobe",
87195534Sscottl	TAILQ_HEAD_INITIALIZER(probe_driver.units)
88195534Sscottl};
89195534Sscottl
90195653SmavPERIPHDRIVER_DECLARE(aprobe, probe_driver);
91195534Sscottl
92195534Sscottltypedef enum {
93195534Sscottl	PROBE_RESET,
94195534Sscottl	PROBE_IDENTIFY,
95195534Sscottl	PROBE_SETMODE,
96195534Sscottl	PROBE_INQUIRY,
97195534Sscottl	PROBE_FULL_INQUIRY,
98195534Sscottl	PROBE_PM_PID,
99195534Sscottl	PROBE_PM_PRV,
100195534Sscottl	PROBE_PM_PORTS,
101195534Sscottl	PROBE_PM_RESET,
102195534Sscottl	PROBE_PM_CONNECT,
103195534Sscottl	PROBE_PM_CHECK,
104195534Sscottl	PROBE_PM_CLEAR,
105195534Sscottl	PROBE_INVALID
106195534Sscottl} probe_action;
107195534Sscottl
108195534Sscottlstatic char *probe_action_text[] = {
109195534Sscottl	"PROBE_RESET",
110195534Sscottl	"PROBE_IDENTIFY",
111195534Sscottl	"PROBE_SETMODE",
112195534Sscottl	"PROBE_INQUIRY",
113195534Sscottl	"PROBE_FULL_INQUIRY",
114195534Sscottl	"PROBE_PM_PID",
115195534Sscottl	"PROBE_PM_PRV",
116195534Sscottl	"PROBE_PM_PORTS",
117195534Sscottl	"PROBE_PM_RESET",
118195534Sscottl	"PROBE_PM_CONNECT",
119195534Sscottl	"PROBE_PM_CHECK",
120195534Sscottl	"PROBE_PM_CLEAR",
121195534Sscottl	"PROBE_INVALID"
122195534Sscottl};
123195534Sscottl
124195534Sscottl#define PROBE_SET_ACTION(softc, newaction)	\
125195534Sscottldo {									\
126195534Sscottl	char **text;							\
127195534Sscottl	text = probe_action_text;					\
128195534Sscottl	CAM_DEBUG((softc)->periph->path, CAM_DEBUG_INFO,		\
129195534Sscottl	    ("Probe %s to %s\n", text[(softc)->action],			\
130195534Sscottl	    text[(newaction)]));					\
131195534Sscottl	(softc)->action = (newaction);					\
132195534Sscottl} while(0)
133195534Sscottl
134195534Sscottltypedef enum {
135195534Sscottl	PROBE_NO_ANNOUNCE	= 0x04
136195534Sscottl} probe_flags;
137195534Sscottl
138195534Sscottltypedef struct {
139195534Sscottl	TAILQ_HEAD(, ccb_hdr) request_ccbs;
140195534Sscottl	probe_action	action;
141195534Sscottl	union ccb	saved_ccb;
142195534Sscottl	probe_flags	flags;
143195534Sscottl	u_int8_t	digest[16];
144195534Sscottl	uint32_t	pm_pid;
145195534Sscottl	uint32_t	pm_prv;
146195534Sscottl	int		pm_ports;
147195534Sscottl	int		pm_step;
148195534Sscottl	int		pm_try;
149195534Sscottl	struct cam_periph *periph;
150195534Sscottl} probe_softc;
151195534Sscottl
152195534Sscottlstatic struct scsi_quirk_entry scsi_quirk_table[] =
153195534Sscottl{
154195534Sscottl	{
155195534Sscottl		/* Default tagged queuing parameters for all devices */
156195534Sscottl		{
157195534Sscottl		  T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED,
158195534Sscottl		  /*vendor*/"*", /*product*/"*", /*revision*/"*"
159195534Sscottl		},
160195534Sscottl		/*quirks*/0, /*mintags*/2, /*maxtags*/32
161195534Sscottl	},
162195534Sscottl};
163195534Sscottl
164195534Sscottlstatic const int scsi_quirk_table_size =
165195534Sscottl	sizeof(scsi_quirk_table) / sizeof(*scsi_quirk_table);
166195534Sscottl
167195534Sscottlstatic cam_status	proberegister(struct cam_periph *periph,
168195534Sscottl				      void *arg);
169195534Sscottlstatic void	 probeschedule(struct cam_periph *probe_periph);
170195534Sscottlstatic void	 probestart(struct cam_periph *periph, union ccb *start_ccb);
171195534Sscottl//static void	 proberequestdefaultnegotiation(struct cam_periph *periph);
172195534Sscottl//static int       proberequestbackoff(struct cam_periph *periph,
173195534Sscottl//				     struct cam_ed *device);
174195534Sscottlstatic void	 probedone(struct cam_periph *periph, union ccb *done_ccb);
175195534Sscottlstatic void	 probecleanup(struct cam_periph *periph);
176195534Sscottlstatic void	 scsi_find_quirk(struct cam_ed *device);
177195534Sscottlstatic void	 ata_scan_bus(struct cam_periph *periph, union ccb *ccb);
178195534Sscottlstatic void	 ata_scan_lun(struct cam_periph *periph,
179195534Sscottl			       struct cam_path *path, cam_flags flags,
180195534Sscottl			       union ccb *ccb);
181195534Sscottlstatic void	 xptscandone(struct cam_periph *periph, union ccb *done_ccb);
182195534Sscottlstatic struct cam_ed *
183195534Sscottl		 ata_alloc_device(struct cam_eb *bus, struct cam_et *target,
184195534Sscottl				   lun_id_t lun_id);
185195534Sscottlstatic void	 ata_device_transport(struct cam_path *path);
186195534Sscottlstatic void	 scsi_set_transfer_settings(struct ccb_trans_settings *cts,
187195534Sscottl					    struct cam_ed *device,
188195534Sscottl					    int async_update);
189195534Sscottlstatic void	 scsi_toggle_tags(struct cam_path *path);
190195534Sscottlstatic void	 ata_dev_async(u_int32_t async_code,
191195534Sscottl				struct cam_eb *bus,
192195534Sscottl				struct cam_et *target,
193195534Sscottl				struct cam_ed *device,
194195534Sscottl				void *async_arg);
195195534Sscottlstatic void	 ata_action(union ccb *start_ccb);
196195534Sscottl
197195534Sscottlstatic struct xpt_xport ata_xport = {
198195534Sscottl	.alloc_device = ata_alloc_device,
199195534Sscottl	.action = ata_action,
200195534Sscottl	.async = ata_dev_async,
201195534Sscottl};
202195534Sscottl
203195534Sscottlstruct xpt_xport *
204195534Sscottlata_get_xport(void)
205195534Sscottl{
206195534Sscottl	return (&ata_xport);
207195534Sscottl}
208195534Sscottl
209195534Sscottlstatic void
210195534Sscottlprobe_periph_init()
211195534Sscottl{
212195534Sscottl}
213195534Sscottl
214195534Sscottlstatic cam_status
215195534Sscottlproberegister(struct cam_periph *periph, void *arg)
216195534Sscottl{
217195534Sscottl	union ccb *request_ccb;	/* CCB representing the probe request */
218195534Sscottl	cam_status status;
219195534Sscottl	probe_softc *softc;
220195534Sscottl
221195534Sscottl	request_ccb = (union ccb *)arg;
222195534Sscottl	if (periph == NULL) {
223195534Sscottl		printf("proberegister: periph was NULL!!\n");
224195534Sscottl		return(CAM_REQ_CMP_ERR);
225195534Sscottl	}
226195534Sscottl
227195534Sscottl	if (request_ccb == NULL) {
228195534Sscottl		printf("proberegister: no probe CCB, "
229195534Sscottl		       "can't register device\n");
230195534Sscottl		return(CAM_REQ_CMP_ERR);
231195534Sscottl	}
232195534Sscottl
233195534Sscottl	softc = (probe_softc *)malloc(sizeof(*softc), M_CAMXPT, M_NOWAIT);
234195534Sscottl
235195534Sscottl	if (softc == NULL) {
236195534Sscottl		printf("proberegister: Unable to probe new device. "
237195534Sscottl		       "Unable to allocate softc\n");
238195534Sscottl		return(CAM_REQ_CMP_ERR);
239195534Sscottl	}
240195534Sscottl	TAILQ_INIT(&softc->request_ccbs);
241195534Sscottl	TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h,
242195534Sscottl			  periph_links.tqe);
243195534Sscottl	softc->flags = 0;
244195534Sscottl	periph->softc = softc;
245195534Sscottl	softc->periph = periph;
246195534Sscottl	softc->action = PROBE_INVALID;
247195534Sscottl	status = cam_periph_acquire(periph);
248195534Sscottl	if (status != CAM_REQ_CMP) {
249195534Sscottl		return (status);
250195534Sscottl	}
251195534Sscottl
252195534Sscottl
253195534Sscottl	/*
254195534Sscottl	 * Ensure we've waited at least a bus settle
255195534Sscottl	 * delay before attempting to probe the device.
256195534Sscottl	 * For HBAs that don't do bus resets, this won't make a difference.
257195534Sscottl	 */
258195534Sscottl	cam_periph_freeze_after_event(periph, &periph->path->bus->last_reset,
259195534Sscottl				      scsi_delay);
260195534Sscottl	probeschedule(periph);
261195534Sscottl	return(CAM_REQ_CMP);
262195534Sscottl}
263195534Sscottl
264195534Sscottlstatic void
265195534Sscottlprobeschedule(struct cam_periph *periph)
266195534Sscottl{
267195534Sscottl	struct ccb_pathinq cpi;
268195534Sscottl	union ccb *ccb;
269195534Sscottl	probe_softc *softc;
270195534Sscottl
271195534Sscottl	softc = (probe_softc *)periph->softc;
272195534Sscottl	ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs);
273195534Sscottl
274195534Sscottl	xpt_setup_ccb(&cpi.ccb_h, periph->path, /*priority*/1);
275195534Sscottl	cpi.ccb_h.func_code = XPT_PATH_INQ;
276195534Sscottl	xpt_action((union ccb *)&cpi);
277195534Sscottl
278195534Sscottl	if (periph->path->device->flags & CAM_DEV_UNCONFIGURED)
279195534Sscottl		PROBE_SET_ACTION(softc, PROBE_RESET);
280195534Sscottl	else if (periph->path->device->protocol == PROTO_SATAPM)
281195534Sscottl		PROBE_SET_ACTION(softc, PROBE_PM_PID);
282195534Sscottl	else
283195534Sscottl		PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
284195534Sscottl
285195534Sscottl	if (ccb->crcn.flags & CAM_EXPECT_INQ_CHANGE)
286195534Sscottl		softc->flags |= PROBE_NO_ANNOUNCE;
287195534Sscottl	else
288195534Sscottl		softc->flags &= ~PROBE_NO_ANNOUNCE;
289195534Sscottl
290195534Sscottl	xpt_schedule(periph, ccb->ccb_h.pinfo.priority);
291195534Sscottl}
292195534Sscottl
293195534Sscottlstatic void
294195534Sscottlprobestart(struct cam_periph *periph, union ccb *start_ccb)
295195534Sscottl{
296195534Sscottl	/* Probe the device that our peripheral driver points to */
297195534Sscottl	struct ccb_ataio *ataio;
298195534Sscottl	struct ccb_scsiio *csio;
299195534Sscottl	struct ccb_trans_settings cts;
300195534Sscottl	probe_softc *softc;
301195534Sscottl
302195534Sscottl	CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probestart\n"));
303195534Sscottl
304195534Sscottl	softc = (probe_softc *)periph->softc;
305195534Sscottl	ataio = &start_ccb->ataio;
306195534Sscottl	csio = &start_ccb->csio;
307195534Sscottl
308195534Sscottl	switch (softc->action) {
309195534Sscottl	case PROBE_RESET:
310195534Sscottl		if (start_ccb->ccb_h.target_id == 15) {
311195534Sscottl			/* Report SIM that we have no knowledge about PM presence. */
312195534Sscottl			bzero(&cts, sizeof(cts));
313195534Sscottl			xpt_setup_ccb(&cts.ccb_h, start_ccb->ccb_h.path, 1);
314195534Sscottl			cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
315195534Sscottl			cts.type = CTS_TYPE_CURRENT_SETTINGS;
316195534Sscottl			cts.xport_specific.sata.pm_present = 0;
317195534Sscottl			cts.xport_specific.sata.valid = CTS_SATA_VALID_PM;
318195534Sscottl			xpt_action((union ccb *)&cts);
319195534Sscottl		}
320195534Sscottl		cam_fill_ataio(ataio,
321195534Sscottl		      0,
322195534Sscottl		      probedone,
323195534Sscottl		      /*flags*/CAM_DIR_NONE,
324195534Sscottl		      MSG_SIMPLE_Q_TAG,
325195534Sscottl		      /*data_ptr*/NULL,
326195534Sscottl		      /*dxfer_len*/0,
327195534Sscottl		      (start_ccb->ccb_h.target_id == 15 ? 3 : 15) * 1000);
328195534Sscottl		ata_reset_cmd(ataio);
329195534Sscottl		break;
330195534Sscottl	case PROBE_IDENTIFY:
331195534Sscottl	{
332195534Sscottl		struct ata_params *ident_buf =
333195534Sscottl		    &periph->path->device->ident_data;
334195534Sscottl
335195534Sscottl		if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) {
336195534Sscottl			/* Prepare check that it is the same device. */
337195534Sscottl			MD5_CTX context;
338195534Sscottl
339195534Sscottl			MD5Init(&context);
340195534Sscottl			MD5Update(&context,
341195534Sscottl			    (unsigned char *)ident_buf->model,
342195534Sscottl			    sizeof(ident_buf->model));
343195534Sscottl			MD5Update(&context,
344195534Sscottl			    (unsigned char *)ident_buf->revision,
345195534Sscottl			    sizeof(ident_buf->revision));
346195534Sscottl			MD5Update(&context,
347195534Sscottl			    (unsigned char *)ident_buf->serial,
348195534Sscottl			    sizeof(ident_buf->serial));
349195534Sscottl			MD5Final(softc->digest, &context);
350195534Sscottl		}
351195534Sscottl		cam_fill_ataio(ataio,
352195534Sscottl		      1,
353195534Sscottl		      probedone,
354195534Sscottl		      /*flags*/CAM_DIR_IN,
355195534Sscottl		      MSG_SIMPLE_Q_TAG,
356195534Sscottl		      /*data_ptr*/(u_int8_t *)ident_buf,
357195534Sscottl		      /*dxfer_len*/sizeof(struct ata_params),
358195534Sscottl		      30 * 1000);
359195534Sscottl		if (periph->path->device->protocol == PROTO_ATA)
360196659Smav			ata_28bit_cmd(ataio, ATA_ATA_IDENTIFY, 0, 0, 0);
361195534Sscottl		else
362196659Smav			ata_28bit_cmd(ataio, ATA_ATAPI_IDENTIFY, 0, 0, 0);
363195534Sscottl		break;
364195534Sscottl	}
365195534Sscottl	case PROBE_SETMODE:
366195534Sscottl	{
367195534Sscottl		struct ata_params *ident_buf =
368195534Sscottl		    &periph->path->device->ident_data;
369195534Sscottl
370195534Sscottl		cam_fill_ataio(ataio,
371195534Sscottl		      1,
372195534Sscottl		      probedone,
373196353Smav		      /*flags*/CAM_DIR_NONE,
374196353Smav		      0,
375196353Smav		      /*data_ptr*/NULL,
376196353Smav		      /*dxfer_len*/0,
377195534Sscottl		      30 * 1000);
378196659Smav		ata_28bit_cmd(ataio, ATA_SETFEATURES, ATA_SF_SETXFER, 0,
379195534Sscottl		    ata_max_mode(ident_buf, ATA_UDMA6, ATA_UDMA6));
380195534Sscottl		break;
381195534Sscottl	}
382195534Sscottl	case PROBE_INQUIRY:
383195534Sscottl	case PROBE_FULL_INQUIRY:
384195534Sscottl	{
385195534Sscottl		u_int inquiry_len;
386195534Sscottl		struct scsi_inquiry_data *inq_buf =
387195534Sscottl		    &periph->path->device->inq_data;
388195534Sscottl
389195534Sscottl		if (softc->action == PROBE_INQUIRY)
390195534Sscottl			inquiry_len = SHORT_INQUIRY_LENGTH;
391195534Sscottl		else
392195534Sscottl			inquiry_len = SID_ADDITIONAL_LENGTH(inq_buf);
393195534Sscottl		/*
394195534Sscottl		 * Some parallel SCSI devices fail to send an
395195534Sscottl		 * ignore wide residue message when dealing with
396195534Sscottl		 * odd length inquiry requests.  Round up to be
397195534Sscottl		 * safe.
398195534Sscottl		 */
399195534Sscottl		inquiry_len = roundup2(inquiry_len, 2);
400195534Sscottl		scsi_inquiry(csio,
401195534Sscottl			     /*retries*/1,
402195534Sscottl			     probedone,
403195534Sscottl			     MSG_SIMPLE_Q_TAG,
404195534Sscottl			     (u_int8_t *)inq_buf,
405195534Sscottl			     inquiry_len,
406195534Sscottl			     /*evpd*/FALSE,
407195534Sscottl			     /*page_code*/0,
408195534Sscottl			     SSD_MIN_SIZE,
409195534Sscottl			     /*timeout*/60 * 1000);
410195534Sscottl		break;
411195534Sscottl	}
412195534Sscottl	case PROBE_PM_PID:
413195534Sscottl		cam_fill_ataio(ataio,
414195534Sscottl		      1,
415195534Sscottl		      probedone,
416195534Sscottl		      /*flags*/CAM_DIR_NONE,
417195534Sscottl		      MSG_SIMPLE_Q_TAG,
418195534Sscottl		      /*data_ptr*/NULL,
419195534Sscottl		      /*dxfer_len*/0,
420195534Sscottl		      10 * 1000);
421195534Sscottl		ata_pm_read_cmd(ataio, 0, 15);
422195534Sscottl		break;
423195534Sscottl	case PROBE_PM_PRV:
424195534Sscottl		cam_fill_ataio(ataio,
425195534Sscottl		      1,
426195534Sscottl		      probedone,
427195534Sscottl		      /*flags*/CAM_DIR_NONE,
428195534Sscottl		      MSG_SIMPLE_Q_TAG,
429195534Sscottl		      /*data_ptr*/NULL,
430195534Sscottl		      /*dxfer_len*/0,
431195534Sscottl		      10 * 1000);
432195534Sscottl		ata_pm_read_cmd(ataio, 1, 15);
433195534Sscottl		break;
434195534Sscottl	case PROBE_PM_PORTS:
435195534Sscottl		cam_fill_ataio(ataio,
436195534Sscottl		      1,
437195534Sscottl		      probedone,
438195534Sscottl		      /*flags*/CAM_DIR_NONE,
439195534Sscottl		      MSG_SIMPLE_Q_TAG,
440195534Sscottl		      /*data_ptr*/NULL,
441195534Sscottl		      /*dxfer_len*/0,
442195534Sscottl		      10 * 1000);
443195534Sscottl		ata_pm_read_cmd(ataio, 2, 15);
444195534Sscottl		break;
445195534Sscottl	case PROBE_PM_RESET:
446195534Sscottl	{
447195534Sscottl		struct ata_params *ident_buf =
448195534Sscottl		    &periph->path->device->ident_data;
449195534Sscottl		cam_fill_ataio(ataio,
450195534Sscottl		      1,
451195534Sscottl		      probedone,
452195534Sscottl		      /*flags*/CAM_DIR_NONE,
453195534Sscottl		      MSG_SIMPLE_Q_TAG,
454195534Sscottl		      /*data_ptr*/NULL,
455195534Sscottl		      /*dxfer_len*/0,
456195534Sscottl		      10 * 1000);
457195534Sscottl		ata_pm_write_cmd(ataio, 2, softc->pm_step,
458195534Sscottl		    (ident_buf->cylinders & (1 << softc->pm_step)) ? 0 : 1);
459195534Sscottlprintf("PM RESET %d %04x %d\n", softc->pm_step, ident_buf->cylinders,
460195534Sscottl    (ident_buf->cylinders & (1 << softc->pm_step)) ? 0 : 1);
461195534Sscottl		break;
462195534Sscottl	}
463195534Sscottl	case PROBE_PM_CONNECT:
464195534Sscottl		cam_fill_ataio(ataio,
465195534Sscottl		      1,
466195534Sscottl		      probedone,
467195534Sscottl		      /*flags*/CAM_DIR_NONE,
468195534Sscottl		      MSG_SIMPLE_Q_TAG,
469195534Sscottl		      /*data_ptr*/NULL,
470195534Sscottl		      /*dxfer_len*/0,
471195534Sscottl		      10 * 1000);
472195534Sscottl		ata_pm_write_cmd(ataio, 2, softc->pm_step, 0);
473195534Sscottl		break;
474195534Sscottl	case PROBE_PM_CHECK:
475195534Sscottl		cam_fill_ataio(ataio,
476195534Sscottl		      1,
477195534Sscottl		      probedone,
478195534Sscottl		      /*flags*/CAM_DIR_NONE,
479195534Sscottl		      MSG_SIMPLE_Q_TAG,
480195534Sscottl		      /*data_ptr*/NULL,
481195534Sscottl		      /*dxfer_len*/0,
482195534Sscottl		      10 * 1000);
483195534Sscottl		ata_pm_read_cmd(ataio, 0, softc->pm_step);
484195534Sscottl		break;
485195534Sscottl	case PROBE_PM_CLEAR:
486195534Sscottl		cam_fill_ataio(ataio,
487195534Sscottl		      1,
488195534Sscottl		      probedone,
489195534Sscottl		      /*flags*/CAM_DIR_NONE,
490195534Sscottl		      MSG_SIMPLE_Q_TAG,
491195534Sscottl		      /*data_ptr*/NULL,
492195534Sscottl		      /*dxfer_len*/0,
493195534Sscottl		      10 * 1000);
494195534Sscottl		ata_pm_write_cmd(ataio, 1, softc->pm_step, 0xFFFFFFFF);
495195534Sscottl		break;
496195534Sscottl	case PROBE_INVALID:
497195534Sscottl		CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_INFO,
498195534Sscottl		    ("probestart: invalid action state\n"));
499195534Sscottl	default:
500195534Sscottl		break;
501195534Sscottl	}
502195534Sscottl	xpt_action(start_ccb);
503195534Sscottl}
504195534Sscottl#if 0
505195534Sscottlstatic void
506195534Sscottlproberequestdefaultnegotiation(struct cam_periph *periph)
507195534Sscottl{
508195534Sscottl	struct ccb_trans_settings cts;
509195534Sscottl
510195534Sscottl	xpt_setup_ccb(&cts.ccb_h, periph->path, /*priority*/1);
511195534Sscottl	cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
512195534Sscottl	cts.type = CTS_TYPE_USER_SETTINGS;
513195534Sscottl	xpt_action((union ccb *)&cts);
514195534Sscottl	if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
515195534Sscottl		return;
516195534Sscottl	}
517195534Sscottl	cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
518195534Sscottl	cts.type = CTS_TYPE_CURRENT_SETTINGS;
519195534Sscottl	xpt_action((union ccb *)&cts);
520195534Sscottl}
521195534Sscottl
522195534Sscottl/*
523195534Sscottl * Backoff Negotiation Code- only pertinent for SPI devices.
524195534Sscottl */
525195534Sscottlstatic int
526195534Sscottlproberequestbackoff(struct cam_periph *periph, struct cam_ed *device)
527195534Sscottl{
528195534Sscottl	struct ccb_trans_settings cts;
529195534Sscottl	struct ccb_trans_settings_spi *spi;
530195534Sscottl
531195534Sscottl	memset(&cts, 0, sizeof (cts));
532195534Sscottl	xpt_setup_ccb(&cts.ccb_h, periph->path, /*priority*/1);
533195534Sscottl	cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
534195534Sscottl	cts.type = CTS_TYPE_CURRENT_SETTINGS;
535195534Sscottl	xpt_action((union ccb *)&cts);
536195534Sscottl	if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
537195534Sscottl		if (bootverbose) {
538195534Sscottl			xpt_print(periph->path,
539195534Sscottl			    "failed to get current device settings\n");
540195534Sscottl		}
541195534Sscottl		return (0);
542195534Sscottl	}
543195534Sscottl	if (cts.transport != XPORT_SPI) {
544195534Sscottl		if (bootverbose) {
545195534Sscottl			xpt_print(periph->path, "not SPI transport\n");
546195534Sscottl		}
547195534Sscottl		return (0);
548195534Sscottl	}
549195534Sscottl	spi = &cts.xport_specific.spi;
550195534Sscottl
551195534Sscottl	/*
552195534Sscottl	 * We cannot renegotiate sync rate if we don't have one.
553195534Sscottl	 */
554195534Sscottl	if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) {
555195534Sscottl		if (bootverbose) {
556195534Sscottl			xpt_print(periph->path, "no sync rate known\n");
557195534Sscottl		}
558195534Sscottl		return (0);
559195534Sscottl	}
560195534Sscottl
561195534Sscottl	/*
562195534Sscottl	 * We'll assert that we don't have to touch PPR options- the
563195534Sscottl	 * SIM will see what we do with period and offset and adjust
564195534Sscottl	 * the PPR options as appropriate.
565195534Sscottl	 */
566195534Sscottl
567195534Sscottl	/*
568195534Sscottl	 * A sync rate with unknown or zero offset is nonsensical.
569195534Sscottl	 * A sync period of zero means Async.
570195534Sscottl	 */
571195534Sscottl	if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0
572195534Sscottl	 || spi->sync_offset == 0 || spi->sync_period == 0) {
573195534Sscottl		if (bootverbose) {
574195534Sscottl			xpt_print(periph->path, "no sync rate available\n");
575195534Sscottl		}
576195534Sscottl		return (0);
577195534Sscottl	}
578195534Sscottl
579195534Sscottl	if (device->flags & CAM_DEV_DV_HIT_BOTTOM) {
580195534Sscottl		CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
581195534Sscottl		    ("hit async: giving up on DV\n"));
582195534Sscottl		return (0);
583195534Sscottl	}
584195534Sscottl
585195534Sscottl
586195534Sscottl	/*
587195534Sscottl	 * Jump sync_period up by one, but stop at 5MHz and fall back to Async.
588195534Sscottl	 * We don't try to remember 'last' settings to see if the SIM actually
589195534Sscottl	 * gets into the speed we want to set. We check on the SIM telling
590195534Sscottl	 * us that a requested speed is bad, but otherwise don't try and
591195534Sscottl	 * check the speed due to the asynchronous and handshake nature
592195534Sscottl	 * of speed setting.
593195534Sscottl	 */
594195534Sscottl	spi->valid = CTS_SPI_VALID_SYNC_RATE | CTS_SPI_VALID_SYNC_OFFSET;
595195534Sscottl	for (;;) {
596195534Sscottl		spi->sync_period++;
597195534Sscottl		if (spi->sync_period >= 0xf) {
598195534Sscottl			spi->sync_period = 0;
599195534Sscottl			spi->sync_offset = 0;
600195534Sscottl			CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
601195534Sscottl			    ("setting to async for DV\n"));
602195534Sscottl			/*
603195534Sscottl			 * Once we hit async, we don't want to try
604195534Sscottl			 * any more settings.
605195534Sscottl			 */
606195534Sscottl			device->flags |= CAM_DEV_DV_HIT_BOTTOM;
607195534Sscottl		} else if (bootverbose) {
608195534Sscottl			CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
609195534Sscottl			    ("DV: period 0x%x\n", spi->sync_period));
610195534Sscottl			printf("setting period to 0x%x\n", spi->sync_period);
611195534Sscottl		}
612195534Sscottl		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
613195534Sscottl		cts.type = CTS_TYPE_CURRENT_SETTINGS;
614195534Sscottl		xpt_action((union ccb *)&cts);
615195534Sscottl		if ((cts.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
616195534Sscottl			break;
617195534Sscottl		}
618195534Sscottl		CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
619195534Sscottl		    ("DV: failed to set period 0x%x\n", spi->sync_period));
620195534Sscottl		if (spi->sync_period == 0) {
621195534Sscottl			return (0);
622195534Sscottl		}
623195534Sscottl	}
624195534Sscottl	return (1);
625195534Sscottl}
626195534Sscottl#endif
627195534Sscottlstatic void
628195534Sscottlprobedone(struct cam_periph *periph, union ccb *done_ccb)
629195534Sscottl{
630195534Sscottl	struct ata_params *ident_buf;
631195534Sscottl	probe_softc *softc;
632195534Sscottl	struct cam_path *path;
633195534Sscottl	u_int32_t  priority;
634195534Sscottl	int found = 0;
635195534Sscottl
636195534Sscottl	CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probedone\n"));
637195534Sscottl
638195534Sscottl	softc = (probe_softc *)periph->softc;
639195534Sscottl	path = done_ccb->ccb_h.path;
640195534Sscottl	priority = done_ccb->ccb_h.pinfo.priority;
641195534Sscottl	ident_buf = &path->device->ident_data;
642195534Sscottl
643195534Sscottl	switch (softc->action) {
644195534Sscottl	case PROBE_RESET:
645195534Sscottl		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
646195534Sscottl			int sign = (done_ccb->ataio.res.lba_high << 8) +
647195534Sscottl			    done_ccb->ataio.res.lba_mid;
648195534Sscottl			xpt_print(path, "SIGNATURE: %04x\n", sign);
649195534Sscottl			if (sign == 0x0000 &&
650195534Sscottl			    done_ccb->ccb_h.target_id != 15) {
651195534Sscottl				path->device->protocol = PROTO_ATA;
652195534Sscottl				PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
653195534Sscottl			} else if (sign == 0x9669 &&
654195534Sscottl			    done_ccb->ccb_h.target_id == 15) {
655195534Sscottl				struct ccb_trans_settings cts;
656195534Sscottl
657195534Sscottl				/* Report SIM that PM is present. */
658195534Sscottl				bzero(&cts, sizeof(cts));
659195534Sscottl				xpt_setup_ccb(&cts.ccb_h, path, 1);
660195534Sscottl				cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
661195534Sscottl				cts.type = CTS_TYPE_CURRENT_SETTINGS;
662195534Sscottl				cts.xport_specific.sata.pm_present = 1;
663195534Sscottl				cts.xport_specific.sata.valid = CTS_SATA_VALID_PM;
664195534Sscottl				xpt_action((union ccb *)&cts);
665195534Sscottl				path->device->protocol = PROTO_SATAPM;
666195534Sscottl				PROBE_SET_ACTION(softc, PROBE_PM_PID);
667195534Sscottl			} else if (sign == 0xeb14 &&
668195534Sscottl			    done_ccb->ccb_h.target_id != 15) {
669195534Sscottl				path->device->protocol = PROTO_SCSI;
670195534Sscottl				PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
671195534Sscottl			} else {
672195534Sscottl				if (done_ccb->ccb_h.target_id != 15) {
673195534Sscottl					xpt_print(path,
674195534Sscottl					    "Unexpected signature 0x%04x\n", sign);
675195534Sscottl				}
676195534Sscottl				xpt_release_ccb(done_ccb);
677195534Sscottl				break;
678195534Sscottl			}
679195534Sscottl			xpt_release_ccb(done_ccb);
680195534Sscottl			xpt_schedule(periph, priority);
681195534Sscottl			return;
682195534Sscottl		} else if (cam_periph_error(done_ccb, 0, 0,
683195534Sscottl					    &softc->saved_ccb) == ERESTART) {
684195534Sscottl			return;
685195534Sscottl		} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
686195534Sscottl			/* Don't wedge the queue */
687195534Sscottl			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
688195534Sscottl					 /*run_queue*/TRUE);
689195534Sscottl		}
690195534Sscottl		goto device_fail;
691195534Sscottl	case PROBE_IDENTIFY:
692195534Sscottl	{
693195534Sscottl		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
694195534Sscottl			int16_t *ptr;
695195534Sscottl
696195534Sscottl			for (ptr = (int16_t *)ident_buf;
697195534Sscottl			     ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) {
698195534Sscottl				*ptr = le16toh(*ptr);
699195534Sscottl			}
700195534Sscottl			if (strncmp(ident_buf->model, "FX", 2) &&
701195534Sscottl			    strncmp(ident_buf->model, "NEC", 3) &&
702195534Sscottl			    strncmp(ident_buf->model, "Pioneer", 7) &&
703195534Sscottl			    strncmp(ident_buf->model, "SHARP", 5)) {
704195534Sscottl				ata_bswap(ident_buf->model, sizeof(ident_buf->model));
705195534Sscottl				ata_bswap(ident_buf->revision, sizeof(ident_buf->revision));
706195534Sscottl				ata_bswap(ident_buf->serial, sizeof(ident_buf->serial));
707195534Sscottl			}
708195534Sscottl			ata_btrim(ident_buf->model, sizeof(ident_buf->model));
709195534Sscottl			ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model));
710195534Sscottl			ata_btrim(ident_buf->revision, sizeof(ident_buf->revision));
711195534Sscottl			ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision));
712195534Sscottl			ata_btrim(ident_buf->serial, sizeof(ident_buf->serial));
713195534Sscottl			ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial));
714195534Sscottl
715195534Sscottl			if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) {
716195534Sscottl				/* Check that it is the same device. */
717195534Sscottl				MD5_CTX context;
718195534Sscottl				u_int8_t digest[16];
719195534Sscottl
720195534Sscottl				MD5Init(&context);
721195534Sscottl				MD5Update(&context,
722195534Sscottl				    (unsigned char *)ident_buf->model,
723195534Sscottl				    sizeof(ident_buf->model));
724195534Sscottl				MD5Update(&context,
725195534Sscottl				    (unsigned char *)ident_buf->revision,
726195534Sscottl				    sizeof(ident_buf->revision));
727195534Sscottl				MD5Update(&context,
728195534Sscottl				    (unsigned char *)ident_buf->serial,
729195534Sscottl				    sizeof(ident_buf->serial));
730195534Sscottl				MD5Final(digest, &context);
731195534Sscottl				if (bcmp(digest, softc->digest, sizeof(digest))) {
732195534Sscottl					/* Device changed. */
733195534Sscottl					xpt_async(AC_LOST_DEVICE, path, NULL);
734195534Sscottl				}
735195534Sscottl				xpt_release_ccb(done_ccb);
736195534Sscottl				break;
737195534Sscottl			}
738195534Sscottl
739195534Sscottl			/* Clean up from previous instance of this device */
740195534Sscottl			if (path->device->serial_num != NULL) {
741195534Sscottl				free(path->device->serial_num, M_CAMXPT);
742195534Sscottl				path->device->serial_num = NULL;
743195534Sscottl				path->device->serial_num_len = 0;
744195534Sscottl			}
745195534Sscottl			path->device->serial_num =
746195534Sscottl				(u_int8_t *)malloc((sizeof(ident_buf->serial) + 1),
747195534Sscottl						   M_CAMXPT, M_NOWAIT);
748195534Sscottl			if (path->device->serial_num != NULL) {
749195534Sscottl				bcopy(ident_buf->serial,
750195534Sscottl				      path->device->serial_num,
751195534Sscottl				      sizeof(ident_buf->serial));
752195534Sscottl				path->device->serial_num[sizeof(ident_buf->serial)]
753195534Sscottl				    = '\0';
754195534Sscottl				path->device->serial_num_len =
755195534Sscottl				    strlen(path->device->serial_num);
756195534Sscottl			}
757195534Sscottl
758195534Sscottl			path->device->flags |= CAM_DEV_INQUIRY_DATA_VALID;
759195534Sscottl
760195534Sscottl			scsi_find_quirk(path->device);
761195534Sscottl			ata_device_transport(path);
762195534Sscottl
763195534Sscottl			PROBE_SET_ACTION(softc, PROBE_SETMODE);
764195534Sscottl			xpt_release_ccb(done_ccb);
765195534Sscottl			xpt_schedule(periph, priority);
766195534Sscottl			return;
767195534Sscottl		} else if (cam_periph_error(done_ccb, 0, 0,
768195534Sscottl					    &softc->saved_ccb) == ERESTART) {
769195534Sscottl			return;
770195534Sscottl		} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
771195534Sscottl			/* Don't wedge the queue */
772195534Sscottl			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
773195534Sscottl					 /*run_queue*/TRUE);
774195534Sscottl		}
775195534Sscottldevice_fail:
776195534Sscottl		/*
777195534Sscottl		 * If we get to this point, we got an error status back
778195534Sscottl		 * from the inquiry and the error status doesn't require
779195534Sscottl		 * automatically retrying the command.  Therefore, the
780195534Sscottl		 * inquiry failed.  If we had inquiry information before
781195534Sscottl		 * for this device, but this latest inquiry command failed,
782195534Sscottl		 * the device has probably gone away.  If this device isn't
783195534Sscottl		 * already marked unconfigured, notify the peripheral
784195534Sscottl		 * drivers that this device is no more.
785195534Sscottl		 */
786195534Sscottl		if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0)
787195534Sscottl			/* Send the async notification. */
788195534Sscottl			xpt_async(AC_LOST_DEVICE, path, NULL);
789195534Sscottl
790195534Sscottl		xpt_release_ccb(done_ccb);
791195534Sscottl		break;
792195534Sscottl	}
793195534Sscottl	case PROBE_SETMODE:
794195534Sscottl	{
795195534Sscottl		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
796195534Sscottl			if (path->device->protocol == PROTO_ATA) {
797195534Sscottl				path->device->flags &= ~CAM_DEV_UNCONFIGURED;
798195534Sscottl				done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
799195534Sscottl				xpt_action(done_ccb);
800195534Sscottl				xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path,
801195534Sscottl				    done_ccb);
802195534Sscottl				xpt_release_ccb(done_ccb);
803195534Sscottl				break;
804195534Sscottl			} else {
805195534Sscottl				PROBE_SET_ACTION(softc, PROBE_INQUIRY);
806195534Sscottl				xpt_release_ccb(done_ccb);
807195534Sscottl				xpt_schedule(periph, priority);
808195534Sscottl				return;
809195534Sscottl			}
810195534Sscottl		} else if (cam_periph_error(done_ccb, 0, 0,
811195534Sscottl					    &softc->saved_ccb) == ERESTART) {
812195534Sscottl			return;
813195534Sscottl		} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
814195534Sscottl			/* Don't wedge the queue */
815195534Sscottl			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
816195534Sscottl					 /*run_queue*/TRUE);
817195534Sscottl		}
818195534Sscottl		goto device_fail;
819195534Sscottl	}
820195534Sscottl	case PROBE_INQUIRY:
821195534Sscottl	case PROBE_FULL_INQUIRY:
822195534Sscottl	{
823195534Sscottl		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
824195534Sscottl			struct scsi_inquiry_data *inq_buf;
825195534Sscottl			u_int8_t periph_qual;
826195534Sscottl
827195534Sscottl			path->device->flags |= CAM_DEV_INQUIRY_DATA_VALID;
828195534Sscottl			inq_buf = &path->device->inq_data;
829195534Sscottl
830195534Sscottl			periph_qual = SID_QUAL(inq_buf);
831195534Sscottl
832195534Sscottl			if (periph_qual == SID_QUAL_LU_CONNECTED) {
833195534Sscottl				u_int8_t len;
834195534Sscottl
835195534Sscottl				/*
836195534Sscottl				 * We conservatively request only
837195534Sscottl				 * SHORT_INQUIRY_LEN bytes of inquiry
838195534Sscottl				 * information during our first try
839195534Sscottl				 * at sending an INQUIRY. If the device
840195534Sscottl				 * has more information to give,
841195534Sscottl				 * perform a second request specifying
842195534Sscottl				 * the amount of information the device
843195534Sscottl				 * is willing to give.
844195534Sscottl				 */
845195534Sscottl				len = inq_buf->additional_length
846195534Sscottl				    + offsetof(struct scsi_inquiry_data,
847195534Sscottl                                               additional_length) + 1;
848195534Sscottl				if (softc->action == PROBE_INQUIRY
849195534Sscottl				    && len > SHORT_INQUIRY_LENGTH) {
850195534Sscottl					PROBE_SET_ACTION(softc, PROBE_FULL_INQUIRY);
851195534Sscottl					xpt_release_ccb(done_ccb);
852195534Sscottl					xpt_schedule(periph, priority);
853195534Sscottl					return;
854195534Sscottl				}
855195534Sscottl
856195534Sscottl				scsi_find_quirk(path->device);
857195534Sscottl
858195534Sscottl//				scsi_devise_transport(path);
859195534Sscottl				path->device->flags &= ~CAM_DEV_UNCONFIGURED;
860195534Sscottl				done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
861195534Sscottl				xpt_action(done_ccb);
862195534Sscottl				xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path,
863195534Sscottl				    done_ccb);
864195534Sscottl				xpt_release_ccb(done_ccb);
865195534Sscottl				break;
866195534Sscottl			}
867195534Sscottl		} else if (cam_periph_error(done_ccb, 0, 0,
868195534Sscottl					    &softc->saved_ccb) == ERESTART) {
869195534Sscottl			return;
870195534Sscottl		} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
871195534Sscottl			/* Don't wedge the queue */
872195534Sscottl			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
873195534Sscottl					 /*run_queue*/TRUE);
874195534Sscottl		}
875195534Sscottl		goto device_fail;
876195534Sscottl	}
877195534Sscottl	case PROBE_PM_PID:
878195534Sscottl		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
879195534Sscottl			if ((path->device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0)
880195534Sscottl				bzero(ident_buf, sizeof(*ident_buf));
881195534Sscottl			softc->pm_pid = (done_ccb->ataio.res.lba_high << 24) +
882195534Sscottl			    (done_ccb->ataio.res.lba_mid << 16) +
883195534Sscottl			    (done_ccb->ataio.res.lba_low << 8) +
884195534Sscottl			    done_ccb->ataio.res.sector_count;
885195534Sscottl			printf("PM Product ID: %08x\n", softc->pm_pid);
886195534Sscottl			snprintf(ident_buf->model, sizeof(ident_buf->model),
887195534Sscottl			    "Port Multiplier %08x", softc->pm_pid);
888195534Sscottl			PROBE_SET_ACTION(softc, PROBE_PM_PRV);
889195534Sscottl			xpt_release_ccb(done_ccb);
890195534Sscottl			xpt_schedule(periph, priority);
891195534Sscottl			return;
892195534Sscottl		} else if (cam_periph_error(done_ccb, 0, 0,
893195534Sscottl					    &softc->saved_ccb) == ERESTART) {
894195534Sscottl			return;
895195534Sscottl		} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
896195534Sscottl			/* Don't wedge the queue */
897195534Sscottl			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
898195534Sscottl					 /*run_queue*/TRUE);
899195534Sscottl		}
900195534Sscottl		goto device_fail;
901195534Sscottl	case PROBE_PM_PRV:
902195534Sscottl		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
903195534Sscottl			softc->pm_prv = (done_ccb->ataio.res.lba_high << 24) +
904195534Sscottl			    (done_ccb->ataio.res.lba_mid << 16) +
905195534Sscottl			    (done_ccb->ataio.res.lba_low << 8) +
906195534Sscottl			    done_ccb->ataio.res.sector_count;
907195534Sscottl			printf("PM Revision: %08x\n", softc->pm_prv);
908195534Sscottl			snprintf(ident_buf->revision, sizeof(ident_buf->revision),
909195534Sscottl			    "%04x", softc->pm_prv);
910195534Sscottl			PROBE_SET_ACTION(softc, PROBE_PM_PORTS);
911195534Sscottl			xpt_release_ccb(done_ccb);
912195534Sscottl			xpt_schedule(periph, priority);
913195534Sscottl			return;
914195534Sscottl		} else if (cam_periph_error(done_ccb, 0, 0,
915195534Sscottl					    &softc->saved_ccb) == ERESTART) {
916195534Sscottl			return;
917195534Sscottl		} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
918195534Sscottl			/* Don't wedge the queue */
919195534Sscottl			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
920195534Sscottl					 /*run_queue*/TRUE);
921195534Sscottl		}
922195534Sscottl		goto device_fail;
923195534Sscottl	case PROBE_PM_PORTS:
924195534Sscottl		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
925195534Sscottl			softc->pm_ports = (done_ccb->ataio.res.lba_high << 24) +
926195534Sscottl			    (done_ccb->ataio.res.lba_mid << 16) +
927195534Sscottl			    (done_ccb->ataio.res.lba_low << 8) +
928195534Sscottl			    done_ccb->ataio.res.sector_count;
929195534Sscottl			/* This PM declares 6 ports, while only 5 of them are real.
930195534Sscottl			 * Port 5 is enclosure management bridge port, which has implementation
931195534Sscottl			 * problems, causing probe faults. Hide it for now. */
932195534Sscottl			if (softc->pm_pid == 0x37261095 && softc->pm_ports == 6)
933195534Sscottl				softc->pm_ports = 5;
934195534Sscottl			/* This PM declares 7 ports, while only 5 of them are real.
935195534Sscottl			 * Port 5 is some fake "Config  Disk" with 640 sectors size,
936195534Sscottl			 * port 6 is enclosure management bridge port.
937195534Sscottl			 * Both fake ports has implementation problems, causing
938195534Sscottl			 * probe faults. Hide them for now. */
939195534Sscottl			if (softc->pm_pid == 0x47261095 && softc->pm_ports == 7)
940195534Sscottl				softc->pm_ports = 5;
941195534Sscottl			printf("PM ports: %d\n", softc->pm_ports);
942195534Sscottl			ident_buf->config = softc->pm_ports;
943195534Sscottl			path->device->flags |= CAM_DEV_INQUIRY_DATA_VALID;
944195534Sscottl			softc->pm_step = 0;
945195534Sscottl			PROBE_SET_ACTION(softc, PROBE_PM_RESET);
946195534Sscottl			xpt_release_ccb(done_ccb);
947195534Sscottl			xpt_schedule(periph, priority);
948195534Sscottl			return;
949195534Sscottl		} else if (cam_periph_error(done_ccb, 0, 0,
950195534Sscottl					    &softc->saved_ccb) == ERESTART) {
951195534Sscottl			return;
952195534Sscottl		} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
953195534Sscottl			/* Don't wedge the queue */
954195534Sscottl			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
955195534Sscottl					 /*run_queue*/TRUE);
956195534Sscottl		}
957195534Sscottl		goto device_fail;
958195534Sscottl	case PROBE_PM_RESET:
959195534Sscottl		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
960195534Sscottl			softc->pm_step++;
961195534Sscottl			if (softc->pm_step < softc->pm_ports) {
962195534Sscottl				xpt_release_ccb(done_ccb);
963195534Sscottl				xpt_schedule(periph, priority);
964195534Sscottl				return;
965195534Sscottl			} else {
966195534Sscottl				softc->pm_step = 0;
967195534Sscottl				DELAY(5000);
968195534Sscottl				printf("PM reset done\n");
969195534Sscottl				PROBE_SET_ACTION(softc, PROBE_PM_CONNECT);
970195534Sscottl				xpt_release_ccb(done_ccb);
971195534Sscottl				xpt_schedule(periph, priority);
972195534Sscottl				return;
973195534Sscottl			}
974195534Sscottl		} else if (cam_periph_error(done_ccb, 0, 0,
975195534Sscottl					    &softc->saved_ccb) == ERESTART) {
976195534Sscottl			return;
977195534Sscottl		} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
978195534Sscottl			/* Don't wedge the queue */
979195534Sscottl			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
980195534Sscottl					 /*run_queue*/TRUE);
981195534Sscottl		}
982195534Sscottl		goto device_fail;
983195534Sscottl	case PROBE_PM_CONNECT:
984195534Sscottl		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
985195534Sscottl			softc->pm_step++;
986195534Sscottl			if (softc->pm_step < softc->pm_ports) {
987195534Sscottl				xpt_release_ccb(done_ccb);
988195534Sscottl				xpt_schedule(periph, priority);
989195534Sscottl				return;
990195534Sscottl			} else {
991195534Sscottl				softc->pm_step = 0;
992195534Sscottl				softc->pm_try = 0;
993195534Sscottl				printf("PM connect done\n");
994195534Sscottl				PROBE_SET_ACTION(softc, PROBE_PM_CHECK);
995195534Sscottl				xpt_release_ccb(done_ccb);
996195534Sscottl				xpt_schedule(periph, priority);
997195534Sscottl				return;
998195534Sscottl			}
999195534Sscottl		} else if (cam_periph_error(done_ccb, 0, 0,
1000195534Sscottl					    &softc->saved_ccb) == ERESTART) {
1001195534Sscottl			return;
1002195534Sscottl		} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
1003195534Sscottl			/* Don't wedge the queue */
1004195534Sscottl			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
1005195534Sscottl					 /*run_queue*/TRUE);
1006195534Sscottl		}
1007195534Sscottl		goto device_fail;
1008195534Sscottl	case PROBE_PM_CHECK:
1009195534Sscottl		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
1010195534Sscottl			int res = (done_ccb->ataio.res.lba_high << 24) +
1011195534Sscottl			    (done_ccb->ataio.res.lba_mid << 16) +
1012195534Sscottl			    (done_ccb->ataio.res.lba_low << 8) +
1013195534Sscottl			    done_ccb->ataio.res.sector_count;
1014195534Sscottl			if ((res & 0xf0f) == 0x103 && (res & 0x0f0) != 0) {
1015195534Sscottl				printf("PM status: %d - %08x\n", softc->pm_step, res);
1016195534Sscottl				ident_buf->cylinders |= (1 << softc->pm_step);
1017195534Sscottl				softc->pm_step++;
1018195534Sscottl			} else {
1019195534Sscottl				if (softc->pm_try < 100) {
1020195534Sscottl					DELAY(10000);
1021195534Sscottl					softc->pm_try++;
1022195534Sscottl				} else {
1023195534Sscottl					printf("PM status: %d - %08x\n", softc->pm_step, res);
1024195534Sscottl					ident_buf->cylinders &= ~(1 << softc->pm_step);
1025195534Sscottl					softc->pm_step++;
1026195534Sscottl				}
1027195534Sscottl			}
1028195534Sscottl			if (softc->pm_step < softc->pm_ports) {
1029195534Sscottl				xpt_release_ccb(done_ccb);
1030195534Sscottl				xpt_schedule(periph, priority);
1031195534Sscottl				return;
1032195534Sscottl			} else {
1033195534Sscottl				softc->pm_step = 0;
1034195534Sscottl				PROBE_SET_ACTION(softc, PROBE_PM_CLEAR);
1035195534Sscottl				xpt_release_ccb(done_ccb);
1036195534Sscottl				xpt_schedule(periph, priority);
1037195534Sscottl				return;
1038195534Sscottl			}
1039195534Sscottl		} else if (cam_periph_error(done_ccb, 0, 0,
1040195534Sscottl					    &softc->saved_ccb) == ERESTART) {
1041195534Sscottl			return;
1042195534Sscottl		} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
1043195534Sscottl			/* Don't wedge the queue */
1044195534Sscottl			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
1045195534Sscottl					 /*run_queue*/TRUE);
1046195534Sscottl		}
1047195534Sscottl		goto device_fail;
1048195534Sscottl	case PROBE_PM_CLEAR:
1049195534Sscottl		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
1050195534Sscottl			softc->pm_step++;
1051195534Sscottl			if (softc->pm_step < softc->pm_ports) {
1052195534Sscottl				xpt_release_ccb(done_ccb);
1053195534Sscottl				xpt_schedule(periph, priority);
1054195534Sscottl				return;
1055195534Sscottl			}
1056195534Sscottl			found = ident_buf->cylinders | 0x8000;
1057195534Sscottl			if (path->device->flags & CAM_DEV_UNCONFIGURED) {
1058195534Sscottl				path->device->flags &= ~CAM_DEV_UNCONFIGURED;
1059195534Sscottl				done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
1060195534Sscottl				xpt_action(done_ccb);
1061195534Sscottl				xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path,
1062195534Sscottl				    done_ccb);
1063195534Sscottl				xpt_release_ccb(done_ccb);
1064195534Sscottl			}
1065195534Sscottl			break;
1066195534Sscottl		} else if (cam_periph_error(done_ccb, 0, 0,
1067195534Sscottl					    &softc->saved_ccb) == ERESTART) {
1068195534Sscottl			return;
1069195534Sscottl		} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
1070195534Sscottl			/* Don't wedge the queue */
1071195534Sscottl			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
1072195534Sscottl					 /*run_queue*/TRUE);
1073195534Sscottl		}
1074195534Sscottl		goto device_fail;
1075195534Sscottl	case PROBE_INVALID:
1076195534Sscottl		CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_INFO,
1077195534Sscottl		    ("probedone: invalid action state\n"));
1078195534Sscottl	default:
1079195534Sscottl		break;
1080195534Sscottl	}
1081195534Sscottl	done_ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs);
1082195534Sscottl	TAILQ_REMOVE(&softc->request_ccbs, &done_ccb->ccb_h, periph_links.tqe);
1083195534Sscottl	done_ccb->ccb_h.status = CAM_REQ_CMP;
1084195534Sscottl	done_ccb->ccb_h.ppriv_field1 = found;
1085195534Sscottl	xpt_done(done_ccb);
1086195534Sscottl	if (TAILQ_FIRST(&softc->request_ccbs) == NULL) {
1087195534Sscottl		cam_periph_invalidate(periph);
1088195534Sscottl		cam_periph_release_locked(periph);
1089195534Sscottl	} else {
1090195534Sscottl		probeschedule(periph);
1091195534Sscottl	}
1092195534Sscottl}
1093195534Sscottl
1094195534Sscottlstatic void
1095195534Sscottlprobecleanup(struct cam_periph *periph)
1096195534Sscottl{
1097195534Sscottl	free(periph->softc, M_CAMXPT);
1098195534Sscottl}
1099195534Sscottl
1100195534Sscottlstatic void
1101195534Sscottlscsi_find_quirk(struct cam_ed *device)
1102195534Sscottl{
1103195534Sscottl	struct scsi_quirk_entry *quirk;
1104195534Sscottl	caddr_t	match;
1105195534Sscottl
1106195534Sscottl	match = cam_quirkmatch((caddr_t)&device->inq_data,
1107195534Sscottl			       (caddr_t)scsi_quirk_table,
1108195534Sscottl			       sizeof(scsi_quirk_table) /
1109195534Sscottl			       sizeof(*scsi_quirk_table),
1110195534Sscottl			       sizeof(*scsi_quirk_table), scsi_inquiry_match);
1111195534Sscottl
1112195534Sscottl	if (match == NULL)
1113195534Sscottl		panic("xpt_find_quirk: device didn't match wildcard entry!!");
1114195534Sscottl
1115195534Sscottl	quirk = (struct scsi_quirk_entry *)match;
1116195534Sscottl	device->quirk = quirk;
1117195534Sscottl	device->mintags = quirk->mintags;
1118195534Sscottl	device->maxtags = quirk->maxtags;
1119195534Sscottl}
1120195534Sscottl
1121195534Sscottltypedef struct {
1122195534Sscottl	union	ccb *request_ccb;
1123195534Sscottl	struct 	ccb_pathinq *cpi;
1124195534Sscottl	int	counter;
1125195534Sscottl	int	found;
1126195534Sscottl} ata_scan_bus_info;
1127195534Sscottl
1128195534Sscottl/*
1129195534Sscottl * To start a scan, request_ccb is an XPT_SCAN_BUS ccb.
1130195534Sscottl * As the scan progresses, xpt_scan_bus is used as the
1131195534Sscottl * callback on completion function.
1132195534Sscottl */
1133195534Sscottlstatic void
1134195534Sscottlata_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
1135195534Sscottl{
1136195534Sscottl	struct	cam_path *path;
1137195534Sscottl	ata_scan_bus_info *scan_info;
1138195534Sscottl	union	ccb *work_ccb;
1139195534Sscottl	cam_status status;
1140195534Sscottl
1141195534Sscottl	CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE,
1142195534Sscottl		  ("xpt_scan_bus\n"));
1143195534Sscottl	switch (request_ccb->ccb_h.func_code) {
1144195534Sscottl	case XPT_SCAN_BUS:
1145195534Sscottl		/* Find out the characteristics of the bus */
1146195534Sscottl		work_ccb = xpt_alloc_ccb_nowait();
1147195534Sscottl		if (work_ccb == NULL) {
1148195534Sscottl			request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1149195534Sscottl			xpt_done(request_ccb);
1150195534Sscottl			return;
1151195534Sscottl		}
1152195534Sscottl		xpt_setup_ccb(&work_ccb->ccb_h, request_ccb->ccb_h.path,
1153195534Sscottl			      request_ccb->ccb_h.pinfo.priority);
1154195534Sscottl		work_ccb->ccb_h.func_code = XPT_PATH_INQ;
1155195534Sscottl		xpt_action(work_ccb);
1156195534Sscottl		if (work_ccb->ccb_h.status != CAM_REQ_CMP) {
1157195534Sscottl			request_ccb->ccb_h.status = work_ccb->ccb_h.status;
1158195534Sscottl			xpt_free_ccb(work_ccb);
1159195534Sscottl			xpt_done(request_ccb);
1160195534Sscottl			return;
1161195534Sscottl		}
1162195534Sscottl
1163195534Sscottl		/* Save some state for use while we probe for devices */
1164195534Sscottl		scan_info = (ata_scan_bus_info *)
1165195534Sscottl		    malloc(sizeof(ata_scan_bus_info), M_CAMXPT, M_NOWAIT);
1166195534Sscottl		if (scan_info == NULL) {
1167195534Sscottl			request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1168195534Sscottl			xpt_done(request_ccb);
1169195534Sscottl			return;
1170195534Sscottl		}
1171195534Sscottl		scan_info->request_ccb = request_ccb;
1172195534Sscottl		scan_info->cpi = &work_ccb->cpi;
1173195534Sscottl		scan_info->found = 0x8001;
1174195534Sscottl		scan_info->counter = 0;
1175195534Sscottl		/* If PM supported, probe it first. */
1176195534Sscottl		if (scan_info->cpi->hba_inquiry & PI_SATAPM)
1177195534Sscottl			scan_info->counter = 15;
1178195534Sscottl
1179195534Sscottl		work_ccb = xpt_alloc_ccb_nowait();
1180195534Sscottl		if (work_ccb == NULL) {
1181195534Sscottl			free(scan_info, M_CAMXPT);
1182195534Sscottl			request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
1183195534Sscottl			xpt_done(request_ccb);
1184195534Sscottl			break;
1185195534Sscottl		}
1186195534Sscottl		goto scan_next;
1187195534Sscottl	case XPT_SCAN_LUN:
1188195534Sscottl		work_ccb = request_ccb;
1189195534Sscottl		/* Reuse the same CCB to query if a device was really found */
1190195534Sscottl		scan_info = (ata_scan_bus_info *)work_ccb->ccb_h.ppriv_ptr0;
1191195534Sscottl		/* Free the current request path- we're done with it. */
1192195534Sscottl		xpt_free_path(work_ccb->ccb_h.path);
1193195534Sscottl		/* If there is PM... */
1194195534Sscottl		if (scan_info->counter == 15) {
1195195534Sscottl			if (work_ccb->ccb_h.ppriv_field1 != 0) {
1196195534Sscottl				/* Save PM probe result. */
1197195534Sscottl				scan_info->found = work_ccb->ccb_h.ppriv_field1;
1198195534Sscottl			} else {
1199195534Sscottl				struct ccb_trans_settings cts;
1200195534Sscottl
1201195534Sscottl				/* Report SIM that PM is absent. */
1202195534Sscottl				bzero(&cts, sizeof(cts));
1203195534Sscottl				xpt_setup_ccb(&cts.ccb_h,
1204195534Sscottl				    scan_info->request_ccb->ccb_h.path, 1);
1205195534Sscottl				cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
1206195534Sscottl				cts.type = CTS_TYPE_CURRENT_SETTINGS;
1207195665Smav				cts.xport_specific.sata.pm_present = 0;
1208195534Sscottl				cts.xport_specific.sata.valid = CTS_SATA_VALID_PM;
1209195534Sscottl				xpt_action((union ccb *)&cts);
1210195534Sscottl			}
1211195534Sscottl		}
1212195534Sscottltake_next:
1213195534Sscottl		/* Take next device. Wrap from 15 (PM) to 0. */
1214195534Sscottl		scan_info->counter = (scan_info->counter + 1 ) & 0x0f;
1215195534Sscottl		if (scan_info->counter >= scan_info->cpi->max_target+1) {
1216195534Sscottl			xpt_free_ccb(work_ccb);
1217195534Sscottl			xpt_free_ccb((union ccb *)scan_info->cpi);
1218195534Sscottl			request_ccb = scan_info->request_ccb;
1219195534Sscottl			free(scan_info, M_CAMXPT);
1220195534Sscottl			request_ccb->ccb_h.status = CAM_REQ_CMP;
1221195534Sscottl			xpt_done(request_ccb);
1222195534Sscottl			break;
1223195534Sscottl		}
1224195534Sscottlscan_next:
1225195534Sscottl		status = xpt_create_path(&path, xpt_periph,
1226195534Sscottl		    scan_info->request_ccb->ccb_h.path_id,
1227195534Sscottl		    scan_info->counter, 0);
1228195534Sscottl		if (status != CAM_REQ_CMP) {
1229195534Sscottl			printf("xpt_scan_bus: xpt_create_path failed"
1230195534Sscottl			    " with status %#x, bus scan halted\n",
1231195534Sscottl			    status);
1232195534Sscottl			xpt_free_ccb(work_ccb);
1233195534Sscottl			xpt_free_ccb((union ccb *)scan_info->cpi);
1234195534Sscottl			request_ccb = scan_info->request_ccb;
1235195534Sscottl			free(scan_info, M_CAMXPT);
1236195534Sscottl			request_ccb->ccb_h.status = status;
1237195534Sscottl			xpt_done(request_ccb);
1238195534Sscottl			break;
1239195534Sscottl		}
1240195534Sscottl		if ((scan_info->found & (1 << scan_info->counter)) == 0) {
1241195534Sscottl			xpt_async(AC_LOST_DEVICE, path, NULL);
1242195534Sscottl			xpt_free_path(path);
1243195534Sscottl			goto take_next;
1244195534Sscottl		}
1245195534Sscottl		xpt_setup_ccb(&work_ccb->ccb_h, path,
1246195534Sscottl		    scan_info->request_ccb->ccb_h.pinfo.priority);
1247195534Sscottl		work_ccb->ccb_h.func_code = XPT_SCAN_LUN;
1248195534Sscottl		work_ccb->ccb_h.cbfcnp = ata_scan_bus;
1249195534Sscottl		work_ccb->ccb_h.ppriv_ptr0 = scan_info;
1250195534Sscottl		work_ccb->crcn.flags = scan_info->request_ccb->crcn.flags;
1251195534Sscottl		xpt_action(work_ccb);
1252195534Sscottl		break;
1253195534Sscottl	default:
1254195534Sscottl		break;
1255195534Sscottl	}
1256195534Sscottl}
1257195534Sscottl
1258195534Sscottlstatic void
1259195534Sscottlata_scan_lun(struct cam_periph *periph, struct cam_path *path,
1260195534Sscottl	     cam_flags flags, union ccb *request_ccb)
1261195534Sscottl{
1262195534Sscottl	struct ccb_pathinq cpi;
1263195534Sscottl	cam_status status;
1264195534Sscottl	struct cam_path *new_path;
1265195534Sscottl	struct cam_periph *old_periph;
1266195534Sscottl
1267195534Sscottl	CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE,
1268195534Sscottl		  ("xpt_scan_lun\n"));
1269195534Sscottl
1270195534Sscottl	xpt_setup_ccb(&cpi.ccb_h, path, /*priority*/1);
1271195534Sscottl	cpi.ccb_h.func_code = XPT_PATH_INQ;
1272195534Sscottl	xpt_action((union ccb *)&cpi);
1273195534Sscottl
1274195534Sscottl	if (cpi.ccb_h.status != CAM_REQ_CMP) {
1275195534Sscottl		if (request_ccb != NULL) {
1276195534Sscottl			request_ccb->ccb_h.status = cpi.ccb_h.status;
1277195534Sscottl			xpt_done(request_ccb);
1278195534Sscottl		}
1279195534Sscottl		return;
1280195534Sscottl	}
1281195534Sscottl
1282195534Sscottl	if (request_ccb == NULL) {
1283195534Sscottl		request_ccb = malloc(sizeof(union ccb), M_CAMXPT, M_NOWAIT);
1284195534Sscottl		if (request_ccb == NULL) {
1285195534Sscottl			xpt_print(path, "xpt_scan_lun: can't allocate CCB, "
1286195534Sscottl			    "can't continue\n");
1287195534Sscottl			return;
1288195534Sscottl		}
1289195534Sscottl		new_path = malloc(sizeof(*new_path), M_CAMXPT, M_NOWAIT);
1290195534Sscottl		if (new_path == NULL) {
1291195534Sscottl			xpt_print(path, "xpt_scan_lun: can't allocate path, "
1292195534Sscottl			    "can't continue\n");
1293195534Sscottl			free(request_ccb, M_CAMXPT);
1294195534Sscottl			return;
1295195534Sscottl		}
1296195534Sscottl		status = xpt_compile_path(new_path, xpt_periph,
1297195534Sscottl					  path->bus->path_id,
1298195534Sscottl					  path->target->target_id,
1299195534Sscottl					  path->device->lun_id);
1300195534Sscottl
1301195534Sscottl		if (status != CAM_REQ_CMP) {
1302195534Sscottl			xpt_print(path, "xpt_scan_lun: can't compile path, "
1303195534Sscottl			    "can't continue\n");
1304195534Sscottl			free(request_ccb, M_CAMXPT);
1305195534Sscottl			free(new_path, M_CAMXPT);
1306195534Sscottl			return;
1307195534Sscottl		}
1308195534Sscottl		xpt_setup_ccb(&request_ccb->ccb_h, new_path, /*priority*/ 1);
1309195534Sscottl		request_ccb->ccb_h.cbfcnp = xptscandone;
1310195534Sscottl		request_ccb->ccb_h.func_code = XPT_SCAN_LUN;
1311195534Sscottl		request_ccb->crcn.flags = flags;
1312195534Sscottl	}
1313195534Sscottl
1314195653Smav	if ((old_periph = cam_periph_find(path, "aprobe")) != NULL) {
1315195534Sscottl		probe_softc *softc;
1316195534Sscottl
1317195534Sscottl		softc = (probe_softc *)old_periph->softc;
1318195534Sscottl		TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h,
1319195534Sscottl				  periph_links.tqe);
1320195534Sscottl	} else {
1321195534Sscottl		status = cam_periph_alloc(proberegister, NULL, probecleanup,
1322195653Smav					  probestart, "aprobe",
1323195534Sscottl					  CAM_PERIPH_BIO,
1324195534Sscottl					  request_ccb->ccb_h.path, NULL, 0,
1325195534Sscottl					  request_ccb);
1326195534Sscottl
1327195534Sscottl		if (status != CAM_REQ_CMP) {
1328195534Sscottl			xpt_print(path, "xpt_scan_lun: cam_alloc_periph "
1329195534Sscottl			    "returned an error, can't continue probe\n");
1330195534Sscottl			request_ccb->ccb_h.status = status;
1331195534Sscottl			xpt_done(request_ccb);
1332195534Sscottl		}
1333195534Sscottl	}
1334195534Sscottl}
1335195534Sscottl
1336195534Sscottlstatic void
1337195534Sscottlxptscandone(struct cam_periph *periph, union ccb *done_ccb)
1338195534Sscottl{
1339195534Sscottl	xpt_release_path(done_ccb->ccb_h.path);
1340195534Sscottl	free(done_ccb->ccb_h.path, M_CAMXPT);
1341195534Sscottl	free(done_ccb, M_CAMXPT);
1342195534Sscottl}
1343195534Sscottl
1344195534Sscottlstatic struct cam_ed *
1345195534Sscottlata_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id)
1346195534Sscottl{
1347195534Sscottl	struct cam_path path;
1348195534Sscottl	struct scsi_quirk_entry *quirk;
1349195534Sscottl	struct cam_ed *device;
1350195534Sscottl	struct cam_ed *cur_device;
1351195534Sscottl
1352195534Sscottl	device = xpt_alloc_device(bus, target, lun_id);
1353195534Sscottl	if (device == NULL)
1354195534Sscottl		return (NULL);
1355195534Sscottl
1356195534Sscottl	/*
1357195534Sscottl	 * Take the default quirk entry until we have inquiry
1358195534Sscottl	 * data and can determine a better quirk to use.
1359195534Sscottl	 */
1360195534Sscottl	quirk = &scsi_quirk_table[scsi_quirk_table_size - 1];
1361195534Sscottl	device->quirk = (void *)quirk;
1362195534Sscottl	device->mintags = quirk->mintags;
1363195534Sscottl	device->maxtags = quirk->maxtags;
1364195534Sscottl	bzero(&device->inq_data, sizeof(device->inq_data));
1365195534Sscottl	device->inq_flags = 0;
1366195534Sscottl	device->queue_flags = 0;
1367195534Sscottl	device->serial_num = NULL;
1368195534Sscottl	device->serial_num_len = 0;
1369195534Sscottl
1370195534Sscottl	/*
1371195534Sscottl	 * XXX should be limited by number of CCBs this bus can
1372195534Sscottl	 * do.
1373195534Sscottl	 */
1374195534Sscottl	bus->sim->max_ccbs += device->ccbq.devq_openings;
1375195534Sscottl	/* Insertion sort into our target's device list */
1376195534Sscottl	cur_device = TAILQ_FIRST(&target->ed_entries);
1377195534Sscottl	while (cur_device != NULL && cur_device->lun_id < lun_id)
1378195534Sscottl		cur_device = TAILQ_NEXT(cur_device, links);
1379195534Sscottl	if (cur_device != NULL) {
1380195534Sscottl		TAILQ_INSERT_BEFORE(cur_device, device, links);
1381195534Sscottl	} else {
1382195534Sscottl		TAILQ_INSERT_TAIL(&target->ed_entries, device, links);
1383195534Sscottl	}
1384195534Sscottl	target->generation++;
1385195534Sscottl	if (lun_id != CAM_LUN_WILDCARD) {
1386195534Sscottl		xpt_compile_path(&path,
1387195534Sscottl				 NULL,
1388195534Sscottl				 bus->path_id,
1389195534Sscottl				 target->target_id,
1390195534Sscottl				 lun_id);
1391195534Sscottl		ata_device_transport(&path);
1392195534Sscottl		xpt_release_path(&path);
1393195534Sscottl	}
1394195534Sscottl
1395195534Sscottl	return (device);
1396195534Sscottl}
1397195534Sscottl
1398195534Sscottlstatic void
1399195534Sscottlata_device_transport(struct cam_path *path)
1400195534Sscottl{
1401195534Sscottl	struct ccb_pathinq cpi;
1402195534Sscottl//	struct ccb_trans_settings cts;
1403195534Sscottl	struct scsi_inquiry_data *inq_buf;
1404195534Sscottl
1405195534Sscottl	/* Get transport information from the SIM */
1406195534Sscottl	xpt_setup_ccb(&cpi.ccb_h, path, /*priority*/1);
1407195534Sscottl	cpi.ccb_h.func_code = XPT_PATH_INQ;
1408195534Sscottl	xpt_action((union ccb *)&cpi);
1409195534Sscottl
1410195534Sscottl	inq_buf = NULL;
1411195534Sscottl//	if ((path->device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0)
1412195534Sscottl//		inq_buf = &path->device->inq_data;
1413195534Sscottl//	path->device->protocol = cpi.protocol;
1414195534Sscottl//	path->device->protocol_version =
1415195534Sscottl//	    inq_buf != NULL ? SID_ANSI_REV(inq_buf) : cpi.protocol_version;
1416195534Sscottl	path->device->transport = cpi.transport;
1417195534Sscottl	path->device->transport_version = cpi.transport_version;
1418195534Sscottl#if 0
1419195534Sscottl	/*
1420195534Sscottl	 * Any device not using SPI3 features should
1421195534Sscottl	 * be considered SPI2 or lower.
1422195534Sscottl	 */
1423195534Sscottl	if (inq_buf != NULL) {
1424195534Sscottl		if (path->device->transport == XPORT_SPI
1425195534Sscottl		 && (inq_buf->spi3data & SID_SPI_MASK) == 0
1426195534Sscottl		 && path->device->transport_version > 2)
1427195534Sscottl			path->device->transport_version = 2;
1428195534Sscottl	} else {
1429195534Sscottl		struct cam_ed* otherdev;
1430195534Sscottl
1431195534Sscottl		for (otherdev = TAILQ_FIRST(&path->target->ed_entries);
1432195534Sscottl		     otherdev != NULL;
1433195534Sscottl		     otherdev = TAILQ_NEXT(otherdev, links)) {
1434195534Sscottl			if (otherdev != path->device)
1435195534Sscottl				break;
1436195534Sscottl		}
1437195534Sscottl
1438195534Sscottl		if (otherdev != NULL) {
1439195534Sscottl			/*
1440195534Sscottl			 * Initially assume the same versioning as
1441195534Sscottl			 * prior luns for this target.
1442195534Sscottl			 */
1443195534Sscottl			path->device->protocol_version =
1444195534Sscottl			    otherdev->protocol_version;
1445195534Sscottl			path->device->transport_version =
1446195534Sscottl			    otherdev->transport_version;
1447195534Sscottl		} else {
1448195534Sscottl			/* Until we know better, opt for safty */
1449195534Sscottl			path->device->protocol_version = 2;
1450195534Sscottl			if (path->device->transport == XPORT_SPI)
1451195534Sscottl				path->device->transport_version = 2;
1452195534Sscottl			else
1453195534Sscottl				path->device->transport_version = 0;
1454195534Sscottl		}
1455195534Sscottl	}
1456195534Sscottl
1457195534Sscottl	/*
1458195534Sscottl	 * XXX
1459195534Sscottl	 * For a device compliant with SPC-2 we should be able
1460195534Sscottl	 * to determine the transport version supported by
1461195534Sscottl	 * scrutinizing the version descriptors in the
1462195534Sscottl	 * inquiry buffer.
1463195534Sscottl	 */
1464195534Sscottl
1465195534Sscottl	/* Tell the controller what we think */
1466195534Sscottl	xpt_setup_ccb(&cts.ccb_h, path, /*priority*/1);
1467195534Sscottl	cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
1468195534Sscottl	cts.type = CTS_TYPE_CURRENT_SETTINGS;
1469195534Sscottl	cts.transport = path->device->transport;
1470195534Sscottl	cts.transport_version = path->device->transport_version;
1471195534Sscottl	cts.protocol = path->device->protocol;
1472195534Sscottl	cts.protocol_version = path->device->protocol_version;
1473195534Sscottl	cts.proto_specific.valid = 0;
1474195534Sscottl	cts.xport_specific.valid = 0;
1475195534Sscottl	xpt_action((union ccb *)&cts);
1476195534Sscottl#endif
1477195534Sscottl}
1478195534Sscottl
1479195534Sscottlstatic void
1480195534Sscottlata_action(union ccb *start_ccb)
1481195534Sscottl{
1482195534Sscottl
1483195534Sscottl	switch (start_ccb->ccb_h.func_code) {
1484195534Sscottl	case XPT_SET_TRAN_SETTINGS:
1485195534Sscottl	{
1486195534Sscottl		scsi_set_transfer_settings(&start_ccb->cts,
1487195534Sscottl					   start_ccb->ccb_h.path->device,
1488195534Sscottl					   /*async_update*/FALSE);
1489195534Sscottl		break;
1490195534Sscottl	}
1491195534Sscottl	case XPT_SCAN_BUS:
1492195534Sscottl		ata_scan_bus(start_ccb->ccb_h.path->periph, start_ccb);
1493195534Sscottl		break;
1494195534Sscottl	case XPT_SCAN_LUN:
1495195534Sscottl		ata_scan_lun(start_ccb->ccb_h.path->periph,
1496195534Sscottl			      start_ccb->ccb_h.path, start_ccb->crcn.flags,
1497195534Sscottl			      start_ccb);
1498195534Sscottl		break;
1499195534Sscottl	case XPT_GET_TRAN_SETTINGS:
1500195534Sscottl	{
1501195534Sscottl		struct cam_sim *sim;
1502195534Sscottl
1503195534Sscottl		sim = start_ccb->ccb_h.path->bus->sim;
1504195534Sscottl		(*(sim->sim_action))(sim, start_ccb);
1505195534Sscottl		break;
1506195534Sscottl	}
1507195534Sscottl	default:
1508195534Sscottl		xpt_action_default(start_ccb);
1509195534Sscottl		break;
1510195534Sscottl	}
1511195534Sscottl}
1512195534Sscottl
1513195534Sscottlstatic void
1514195534Sscottlscsi_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device,
1515195534Sscottl			   int async_update)
1516195534Sscottl{
1517195534Sscottl	struct	ccb_pathinq cpi;
1518195534Sscottl	struct	ccb_trans_settings cur_cts;
1519195534Sscottl	struct	ccb_trans_settings_scsi *scsi;
1520195534Sscottl	struct	ccb_trans_settings_scsi *cur_scsi;
1521195534Sscottl	struct	cam_sim *sim;
1522195534Sscottl	struct	scsi_inquiry_data *inq_data;
1523195534Sscottl
1524195534Sscottl	if (device == NULL) {
1525195534Sscottl		cts->ccb_h.status = CAM_PATH_INVALID;
1526195534Sscottl		xpt_done((union ccb *)cts);
1527195534Sscottl		return;
1528195534Sscottl	}
1529195534Sscottl
1530195534Sscottl	if (cts->protocol == PROTO_UNKNOWN
1531195534Sscottl	 || cts->protocol == PROTO_UNSPECIFIED) {
1532195534Sscottl		cts->protocol = device->protocol;
1533195534Sscottl		cts->protocol_version = device->protocol_version;
1534195534Sscottl	}
1535195534Sscottl
1536195534Sscottl	if (cts->protocol_version == PROTO_VERSION_UNKNOWN
1537195534Sscottl	 || cts->protocol_version == PROTO_VERSION_UNSPECIFIED)
1538195534Sscottl		cts->protocol_version = device->protocol_version;
1539195534Sscottl
1540195534Sscottl	if (cts->protocol != device->protocol) {
1541195534Sscottl		xpt_print(cts->ccb_h.path, "Uninitialized Protocol %x:%x?\n",
1542195534Sscottl		       cts->protocol, device->protocol);
1543195534Sscottl		cts->protocol = device->protocol;
1544195534Sscottl	}
1545195534Sscottl
1546195534Sscottl	if (cts->protocol_version > device->protocol_version) {
1547195534Sscottl		if (bootverbose) {
1548195534Sscottl			xpt_print(cts->ccb_h.path, "Down reving Protocol "
1549195534Sscottl			    "Version from %d to %d?\n", cts->protocol_version,
1550195534Sscottl			    device->protocol_version);
1551195534Sscottl		}
1552195534Sscottl		cts->protocol_version = device->protocol_version;
1553195534Sscottl	}
1554195534Sscottl
1555195534Sscottl	if (cts->transport == XPORT_UNKNOWN
1556195534Sscottl	 || cts->transport == XPORT_UNSPECIFIED) {
1557195534Sscottl		cts->transport = device->transport;
1558195534Sscottl		cts->transport_version = device->transport_version;
1559195534Sscottl	}
1560195534Sscottl
1561195534Sscottl	if (cts->transport_version == XPORT_VERSION_UNKNOWN
1562195534Sscottl	 || cts->transport_version == XPORT_VERSION_UNSPECIFIED)
1563195534Sscottl		cts->transport_version = device->transport_version;
1564195534Sscottl
1565195534Sscottl	if (cts->transport != device->transport) {
1566195534Sscottl		xpt_print(cts->ccb_h.path, "Uninitialized Transport %x:%x?\n",
1567195534Sscottl		    cts->transport, device->transport);
1568195534Sscottl		cts->transport = device->transport;
1569195534Sscottl	}
1570195534Sscottl
1571195534Sscottl	if (cts->transport_version > device->transport_version) {
1572195534Sscottl		if (bootverbose) {
1573195534Sscottl			xpt_print(cts->ccb_h.path, "Down reving Transport "
1574195534Sscottl			    "Version from %d to %d?\n", cts->transport_version,
1575195534Sscottl			    device->transport_version);
1576195534Sscottl		}
1577195534Sscottl		cts->transport_version = device->transport_version;
1578195534Sscottl	}
1579195534Sscottl
1580195534Sscottl	sim = cts->ccb_h.path->bus->sim;
1581195534Sscottl
1582195534Sscottl	/*
1583195534Sscottl	 * Nothing more of interest to do unless
1584195534Sscottl	 * this is a device connected via the
1585195534Sscottl	 * SCSI protocol.
1586195534Sscottl	 */
1587195534Sscottl	if (cts->protocol != PROTO_SCSI) {
1588195534Sscottl		if (async_update == FALSE)
1589195534Sscottl			(*(sim->sim_action))(sim, (union ccb *)cts);
1590195534Sscottl		return;
1591195534Sscottl	}
1592195534Sscottl
1593195534Sscottl	inq_data = &device->inq_data;
1594195534Sscottl	scsi = &cts->proto_specific.scsi;
1595195534Sscottl	xpt_setup_ccb(&cpi.ccb_h, cts->ccb_h.path, /*priority*/1);
1596195534Sscottl	cpi.ccb_h.func_code = XPT_PATH_INQ;
1597195534Sscottl	xpt_action((union ccb *)&cpi);
1598195534Sscottl
1599195534Sscottl	/* SCSI specific sanity checking */
1600195534Sscottl	if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0
1601195534Sscottl	 || (INQ_DATA_TQ_ENABLED(inq_data)) == 0
1602195534Sscottl	 || (device->queue_flags & SCP_QUEUE_DQUE) != 0
1603195534Sscottl	 || (device->mintags == 0)) {
1604195534Sscottl		/*
1605195534Sscottl		 * Can't tag on hardware that doesn't support tags,
1606195534Sscottl		 * doesn't have it enabled, or has broken tag support.
1607195534Sscottl		 */
1608195534Sscottl		scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
1609195534Sscottl	}
1610195534Sscottl
1611195534Sscottl	if (async_update == FALSE) {
1612195534Sscottl		/*
1613195534Sscottl		 * Perform sanity checking against what the
1614195534Sscottl		 * controller and device can do.
1615195534Sscottl		 */
1616195534Sscottl		xpt_setup_ccb(&cur_cts.ccb_h, cts->ccb_h.path, /*priority*/1);
1617195534Sscottl		cur_cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
1618195534Sscottl		cur_cts.type = cts->type;
1619195534Sscottl		xpt_action((union ccb *)&cur_cts);
1620195534Sscottl		if ((cur_cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1621195534Sscottl			return;
1622195534Sscottl		}
1623195534Sscottl		cur_scsi = &cur_cts.proto_specific.scsi;
1624195534Sscottl		if ((scsi->valid & CTS_SCSI_VALID_TQ) == 0) {
1625195534Sscottl			scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
1626195534Sscottl			scsi->flags |= cur_scsi->flags & CTS_SCSI_FLAGS_TAG_ENB;
1627195534Sscottl		}
1628195534Sscottl		if ((cur_scsi->valid & CTS_SCSI_VALID_TQ) == 0)
1629195534Sscottl			scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
1630195534Sscottl	}
1631195534Sscottl
1632195534Sscottl	/* SPI specific sanity checking */
1633195534Sscottl	if (cts->transport == XPORT_SPI && async_update == FALSE) {
1634195534Sscottl		u_int spi3caps;
1635195534Sscottl		struct ccb_trans_settings_spi *spi;
1636195534Sscottl		struct ccb_trans_settings_spi *cur_spi;
1637195534Sscottl
1638195534Sscottl		spi = &cts->xport_specific.spi;
1639195534Sscottl
1640195534Sscottl		cur_spi = &cur_cts.xport_specific.spi;
1641195534Sscottl
1642195534Sscottl		/* Fill in any gaps in what the user gave us */
1643195534Sscottl		if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0)
1644195534Sscottl			spi->sync_period = cur_spi->sync_period;
1645195534Sscottl		if ((cur_spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0)
1646195534Sscottl			spi->sync_period = 0;
1647195534Sscottl		if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0)
1648195534Sscottl			spi->sync_offset = cur_spi->sync_offset;
1649195534Sscottl		if ((cur_spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0)
1650195534Sscottl			spi->sync_offset = 0;
1651195534Sscottl		if ((spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0)
1652195534Sscottl			spi->ppr_options = cur_spi->ppr_options;
1653195534Sscottl		if ((cur_spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0)
1654195534Sscottl			spi->ppr_options = 0;
1655195534Sscottl		if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) == 0)
1656195534Sscottl			spi->bus_width = cur_spi->bus_width;
1657195534Sscottl		if ((cur_spi->valid & CTS_SPI_VALID_BUS_WIDTH) == 0)
1658195534Sscottl			spi->bus_width = 0;
1659195534Sscottl		if ((spi->valid & CTS_SPI_VALID_DISC) == 0) {
1660195534Sscottl			spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
1661195534Sscottl			spi->flags |= cur_spi->flags & CTS_SPI_FLAGS_DISC_ENB;
1662195534Sscottl		}
1663195534Sscottl		if ((cur_spi->valid & CTS_SPI_VALID_DISC) == 0)
1664195534Sscottl			spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
1665195534Sscottl		if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0
1666195534Sscottl		  && (inq_data->flags & SID_Sync) == 0
1667195534Sscottl		  && cts->type == CTS_TYPE_CURRENT_SETTINGS)
1668195534Sscottl		 || ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0)) {
1669195534Sscottl			/* Force async */
1670195534Sscottl			spi->sync_period = 0;
1671195534Sscottl			spi->sync_offset = 0;
1672195534Sscottl		}
1673195534Sscottl
1674195534Sscottl		switch (spi->bus_width) {
1675195534Sscottl		case MSG_EXT_WDTR_BUS_32_BIT:
1676195534Sscottl			if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0
1677195534Sscottl			  || (inq_data->flags & SID_WBus32) != 0
1678195534Sscottl			  || cts->type == CTS_TYPE_USER_SETTINGS)
1679195534Sscottl			 && (cpi.hba_inquiry & PI_WIDE_32) != 0)
1680195534Sscottl				break;
1681195534Sscottl			/* Fall Through to 16-bit */
1682195534Sscottl		case MSG_EXT_WDTR_BUS_16_BIT:
1683195534Sscottl			if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0
1684195534Sscottl			  || (inq_data->flags & SID_WBus16) != 0
1685195534Sscottl			  || cts->type == CTS_TYPE_USER_SETTINGS)
1686195534Sscottl			 && (cpi.hba_inquiry & PI_WIDE_16) != 0) {
1687195534Sscottl				spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
1688195534Sscottl				break;
1689195534Sscottl			}
1690195534Sscottl			/* Fall Through to 8-bit */
1691195534Sscottl		default: /* New bus width?? */
1692195534Sscottl		case MSG_EXT_WDTR_BUS_8_BIT:
1693195534Sscottl			/* All targets can do this */
1694195534Sscottl			spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
1695195534Sscottl			break;
1696195534Sscottl		}
1697195534Sscottl
1698195534Sscottl		spi3caps = cpi.xport_specific.spi.ppr_options;
1699195534Sscottl		if ((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0
1700195534Sscottl		 && cts->type == CTS_TYPE_CURRENT_SETTINGS)
1701195534Sscottl			spi3caps &= inq_data->spi3data;
1702195534Sscottl
1703195534Sscottl		if ((spi3caps & SID_SPI_CLOCK_DT) == 0)
1704195534Sscottl			spi->ppr_options &= ~MSG_EXT_PPR_DT_REQ;
1705195534Sscottl
1706195534Sscottl		if ((spi3caps & SID_SPI_IUS) == 0)
1707195534Sscottl			spi->ppr_options &= ~MSG_EXT_PPR_IU_REQ;
1708195534Sscottl
1709195534Sscottl		if ((spi3caps & SID_SPI_QAS) == 0)
1710195534Sscottl			spi->ppr_options &= ~MSG_EXT_PPR_QAS_REQ;
1711195534Sscottl
1712195534Sscottl		/* No SPI Transfer settings are allowed unless we are wide */
1713195534Sscottl		if (spi->bus_width == 0)
1714195534Sscottl			spi->ppr_options = 0;
1715195534Sscottl
1716195534Sscottl		if ((spi->valid & CTS_SPI_VALID_DISC)
1717195534Sscottl		 && ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) == 0)) {
1718195534Sscottl			/*
1719195534Sscottl			 * Can't tag queue without disconnection.
1720195534Sscottl			 */
1721195534Sscottl			scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
1722195534Sscottl			scsi->valid |= CTS_SCSI_VALID_TQ;
1723195534Sscottl		}
1724195534Sscottl
1725195534Sscottl		/*
1726195534Sscottl		 * If we are currently performing tagged transactions to
1727195534Sscottl		 * this device and want to change its negotiation parameters,
1728195534Sscottl		 * go non-tagged for a bit to give the controller a chance to
1729195534Sscottl		 * negotiate unhampered by tag messages.
1730195534Sscottl		 */
1731195534Sscottl		if (cts->type == CTS_TYPE_CURRENT_SETTINGS
1732195534Sscottl		 && (device->inq_flags & SID_CmdQue) != 0
1733195534Sscottl		 && (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0
1734195534Sscottl		 && (spi->flags & (CTS_SPI_VALID_SYNC_RATE|
1735195534Sscottl				   CTS_SPI_VALID_SYNC_OFFSET|
1736195534Sscottl				   CTS_SPI_VALID_BUS_WIDTH)) != 0)
1737195534Sscottl			scsi_toggle_tags(cts->ccb_h.path);
1738195534Sscottl	}
1739195534Sscottl
1740195534Sscottl	if (cts->type == CTS_TYPE_CURRENT_SETTINGS
1741195534Sscottl	 && (scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
1742195534Sscottl		int device_tagenb;
1743195534Sscottl
1744195534Sscottl		/*
1745195534Sscottl		 * If we are transitioning from tags to no-tags or
1746195534Sscottl		 * vice-versa, we need to carefully freeze and restart
1747195534Sscottl		 * the queue so that we don't overlap tagged and non-tagged
1748195534Sscottl		 * commands.  We also temporarily stop tags if there is
1749195534Sscottl		 * a change in transfer negotiation settings to allow
1750195534Sscottl		 * "tag-less" negotiation.
1751195534Sscottl		 */
1752195534Sscottl		if ((device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0
1753195534Sscottl		 || (device->inq_flags & SID_CmdQue) != 0)
1754195534Sscottl			device_tagenb = TRUE;
1755195534Sscottl		else
1756195534Sscottl			device_tagenb = FALSE;
1757195534Sscottl
1758195534Sscottl		if (((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0
1759195534Sscottl		  && device_tagenb == FALSE)
1760195534Sscottl		 || ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) == 0
1761195534Sscottl		  && device_tagenb == TRUE)) {
1762195534Sscottl
1763195534Sscottl			if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) {
1764195534Sscottl				/*
1765195534Sscottl				 * Delay change to use tags until after a
1766195534Sscottl				 * few commands have gone to this device so
1767195534Sscottl				 * the controller has time to perform transfer
1768195534Sscottl				 * negotiations without tagged messages getting
1769195534Sscottl				 * in the way.
1770195534Sscottl				 */
1771195534Sscottl				device->tag_delay_count = CAM_TAG_DELAY_COUNT;
1772195534Sscottl				device->flags |= CAM_DEV_TAG_AFTER_COUNT;
1773195534Sscottl			} else {
1774195534Sscottl				struct ccb_relsim crs;
1775195534Sscottl
1776195534Sscottl				xpt_freeze_devq(cts->ccb_h.path, /*count*/1);
1777195534Sscottl		  		device->inq_flags &= ~SID_CmdQue;
1778195534Sscottl				xpt_dev_ccbq_resize(cts->ccb_h.path,
1779195534Sscottl						    sim->max_dev_openings);
1780195534Sscottl				device->flags &= ~CAM_DEV_TAG_AFTER_COUNT;
1781195534Sscottl				device->tag_delay_count = 0;
1782195534Sscottl
1783195534Sscottl				xpt_setup_ccb(&crs.ccb_h, cts->ccb_h.path,
1784195534Sscottl					      /*priority*/1);
1785195534Sscottl				crs.ccb_h.func_code = XPT_REL_SIMQ;
1786195534Sscottl				crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY;
1787195534Sscottl				crs.openings
1788195534Sscottl				    = crs.release_timeout
1789195534Sscottl				    = crs.qfrozen_cnt
1790195534Sscottl				    = 0;
1791195534Sscottl				xpt_action((union ccb *)&crs);
1792195534Sscottl			}
1793195534Sscottl		}
1794195534Sscottl	}
1795195534Sscottl	if (async_update == FALSE)
1796195534Sscottl		(*(sim->sim_action))(sim, (union ccb *)cts);
1797195534Sscottl}
1798195534Sscottl
1799195534Sscottlstatic void
1800195534Sscottlscsi_toggle_tags(struct cam_path *path)
1801195534Sscottl{
1802195534Sscottl	struct cam_ed *dev;
1803195534Sscottl
1804195534Sscottl	/*
1805195534Sscottl	 * Give controllers a chance to renegotiate
1806195534Sscottl	 * before starting tag operations.  We
1807195534Sscottl	 * "toggle" tagged queuing off then on
1808195534Sscottl	 * which causes the tag enable command delay
1809195534Sscottl	 * counter to come into effect.
1810195534Sscottl	 */
1811195534Sscottl	dev = path->device;
1812195534Sscottl	if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0
1813195534Sscottl	 || ((dev->inq_flags & SID_CmdQue) != 0
1814195534Sscottl 	  && (dev->inq_flags & (SID_Sync|SID_WBus16|SID_WBus32)) != 0)) {
1815195534Sscottl		struct ccb_trans_settings cts;
1816195534Sscottl
1817195534Sscottl		xpt_setup_ccb(&cts.ccb_h, path, 1);
1818195534Sscottl		cts.protocol = PROTO_SCSI;
1819195534Sscottl		cts.protocol_version = PROTO_VERSION_UNSPECIFIED;
1820195534Sscottl		cts.transport = XPORT_UNSPECIFIED;
1821195534Sscottl		cts.transport_version = XPORT_VERSION_UNSPECIFIED;
1822195534Sscottl		cts.proto_specific.scsi.flags = 0;
1823195534Sscottl		cts.proto_specific.scsi.valid = CTS_SCSI_VALID_TQ;
1824195534Sscottl		scsi_set_transfer_settings(&cts, path->device,
1825195534Sscottl					  /*async_update*/TRUE);
1826195534Sscottl		cts.proto_specific.scsi.flags = CTS_SCSI_FLAGS_TAG_ENB;
1827195534Sscottl		scsi_set_transfer_settings(&cts, path->device,
1828195534Sscottl					  /*async_update*/TRUE);
1829195534Sscottl	}
1830195534Sscottl}
1831195534Sscottl
1832195534Sscottl/*
1833195534Sscottl * Handle any per-device event notifications that require action by the XPT.
1834195534Sscottl */
1835195534Sscottlstatic void
1836195534Sscottlata_dev_async(u_int32_t async_code, struct cam_eb *bus, struct cam_et *target,
1837195534Sscottl	      struct cam_ed *device, void *async_arg)
1838195534Sscottl{
1839195534Sscottl	cam_status status;
1840195534Sscottl	struct cam_path newpath;
1841195534Sscottl
1842195534Sscottl	/*
1843195534Sscottl	 * We only need to handle events for real devices.
1844195534Sscottl	 */
1845195534Sscottl	if (target->target_id == CAM_TARGET_WILDCARD
1846195534Sscottl	 || device->lun_id == CAM_LUN_WILDCARD)
1847195534Sscottl		return;
1848195534Sscottl
1849195534Sscottl	/*
1850195534Sscottl	 * We need our own path with wildcards expanded to
1851195534Sscottl	 * handle certain types of events.
1852195534Sscottl	 */
1853195534Sscottl	if ((async_code == AC_SENT_BDR)
1854195534Sscottl	 || (async_code == AC_BUS_RESET)
1855195534Sscottl	 || (async_code == AC_INQ_CHANGED))
1856195534Sscottl		status = xpt_compile_path(&newpath, NULL,
1857195534Sscottl					  bus->path_id,
1858195534Sscottl					  target->target_id,
1859195534Sscottl					  device->lun_id);
1860195534Sscottl	else
1861195534Sscottl		status = CAM_REQ_CMP_ERR;
1862195534Sscottl
1863195534Sscottl	if (status == CAM_REQ_CMP) {
1864195534Sscottl
1865195534Sscottl		/*
1866195534Sscottl		 * Allow transfer negotiation to occur in a
1867195534Sscottl		 * tag free environment.
1868195534Sscottl		 */
1869195534Sscottl		if (async_code == AC_SENT_BDR
1870195534Sscottl		 || async_code == AC_BUS_RESET)
1871195534Sscottl			scsi_toggle_tags(&newpath);
1872195534Sscottl
1873195534Sscottl		if (async_code == AC_INQ_CHANGED) {
1874195534Sscottl			/*
1875195534Sscottl			 * We've sent a start unit command, or
1876195534Sscottl			 * something similar to a device that
1877195534Sscottl			 * may have caused its inquiry data to
1878195534Sscottl			 * change. So we re-scan the device to
1879195534Sscottl			 * refresh the inquiry data for it.
1880195534Sscottl			 */
1881195534Sscottl			ata_scan_lun(newpath.periph, &newpath,
1882195534Sscottl				     CAM_EXPECT_INQ_CHANGE, NULL);
1883195534Sscottl		}
1884195534Sscottl		xpt_release_path(&newpath);
1885195534Sscottl	} else if (async_code == AC_LOST_DEVICE) {
1886195534Sscottl		device->flags |= CAM_DEV_UNCONFIGURED;
1887195534Sscottl	} else if (async_code == AC_TRANSFER_NEG) {
1888195534Sscottl		struct ccb_trans_settings *settings;
1889195534Sscottl
1890195534Sscottl		settings = (struct ccb_trans_settings *)async_arg;
1891195534Sscottl		scsi_set_transfer_settings(settings, device,
1892195534Sscottl					  /*async_update*/TRUE);
1893195534Sscottl	}
1894195534Sscottl}
1895195534Sscottl
1896