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