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