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