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