]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/cam/ata/ata_pmp.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / cam / ata / ata_pmp.c
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$");
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
64 typedef 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
79 typedef enum {
80         PMP_FLAG_SCTX_INIT      = 0x200
81 } pmp_flags;
82
83 typedef 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
91 struct 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
113 static  periph_init_t   pmpinit;
114 static  void            pmpasync(void *callback_arg, u_int32_t code,
115                                 struct cam_path *path, void *arg);
116 static  void            pmpsysctlinit(void *context, int pending);
117 static  periph_ctor_t   pmpregister;
118 static  periph_dtor_t   pmpcleanup;
119 static  periph_start_t  pmpstart;
120 static  periph_oninv_t  pmponinvalidate;
121 static  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
136 static int pmp_retry_count = PMP_DEFAULT_RETRY;
137 static int pmp_default_timeout = PMP_DEFAULT_TIMEOUT;
138 static int pmp_hide_special = PMP_DEFAULT_HIDE_SPECIAL;
139
140 static SYSCTL_NODE(_kern_cam, OID_AUTO, pmp, CTLFLAG_RD, 0,
141             "CAM Direct Access Disk driver");
142 SYSCTL_INT(_kern_cam_pmp, OID_AUTO, retry_count, CTLFLAG_RW,
143            &pmp_retry_count, 0, "Normal I/O retry count");
144 TUNABLE_INT("kern.cam.pmp.retry_count", &pmp_retry_count);
145 SYSCTL_INT(_kern_cam_pmp, OID_AUTO, default_timeout, CTLFLAG_RW,
146            &pmp_default_timeout, 0, "Normal I/O timeout (in seconds)");
147 TUNABLE_INT("kern.cam.pmp.default_timeout", &pmp_default_timeout);
148 SYSCTL_INT(_kern_cam_pmp, OID_AUTO, hide_special, CTLFLAG_RW,
149            &pmp_hide_special, 0, "Hide extra ports");
150 TUNABLE_INT("kern.cam.pmp.hide_special", &pmp_hide_special);
151
152 static struct periph_driver pmpdriver =
153 {
154         pmpinit, "pmp",
155         TAILQ_HEAD_INITIALIZER(pmpdriver.units), /* generation */ 0,
156         CAM_PERIPH_DRV_EARLY
157 };
158
159 PERIPHDRIVER_DECLARE(pmp, pmpdriver);
160
161 static MALLOC_DEFINE(M_ATPMP, "ata_pmp", "ata_pmp buffers");
162
163 static void
164 pmpinit(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
180 static void
181 pmpfreeze(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
202 static void
203 pmprelease(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
224 static void
225 pmponinvalidate(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
246 static void
247 pmpcleanup(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
267 static void
268 pmpasync(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
337 static void
338 pmpsysctlinit(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
366 static cam_status
367 pmpregister(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
419 static void
420 pmpstart(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
581 static void
582 pmpdone(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         }
853 done:
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 */