ata_pmp.c revision 241937
1/*-
2 * Copyright (c) 2009 Alexander Motin <mav@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer,
10 *    without modification, immediately at the beginning of the file.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: stable/9/sys/cam/ata/ata_pmp.c 241937 2012-10-23 15:16:50Z mav $");
29
30#include <sys/param.h>
31
32#ifdef _KERNEL
33#include <sys/systm.h>
34#include <sys/kernel.h>
35#include <sys/bio.h>
36#include <sys/sysctl.h>
37#include <sys/taskqueue.h>
38#include <sys/lock.h>
39#include <sys/mutex.h>
40#include <sys/conf.h>
41#include <sys/devicestat.h>
42#include <sys/eventhandler.h>
43#include <sys/malloc.h>
44#include <sys/cons.h>
45#include <geom/geom_disk.h>
46#endif /* _KERNEL */
47
48#ifndef _KERNEL
49#include <stdio.h>
50#include <string.h>
51#endif /* _KERNEL */
52
53#include <cam/cam.h>
54#include <cam/cam_ccb.h>
55#include <cam/cam_periph.h>
56#include <cam/cam_xpt_periph.h>
57#include <cam/cam_xpt_internal.h>
58#include <cam/cam_sim.h>
59
60#include <cam/ata/ata_all.h>
61
62#ifdef _KERNEL
63
64typedef enum {
65	PMP_STATE_NORMAL,
66	PMP_STATE_PORTS,
67	PMP_STATE_PRECONFIG,
68	PMP_STATE_RESET,
69	PMP_STATE_CONNECT,
70	PMP_STATE_CHECK,
71	PMP_STATE_CLEAR,
72	PMP_STATE_CONFIG,
73	PMP_STATE_SCAN
74} pmp_state;
75
76typedef enum {
77	PMP_FLAG_SCTX_INIT	= 0x200
78} pmp_flags;
79
80typedef enum {
81	PMP_CCB_PROBE		= 0x01,
82} pmp_ccb_state;
83
84/* Offsets into our private area for storing information */
85#define ccb_state	ppriv_field0
86#define ccb_bp		ppriv_ptr1
87
88struct pmp_softc {
89	SLIST_ENTRY(pmp_softc)	links;
90	pmp_state		state;
91	pmp_flags		flags;
92	uint32_t		pm_pid;
93	uint32_t		pm_prv;
94	int			pm_ports;
95	int			pm_step;
96	int			pm_try;
97	int			found;
98	int			reset;
99	int			frozen;
100	int			restart;
101	int			events;
102#define PMP_EV_RESET	1
103#define PMP_EV_RESCAN	2
104	u_int			caps;
105	struct task		sysctl_task;
106	struct sysctl_ctx_list	sysctl_ctx;
107	struct sysctl_oid	*sysctl_tree;
108};
109
110static	periph_init_t	pmpinit;
111static	void		pmpasync(void *callback_arg, u_int32_t code,
112				struct cam_path *path, void *arg);
113static	void		pmpsysctlinit(void *context, int pending);
114static	periph_ctor_t	pmpregister;
115static	periph_dtor_t	pmpcleanup;
116static	periph_start_t	pmpstart;
117static	periph_oninv_t	pmponinvalidate;
118static	void		pmpdone(struct cam_periph *periph,
119			       union ccb *done_ccb);
120
121#ifndef PMP_DEFAULT_TIMEOUT
122#define PMP_DEFAULT_TIMEOUT 30	/* Timeout in seconds */
123#endif
124
125#ifndef	PMP_DEFAULT_RETRY
126#define	PMP_DEFAULT_RETRY	1
127#endif
128
129#ifndef	PMP_DEFAULT_HIDE_SPECIAL
130#define	PMP_DEFAULT_HIDE_SPECIAL	1
131#endif
132
133static int pmp_retry_count = PMP_DEFAULT_RETRY;
134static int pmp_default_timeout = PMP_DEFAULT_TIMEOUT;
135static int pmp_hide_special = PMP_DEFAULT_HIDE_SPECIAL;
136
137SYSCTL_NODE(_kern_cam, OID_AUTO, pmp, CTLFLAG_RD, 0,
138            "CAM Direct Access Disk driver");
139SYSCTL_INT(_kern_cam_pmp, OID_AUTO, retry_count, CTLFLAG_RW,
140           &pmp_retry_count, 0, "Normal I/O retry count");
141TUNABLE_INT("kern.cam.pmp.retry_count", &pmp_retry_count);
142SYSCTL_INT(_kern_cam_pmp, OID_AUTO, default_timeout, CTLFLAG_RW,
143           &pmp_default_timeout, 0, "Normal I/O timeout (in seconds)");
144TUNABLE_INT("kern.cam.pmp.default_timeout", &pmp_default_timeout);
145SYSCTL_INT(_kern_cam_pmp, OID_AUTO, hide_special, CTLFLAG_RW,
146           &pmp_hide_special, 0, "Hide extra ports");
147TUNABLE_INT("kern.cam.pmp.hide_special", &pmp_hide_special);
148
149static struct periph_driver pmpdriver =
150{
151	pmpinit, "pmp",
152	TAILQ_HEAD_INITIALIZER(pmpdriver.units), /* generation */ 0,
153	CAM_PERIPH_DRV_EARLY
154};
155
156PERIPHDRIVER_DECLARE(pmp, pmpdriver);
157
158MALLOC_DEFINE(M_ATPMP, "ata_pmp", "ata_pmp buffers");
159
160static void
161pmpinit(void)
162{
163	cam_status status;
164
165	/*
166	 * Install a global async callback.  This callback will
167	 * receive async callbacks like "new device found".
168	 */
169	status = xpt_register_async(AC_FOUND_DEVICE, pmpasync, NULL, NULL);
170
171	if (status != CAM_REQ_CMP) {
172		printf("pmp: Failed to attach master async callback "
173		       "due to status 0x%x!\n", status);
174	}
175}
176
177static void
178pmpfreeze(struct cam_periph *periph, int mask)
179{
180	struct pmp_softc *softc = (struct pmp_softc *)periph->softc;
181	struct cam_path *dpath;
182	int i;
183
184	mask &= ~softc->frozen;
185	for (i = 0; i < 15; i++) {
186		if ((mask & (1 << i)) == 0)
187			continue;
188		if (xpt_create_path(&dpath, periph,
189		    xpt_path_path_id(periph->path),
190		    i, 0) == CAM_REQ_CMP) {
191			softc->frozen |= (1 << i);
192			xpt_acquire_device(dpath->device);
193			cam_freeze_devq_arg(dpath,
194			    RELSIM_RELEASE_RUNLEVEL, CAM_RL_BUS + 1);
195			xpt_free_path(dpath);
196		}
197	}
198}
199
200static void
201pmprelease(struct cam_periph *periph, int mask)
202{
203	struct pmp_softc *softc = (struct pmp_softc *)periph->softc;
204	struct cam_path *dpath;
205	int i;
206
207	mask &= softc->frozen;
208	for (i = 0; i < 15; i++) {
209		if ((mask & (1 << i)) == 0)
210			continue;
211		if (xpt_create_path(&dpath, periph,
212		    xpt_path_path_id(periph->path),
213		    i, 0) == CAM_REQ_CMP) {
214			softc->frozen &= ~(1 << i);
215			cam_release_devq(dpath,
216			    RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_BUS + 1, FALSE);
217			xpt_release_device(dpath->device);
218			xpt_free_path(dpath);
219		}
220	}
221}
222
223static void
224pmponinvalidate(struct cam_periph *periph)
225{
226	struct cam_path *dpath;
227	int i;
228
229	/*
230	 * De-register any async callbacks.
231	 */
232	xpt_register_async(0, pmpasync, periph, periph->path);
233
234	for (i = 0; i < 15; i++) {
235		if (xpt_create_path(&dpath, periph,
236		    xpt_path_path_id(periph->path),
237		    i, 0) == CAM_REQ_CMP) {
238			xpt_async(AC_LOST_DEVICE, dpath, NULL);
239			xpt_free_path(dpath);
240		}
241	}
242	pmprelease(periph, -1);
243	xpt_print(periph->path, "lost device\n");
244}
245
246static void
247pmpcleanup(struct cam_periph *periph)
248{
249	struct pmp_softc *softc;
250
251	softc = (struct pmp_softc *)periph->softc;
252
253	xpt_print(periph->path, "removing device entry\n");
254	cam_periph_unlock(periph);
255
256	/*
257	 * If we can't free the sysctl tree, oh well...
258	 */
259	if ((softc->flags & PMP_FLAG_SCTX_INIT) != 0
260	    && sysctl_ctx_free(&softc->sysctl_ctx) != 0) {
261		xpt_print(periph->path, "can't remove sysctl context\n");
262	}
263
264	free(softc, M_DEVBUF);
265	cam_periph_lock(periph);
266}
267
268static void
269pmpasync(void *callback_arg, u_int32_t code,
270	struct cam_path *path, void *arg)
271{
272	struct cam_periph *periph;
273	struct pmp_softc *softc;
274
275	periph = (struct cam_periph *)callback_arg;
276	switch (code) {
277	case AC_FOUND_DEVICE:
278	{
279		struct ccb_getdev *cgd;
280		cam_status status;
281
282		cgd = (struct ccb_getdev *)arg;
283		if (cgd == NULL)
284			break;
285
286		if (cgd->protocol != PROTO_SATAPM)
287			break;
288
289		/*
290		 * Allocate a peripheral instance for
291		 * this device and start the probe
292		 * process.
293		 */
294		status = cam_periph_alloc(pmpregister, pmponinvalidate,
295					  pmpcleanup, pmpstart,
296					  "pmp", CAM_PERIPH_BIO,
297					  cgd->ccb_h.path, pmpasync,
298					  AC_FOUND_DEVICE, cgd);
299
300		if (status != CAM_REQ_CMP
301		 && status != CAM_REQ_INPROG)
302			printf("pmpasync: Unable to attach to new device "
303				"due to status 0x%x\n", status);
304		break;
305	}
306	case AC_SCSI_AEN:
307	case AC_SENT_BDR:
308	case AC_BUS_RESET:
309		softc = (struct pmp_softc *)periph->softc;
310		cam_periph_async(periph, code, path, arg);
311		if (code == AC_SCSI_AEN)
312			softc->events |= PMP_EV_RESCAN;
313		else
314			softc->events |= PMP_EV_RESET;
315		if (code == AC_SCSI_AEN && softc->state != PMP_STATE_NORMAL)
316			break;
317		xpt_hold_boot();
318		pmpfreeze(periph, softc->found);
319		if (code == AC_SENT_BDR || code == AC_BUS_RESET)
320			softc->found = 0; /* We have to reset everything. */
321		if (softc->state == PMP_STATE_NORMAL) {
322			softc->state = PMP_STATE_PRECONFIG;
323			cam_periph_acquire(periph);
324			xpt_schedule(periph, CAM_PRIORITY_DEV);
325		} else
326			softc->restart = 1;
327		break;
328	default:
329		cam_periph_async(periph, code, path, arg);
330		break;
331	}
332}
333
334static void
335pmpsysctlinit(void *context, int pending)
336{
337	struct cam_periph *periph;
338	struct pmp_softc *softc;
339	char tmpstr[80], tmpstr2[80];
340
341	periph = (struct cam_periph *)context;
342	if (cam_periph_acquire(periph) != CAM_REQ_CMP)
343		return;
344
345	softc = (struct pmp_softc *)periph->softc;
346	snprintf(tmpstr, sizeof(tmpstr), "CAM PMP unit %d", periph->unit_number);
347	snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number);
348
349	sysctl_ctx_init(&softc->sysctl_ctx);
350	softc->flags |= PMP_FLAG_SCTX_INIT;
351	softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx,
352		SYSCTL_STATIC_CHILDREN(_kern_cam_pmp), OID_AUTO, tmpstr2,
353		CTLFLAG_RD, 0, tmpstr);
354	if (softc->sysctl_tree == NULL) {
355		printf("pmpsysctlinit: unable to allocate sysctl tree\n");
356		cam_periph_release(periph);
357		return;
358	}
359
360	cam_periph_release(periph);
361}
362
363static cam_status
364pmpregister(struct cam_periph *periph, void *arg)
365{
366	struct pmp_softc *softc;
367	struct ccb_getdev *cgd;
368
369	cgd = (struct ccb_getdev *)arg;
370	if (cgd == NULL) {
371		printf("pmpregister: no getdev CCB, can't register device\n");
372		return(CAM_REQ_CMP_ERR);
373	}
374
375	softc = (struct pmp_softc *)malloc(sizeof(*softc), M_DEVBUF,
376	    M_NOWAIT|M_ZERO);
377
378	if (softc == NULL) {
379		printf("pmpregister: Unable to probe new device. "
380		       "Unable to allocate softc\n");
381		return(CAM_REQ_CMP_ERR);
382	}
383	periph->softc = softc;
384
385	softc->pm_pid = ((uint32_t *)&cgd->ident_data)[0];
386	softc->pm_prv = ((uint32_t *)&cgd->ident_data)[1];
387	TASK_INIT(&softc->sysctl_task, 0, pmpsysctlinit, periph);
388
389	xpt_announce_periph(periph, NULL);
390
391	/*
392	 * Add async callbacks for bus reset and
393	 * bus device reset calls.  I don't bother
394	 * checking if this fails as, in most cases,
395	 * the system will function just fine without
396	 * them and the only alternative would be to
397	 * not attach the device on failure.
398	 */
399	xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE |
400		AC_SCSI_AEN, pmpasync, periph, periph->path);
401
402	/*
403	 * Take an exclusive refcount on the periph while pmpstart is called
404	 * to finish the probe.  The reference will be dropped in pmpdone at
405	 * the end of probe.
406	 */
407	(void)cam_periph_acquire(periph);
408	xpt_hold_boot();
409	softc->state = PMP_STATE_PORTS;
410	softc->events = PMP_EV_RESCAN;
411	xpt_schedule(periph, CAM_PRIORITY_DEV);
412
413	return(CAM_REQ_CMP);
414}
415
416static void
417pmpstart(struct cam_periph *periph, union ccb *start_ccb)
418{
419	struct ccb_trans_settings cts;
420	struct ccb_ataio *ataio;
421	struct pmp_softc *softc;
422	struct cam_path *dpath;
423	int revision = 0;
424
425	softc = (struct pmp_softc *)periph->softc;
426	ataio = &start_ccb->ataio;
427
428	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("pmpstart\n"));
429
430	if (softc->restart) {
431		softc->restart = 0;
432		softc->state = min(softc->state, PMP_STATE_PRECONFIG);
433	}
434	/* Fetch user wanted device speed. */
435	if (softc->state == PMP_STATE_RESET ||
436	    softc->state == PMP_STATE_CONNECT) {
437		if (xpt_create_path(&dpath, periph,
438		    xpt_path_path_id(periph->path),
439		    softc->pm_step, 0) == CAM_REQ_CMP) {
440			bzero(&cts, sizeof(cts));
441			xpt_setup_ccb(&cts.ccb_h, dpath, CAM_PRIORITY_NONE);
442			cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
443			cts.type = CTS_TYPE_USER_SETTINGS;
444			xpt_action((union ccb *)&cts);
445			if (cts.xport_specific.sata.valid & CTS_SATA_VALID_REVISION)
446				revision = cts.xport_specific.sata.revision;
447			xpt_free_path(dpath);
448		}
449	}
450	switch (softc->state) {
451	case PMP_STATE_PORTS:
452		cam_fill_ataio(ataio,
453		      pmp_retry_count,
454		      pmpdone,
455		      /*flags*/CAM_DIR_NONE,
456		      0,
457		      /*data_ptr*/NULL,
458		      /*dxfer_len*/0,
459		      pmp_default_timeout * 1000);
460		ata_pm_read_cmd(ataio, 2, 15);
461		break;
462	case PMP_STATE_PRECONFIG:
463		/* Get/update host SATA capabilities. */
464		bzero(&cts, sizeof(cts));
465		xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NONE);
466		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
467		cts.type = CTS_TYPE_CURRENT_SETTINGS;
468		xpt_action((union ccb *)&cts);
469		if (cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS)
470			softc->caps = cts.xport_specific.sata.caps;
471		cam_fill_ataio(ataio,
472		      pmp_retry_count,
473		      pmpdone,
474		      /*flags*/CAM_DIR_NONE,
475		      0,
476		      /*data_ptr*/NULL,
477		      /*dxfer_len*/0,
478		      pmp_default_timeout * 1000);
479		ata_pm_write_cmd(ataio, 0x60, 15, 0x0);
480		break;
481	case PMP_STATE_RESET:
482		cam_fill_ataio(ataio,
483		      pmp_retry_count,
484		      pmpdone,
485		      /*flags*/CAM_DIR_NONE,
486		      0,
487		      /*data_ptr*/NULL,
488		      /*dxfer_len*/0,
489		      pmp_default_timeout * 1000);
490		ata_pm_write_cmd(ataio, 2, softc->pm_step,
491		    (revision << 4) |
492		    ((softc->found & (1 << softc->pm_step)) ? 0 : 1));
493		break;
494	case PMP_STATE_CONNECT:
495		cam_fill_ataio(ataio,
496		      pmp_retry_count,
497		      pmpdone,
498		      /*flags*/CAM_DIR_NONE,
499		      0,
500		      /*data_ptr*/NULL,
501		      /*dxfer_len*/0,
502		      pmp_default_timeout * 1000);
503		ata_pm_write_cmd(ataio, 2, softc->pm_step,
504		    (revision << 4));
505		break;
506	case PMP_STATE_CHECK:
507		cam_fill_ataio(ataio,
508		      pmp_retry_count,
509		      pmpdone,
510		      /*flags*/CAM_DIR_NONE,
511		      0,
512		      /*data_ptr*/NULL,
513		      /*dxfer_len*/0,
514		      pmp_default_timeout * 1000);
515		ata_pm_read_cmd(ataio, 0, softc->pm_step);
516		break;
517	case PMP_STATE_CLEAR:
518		softc->reset = 0;
519		cam_fill_ataio(ataio,
520		      pmp_retry_count,
521		      pmpdone,
522		      /*flags*/CAM_DIR_NONE,
523		      0,
524		      /*data_ptr*/NULL,
525		      /*dxfer_len*/0,
526		      pmp_default_timeout * 1000);
527		ata_pm_write_cmd(ataio, 1, softc->pm_step, 0xFFFFFFFF);
528		break;
529	case PMP_STATE_CONFIG:
530		cam_fill_ataio(ataio,
531		      pmp_retry_count,
532		      pmpdone,
533		      /*flags*/CAM_DIR_NONE,
534		      0,
535		      /*data_ptr*/NULL,
536		      /*dxfer_len*/0,
537		      pmp_default_timeout * 1000);
538		ata_pm_write_cmd(ataio, 0x60, 15, 0x07 |
539		    ((softc->caps & CTS_SATA_CAPS_H_AN) ? 0x08 : 0));
540		break;
541	default:
542		break;
543	}
544	xpt_action(start_ccb);
545}
546
547static void
548pmpdone(struct cam_periph *periph, union ccb *done_ccb)
549{
550	struct ccb_trans_settings cts;
551	struct pmp_softc *softc;
552	struct ccb_ataio *ataio;
553	struct cam_path *dpath;
554	u_int32_t  priority, res;
555	int i;
556
557	softc = (struct pmp_softc *)periph->softc;
558	ataio = &done_ccb->ataio;
559
560	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("pmpdone\n"));
561
562	priority = done_ccb->ccb_h.pinfo.priority;
563
564	if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
565		if (cam_periph_error(done_ccb, 0, 0, NULL) == ERESTART) {
566			return;
567		} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
568			cam_release_devq(done_ccb->ccb_h.path,
569			    /*relsim_flags*/0,
570			    /*reduction*/0,
571			    /*timeout*/0,
572			    /*getcount_only*/0);
573		}
574		goto done;
575	}
576
577	if (softc->restart) {
578		softc->restart = 0;
579		xpt_release_ccb(done_ccb);
580		softc->state = min(softc->state, PMP_STATE_PRECONFIG);
581		xpt_schedule(periph, priority);
582		return;
583	}
584
585	switch (softc->state) {
586	case PMP_STATE_PORTS:
587		softc->pm_ports = (ataio->res.lba_high << 24) +
588		    (ataio->res.lba_mid << 16) +
589		    (ataio->res.lba_low << 8) +
590		    ataio->res.sector_count;
591		if (pmp_hide_special) {
592			/*
593			 * This PMP declares 6 ports, while only 5 of them
594			 * are real. Port 5 is a SEMB port, probing which
595			 * causes timeouts if external SEP is not connected
596			 * to PMP over I2C.
597			 */
598			if (softc->pm_pid == 0x37261095 && softc->pm_ports == 6)
599				softc->pm_ports = 5;
600
601			/*
602			 * This PMP declares 7 ports, while only 5 of them
603			 * are real. Port 5 is a fake "Config  Disk" with
604			 * 640 sectors size. Port 6 is a SEMB port.
605			 */
606			if (softc->pm_pid == 0x47261095 && softc->pm_ports == 7)
607				softc->pm_ports = 5;
608
609			/*
610			 * These PMPs have extra configuration port.
611			 */
612			if (softc->pm_pid == 0x57231095 ||
613			    softc->pm_pid == 0x57331095 ||
614			    softc->pm_pid == 0x57341095 ||
615			    softc->pm_pid == 0x57441095)
616				softc->pm_ports--;
617		}
618		printf("%s%d: %d fan-out ports\n",
619		    periph->periph_name, periph->unit_number,
620		    softc->pm_ports);
621		softc->state = PMP_STATE_PRECONFIG;
622		xpt_release_ccb(done_ccb);
623		xpt_schedule(periph, priority);
624		return;
625	case PMP_STATE_PRECONFIG:
626		softc->pm_step = 0;
627		softc->state = PMP_STATE_RESET;
628		softc->reset |= ~softc->found;
629		xpt_release_ccb(done_ccb);
630		xpt_schedule(periph, priority);
631		return;
632	case PMP_STATE_RESET:
633		softc->pm_step++;
634		if (softc->pm_step >= softc->pm_ports) {
635			softc->pm_step = 0;
636			cam_freeze_devq(periph->path);
637			cam_release_devq(periph->path,
638			    RELSIM_RELEASE_AFTER_TIMEOUT,
639			    /*reduction*/0,
640			    /*timeout*/5,
641			    /*getcount_only*/0);
642			softc->state = PMP_STATE_CONNECT;
643		}
644		xpt_release_ccb(done_ccb);
645		xpt_schedule(periph, priority);
646		return;
647	case PMP_STATE_CONNECT:
648		softc->pm_step++;
649		if (softc->pm_step >= softc->pm_ports) {
650			softc->pm_step = 0;
651			softc->pm_try = 0;
652			cam_freeze_devq(periph->path);
653			cam_release_devq(periph->path,
654			    RELSIM_RELEASE_AFTER_TIMEOUT,
655			    /*reduction*/0,
656			    /*timeout*/10,
657			    /*getcount_only*/0);
658			softc->state = PMP_STATE_CHECK;
659		}
660		xpt_release_ccb(done_ccb);
661		xpt_schedule(periph, priority);
662		return;
663	case PMP_STATE_CHECK:
664		res = (ataio->res.lba_high << 24) +
665		    (ataio->res.lba_mid << 16) +
666		    (ataio->res.lba_low << 8) +
667		    ataio->res.sector_count;
668		if (((res & 0xf0f) == 0x103 && (res & 0x0f0) != 0) ||
669		    (res & 0x600) != 0) {
670			if (bootverbose) {
671				printf("%s%d: port %d status: %08x\n",
672				    periph->periph_name, periph->unit_number,
673				    softc->pm_step, res);
674			}
675			/* Report device speed if it is online. */
676			if ((res & 0xf0f) == 0x103 &&
677			    xpt_create_path(&dpath, periph,
678			    xpt_path_path_id(periph->path),
679			    softc->pm_step, 0) == CAM_REQ_CMP) {
680				bzero(&cts, sizeof(cts));
681				xpt_setup_ccb(&cts.ccb_h, dpath, CAM_PRIORITY_NONE);
682				cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
683				cts.type = CTS_TYPE_CURRENT_SETTINGS;
684				cts.xport_specific.sata.revision = (res & 0x0f0) >> 4;
685				cts.xport_specific.sata.valid = CTS_SATA_VALID_REVISION;
686				cts.xport_specific.sata.caps = softc->caps &
687				    (CTS_SATA_CAPS_H_PMREQ |
688				     CTS_SATA_CAPS_H_DMAAA |
689				     CTS_SATA_CAPS_H_AN);
690				cts.xport_specific.sata.valid |= CTS_SATA_VALID_CAPS;
691				xpt_action((union ccb *)&cts);
692				xpt_free_path(dpath);
693			}
694			softc->found |= (1 << softc->pm_step);
695			softc->pm_step++;
696		} else {
697			if (softc->pm_try < 10) {
698				cam_freeze_devq(periph->path);
699				cam_release_devq(periph->path,
700				    RELSIM_RELEASE_AFTER_TIMEOUT,
701				    /*reduction*/0,
702				    /*timeout*/10,
703				    /*getcount_only*/0);
704				softc->pm_try++;
705			} else {
706				if (bootverbose) {
707					printf("%s%d: port %d status: %08x\n",
708					    periph->periph_name, periph->unit_number,
709					    softc->pm_step, res);
710				}
711				softc->found &= ~(1 << softc->pm_step);
712				if (xpt_create_path(&dpath, periph,
713				    done_ccb->ccb_h.path_id,
714				    softc->pm_step, 0) == CAM_REQ_CMP) {
715					xpt_async(AC_LOST_DEVICE, dpath, NULL);
716					xpt_free_path(dpath);
717				}
718				softc->pm_step++;
719			}
720		}
721		if (softc->pm_step >= softc->pm_ports) {
722			if (softc->reset & softc->found) {
723				cam_freeze_devq(periph->path);
724				cam_release_devq(periph->path,
725				    RELSIM_RELEASE_AFTER_TIMEOUT,
726				    /*reduction*/0,
727				    /*timeout*/1000,
728				    /*getcount_only*/0);
729			}
730			softc->state = PMP_STATE_CLEAR;
731			softc->pm_step = 0;
732		}
733		xpt_release_ccb(done_ccb);
734		xpt_schedule(periph, priority);
735		return;
736	case PMP_STATE_CLEAR:
737		softc->pm_step++;
738		if (softc->pm_step >= softc->pm_ports) {
739			softc->state = PMP_STATE_CONFIG;
740			softc->pm_step = 0;
741		}
742		xpt_release_ccb(done_ccb);
743		xpt_schedule(periph, priority);
744		return;
745	case PMP_STATE_CONFIG:
746		for (i = 0; i < softc->pm_ports; i++) {
747			union ccb *ccb;
748
749			if ((softc->found & (1 << i)) == 0)
750				continue;
751			if (xpt_create_path(&dpath, periph,
752			    xpt_path_path_id(periph->path),
753			    i, 0) != CAM_REQ_CMP) {
754				printf("pmpdone: xpt_create_path failed\n");
755				continue;
756			}
757			/* If we did hard reset to this device, inform XPT. */
758			if ((softc->reset & softc->found & (1 << i)) != 0)
759				xpt_async(AC_SENT_BDR, dpath, NULL);
760			/* If rescan requested, scan this device. */
761			if (softc->events & PMP_EV_RESCAN) {
762				ccb = xpt_alloc_ccb_nowait();
763				if (ccb == NULL) {
764					xpt_free_path(dpath);
765					goto done;
766				}
767				xpt_setup_ccb(&ccb->ccb_h, dpath, CAM_PRIORITY_XPT);
768				xpt_rescan(ccb);
769			} else
770				xpt_free_path(dpath);
771		}
772		break;
773	default:
774		break;
775	}
776done:
777	xpt_release_ccb(done_ccb);
778	softc->state = PMP_STATE_NORMAL;
779	softc->events = 0;
780	xpt_release_boot();
781	pmprelease(periph, -1);
782	cam_periph_release_locked(periph);
783}
784
785#endif /* _KERNEL */
786