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