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