xref: /freebsd/sys/cam/ata/ata_pmp.c (revision 2ffd30f7ee15c87ee092cbac6a4438bcb3af923c)
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 
63 typedef 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 
78 typedef enum {
79 	PMP_FLAG_SCTX_INIT	= 0x200
80 } pmp_flags;
81 
82 typedef 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 
90 struct 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 
112 static	periph_init_t	pmpinit;
113 static	void		pmpasync(void *callback_arg, uint32_t code,
114 				struct cam_path *path, void *arg);
115 static	void		pmpsysctlinit(void *context, int pending);
116 static	periph_ctor_t	pmpregister;
117 static	periph_dtor_t	pmpcleanup;
118 static	periph_start_t	pmpstart;
119 static	periph_oninv_t	pmponinvalidate;
120 static	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 
135 static int pmp_retry_count = PMP_DEFAULT_RETRY;
136 static int pmp_default_timeout = PMP_DEFAULT_TIMEOUT;
137 static int pmp_hide_special = PMP_DEFAULT_HIDE_SPECIAL;
138 
139 static SYSCTL_NODE(_kern_cam, OID_AUTO, pmp, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
140     "CAM Direct Access Disk driver");
141 SYSCTL_INT(_kern_cam_pmp, OID_AUTO, retry_count, CTLFLAG_RWTUN,
142            &pmp_retry_count, 0, "Normal I/O retry count");
143 SYSCTL_INT(_kern_cam_pmp, OID_AUTO, default_timeout, CTLFLAG_RWTUN,
144            &pmp_default_timeout, 0, "Normal I/O timeout (in seconds)");
145 SYSCTL_INT(_kern_cam_pmp, OID_AUTO, hide_special, CTLFLAG_RWTUN,
146            &pmp_hide_special, 0, "Hide extra ports");
147 
148 static struct periph_driver pmpdriver =
149 {
150 	pmpinit, "pmp",
151 	TAILQ_HEAD_INITIALIZER(pmpdriver.units), /* generation */ 0,
152 	CAM_PERIPH_DRV_EARLY
153 };
154 
155 PERIPHDRIVER_DECLARE(pmp, pmpdriver);
156 
157 static void
pmpinit(void)158 pmpinit(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 
174 static void
pmpfreeze(struct cam_periph * periph,int mask)175 pmpfreeze(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 
196 static void
pmprelease(struct cam_periph * periph,int mask)197 pmprelease(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 
218 static void
pmponinvalidate(struct cam_periph * periph)219 pmponinvalidate(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 
240 static void
pmpcleanup(struct cam_periph * periph)241 pmpcleanup(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 
261 static void
pmpasync(void * callback_arg,uint32_t code,struct cam_path * path,void * arg)262 pmpasync(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 
335 static void
pmpsysctlinit(void * context,int pending)336 pmpsysctlinit(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 
364 static cam_status
pmpregister(struct cam_periph * periph,void * arg)365 pmpregister(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 
417 static void
pmpstart(struct cam_periph * periph,union ccb * start_ccb)418 pmpstart(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 
579 static void
pmpdone(struct cam_periph * periph,union ccb * done_ccb)580 pmpdone(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 	}
851 done:
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