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