FreeBSD kernel CAM code
ata_pmp.c
Go to the documentation of this file.
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>
60#include <cam/cam_sim.h>
61
62#include <cam/ata/ata_all.h>
63
64#ifdef _KERNEL
65
66typedef enum {
80
81typedef enum {
82 PMP_FLAG_SCTX_INIT = 0x200
84
85typedef enum {
88
89/* Offsets into our private area for storing information */
90#define ccb_state ppriv_field0
91#define ccb_bp ppriv_ptr1
92
93struct 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
116static void pmpasync(void *callback_arg, u_int32_t code,
117 struct cam_path *path, void *arg);
118static void pmpsysctlinit(void *context, int pending);
123static 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
141
142static SYSCTL_NODE(_kern_cam, OID_AUTO, pmp, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
143 "CAM Direct Access Disk driver");
144SYSCTL_INT(_kern_cam_pmp, OID_AUTO, retry_count, CTLFLAG_RWTUN,
145 &pmp_retry_count, 0, "Normal I/O retry count");
146SYSCTL_INT(_kern_cam_pmp, OID_AUTO, default_timeout, CTLFLAG_RWTUN,
147 &pmp_default_timeout, 0, "Normal I/O timeout (in seconds)");
148SYSCTL_INT(_kern_cam_pmp, OID_AUTO, hide_special, CTLFLAG_RWTUN,
149 &pmp_hide_special, 0, "Hide extra ports");
150
152{
153 pmpinit, "pmp",
154 TAILQ_HEAD_INITIALIZER(pmpdriver.units), /* generation */ 0,
156};
157
159
160static void
161pmpinit(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
177static void
178pmpfreeze(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
199static void
200pmprelease(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
221static void
223{
224 struct cam_path *dpath;
225 int i;
226
227 /*
228 * De-register any async callbacks.
229 */
231
232 for (i = 0; i < 15; i++) {
233 if (xpt_create_path(&dpath, periph,
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
243static void
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
264static void
265pmpasync(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 */
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;
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;
325 } else {
326 pmprelease(periph, softc->found);
328 }
329 } else
330 softc->restart = 1;
331 break;
332 default:
333 cam_periph_async(periph, code, path, arg);
334 break;
335 }
336}
337
338static void
339pmpsysctlinit(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
367static cam_status
368pmpregister(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 */
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);
413 softc->state = PMP_STATE_PORTS;
414 softc->events = PMP_EV_RESCAN;
416
417 return(CAM_REQ_CMP);
418}
419
420static void
421pmpstart(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;
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,
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
472 cam_fill_ataio(ataio,
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
484 cam_fill_ataio(ataio,
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
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;
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,
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,
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;
530 cam_fill_ataio(ataio,
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,
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,
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,
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
582static void
583pmpdone(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
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
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
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
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,
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;
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,
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;
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 &
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,
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,
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) {
841 if (ccb == NULL) {
842 xpt_free_path(dpath);
843 goto done;
844 }
847 } else
848 xpt_free_path(dpath);
849 }
850 break;
851 default:
852 break;
853 }
854done:
855 xpt_release_ccb(done_ccb);
856 softc->state = PMP_STATE_NORMAL;
857 softc->events = 0;
859 pmprelease(periph, -1);
861}
862
863#endif /* _KERNEL */
void ata_pm_read_cmd(struct ccb_ataio *ataio, int reg, int port)
Definition: ata_all.c:708
void ata_pm_write_cmd(struct ccb_ataio *ataio, int reg, int port, uint32_t val)
Definition: ata_all.c:718
#define PMP_DEFAULT_HIDE_SPECIAL
Definition: ata_pmp.c:135
static periph_ctor_t pmpregister
Definition: ata_pmp.c:119
static void pmpsysctlinit(void *context, int pending)
Definition: ata_pmp.c:339
#define PMP_DEFAULT_RETRY
Definition: ata_pmp.c:131
pmp_state
Definition: ata_pmp.c:66
@ PMP_STATE_CHECK
Definition: ata_pmp.c:75
@ PMP_STATE_NORMAL
Definition: ata_pmp.c:67
@ PMP_STATE_PRECONFIG
Definition: ata_pmp.c:72
@ PMP_STATE_PORTS
Definition: ata_pmp.c:68
@ PMP_STATE_PM_QUIRKS_3
Definition: ata_pmp.c:71
@ PMP_STATE_PM_QUIRKS_1
Definition: ata_pmp.c:69
@ PMP_STATE_CONFIG
Definition: ata_pmp.c:77
@ PMP_STATE_RESET
Definition: ata_pmp.c:73
@ PMP_STATE_PM_QUIRKS_2
Definition: ata_pmp.c:70
@ PMP_STATE_SCAN
Definition: ata_pmp.c:78
@ PMP_STATE_CLEAR
Definition: ata_pmp.c:76
@ PMP_STATE_CONNECT
Definition: ata_pmp.c:74
static int pmp_retry_count
Definition: ata_pmp.c:138
static void pmpfreeze(struct cam_periph *periph, int mask)
Definition: ata_pmp.c:178
static void pmprelease(struct cam_periph *periph, int mask)
Definition: ata_pmp.c:200
PERIPHDRIVER_DECLARE(pmp, pmpdriver)
pmp_flags
Definition: ata_pmp.c:81
@ PMP_FLAG_SCTX_INIT
Definition: ata_pmp.c:82
pmp_ccb_state
Definition: ata_pmp.c:85
@ PMP_CCB_PROBE
Definition: ata_pmp.c:86
static void pmpdone(struct cam_periph *periph, union ccb *done_ccb)
Definition: ata_pmp.c:583
#define PMP_EV_RESET
SYSCTL_INT(_kern_cam_pmp, OID_AUTO, retry_count, CTLFLAG_RWTUN, &pmp_retry_count, 0, "Normal I/O retry count")
static periph_dtor_t pmpcleanup
Definition: ata_pmp.c:120
static void pmpasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
Definition: ata_pmp.c:265
__FBSDID("$FreeBSD$")
#define PMP_DEFAULT_TIMEOUT
Definition: ata_pmp.c:127
static int pmp_default_timeout
Definition: ata_pmp.c:139
static periph_init_t pmpinit
Definition: ata_pmp.c:115
static periph_oninv_t pmponinvalidate
Definition: ata_pmp.c:122
#define PMP_EV_RESCAN
static int pmp_hide_special
Definition: ata_pmp.c:140
static struct periph_driver pmpdriver
Definition: ata_pmp.c:151
static periph_start_t pmpstart
Definition: ata_pmp.c:121
static SYSCTL_NODE(_kern_cam, OID_AUTO, pmp, CTLFLAG_RD|CTLFLAG_MPSAFE, 0, "CAM Direct Access Disk driver")
#define CAM_PRIORITY_NONE
Definition: cam.h:93
#define CAM_PRIORITY_XPT
Definition: cam.h:89
cam_status
Definition: cam.h:132
@ CAM_REQ_INPROG
Definition: cam.h:134
@ CAM_REQ_CMP
Definition: cam.h:137
@ CAM_REQ_CMP_ERR
Definition: cam.h:146
@ CAM_STATUS_MASK
Definition: cam.h:302
@ CAM_DEV_QFRZN
Definition: cam.h:287
#define CAM_PRIORITY_DEV
Definition: cam.h:90
#define CTS_SATA_CAPS_H_DMAAA
Definition: cam_ccb.h:1033
@ AC_FOUND_DEVICE
Definition: cam_ccb.h:874
@ AC_SCSI_AEN
Definition: cam_ccb.h:878
@ AC_BUS_RESET
Definition: cam_ccb.h:880
@ AC_LOST_DEVICE
Definition: cam_ccb.h:873
@ AC_SENT_BDR
Definition: cam_ccb.h:877
#define RELSIM_RELEASE_AFTER_TIMEOUT
Definition: cam_ccb.h:841
static __inline void cam_fill_ataio(struct ccb_ataio *ataio, u_int32_t retries, void(*cbfcnp)(struct cam_periph *, union ccb *), u_int32_t flags, u_int tag_action __unused, u_int8_t *data_ptr, u_int32_t dxfer_len, u_int32_t timeout)
Definition: cam_ccb.h:1436
@ PROTO_SATAPM
Definition: cam_ccb.h:282
@ CTS_TYPE_CURRENT_SETTINGS
Definition: cam_ccb.h:945
@ CTS_TYPE_USER_SETTINGS
Definition: cam_ccb.h:946
#define CTS_SATA_VALID_CAPS
Definition: cam_ccb.h:1022
#define CTS_SATA_CAPS_H_AN
Definition: cam_ccb.h:1034
@ CAM_DIR_NONE
Definition: cam_ccb.h:81
#define CTS_SATA_CAPS_H_PMREQ
Definition: cam_ccb.h:1031
#define CTS_SATA_VALID_REVISION
Definition: cam_ccb.h:1018
@ XPT_GET_TRAN_SETTINGS
Definition: cam_ccb.h:183
@ XPT_SET_TRAN_SETTINGS
Definition: cam_ccb.h:188
@ CAM_DEBUG_TRACE
Definition: cam_debug.h:41
#define CAM_DEBUG(path, flag, printfargs)
Definition: cam_debug.h:93
void cam_periph_release_locked(struct cam_periph *periph)
Definition: cam_periph.c:453
void cam_freeze_devq(struct cam_path *path)
Definition: cam_periph.c:1329
u_int32_t cam_release_devq(struct cam_path *path, u_int32_t relsim_flags, u_int32_t openings, u_int32_t arg, int getcount_only)
Definition: cam_periph.c:1342
int cam_periph_acquire(struct cam_periph *periph)
Definition: cam_periph.c:413
void cam_periph_async(struct cam_periph *periph, u_int32_t code, struct cam_path *path, void *arg)
Definition: cam_periph.c:1471
void cam_periph_release(struct cam_periph *periph)
Definition: cam_periph.c:465
int cam_periph_error(union ccb *ccb, cam_flags camflags, u_int32_t sense_flags)
Definition: cam_periph.c:1864
cam_status cam_periph_alloc(periph_ctor_t *periph_ctor, periph_oninv_t *periph_oninvalidate, periph_dtor_t *periph_dtor, periph_start_t *periph_start, char *name, cam_periph_type type, struct cam_path *path, ac_callback_t *ac_callback, ac_code code, void *arg)
Definition: cam_periph.c:197
cam_status periph_ctor_t(struct cam_periph *periph, void *arg)
Definition: cam_periph.h:115
void periph_oninv_t(struct cam_periph *periph)
Definition: cam_periph.h:117
#define cam_periph_lock(periph)
Definition: cam_periph.h:224
#define CAM_PERIPH_DRV_EARLY
Definition: cam_periph.h:99
#define cam_periph_unlock(periph)
Definition: cam_periph.h:227
void periph_dtor_t(struct cam_periph *periph)
Definition: cam_periph.h:118
void periph_start_t(struct cam_periph *periph, union ccb *start_ccb)
Definition: cam_periph.h:113
@ CAM_PERIPH_BIO
Definition: cam_periph.h:104
void() periph_init_t(void)
Definition: cam_periph.h:85
void xpt_acquire_device(struct cam_ed *device)
Definition: cam_xpt.c:4897
void xpt_schedule(struct cam_periph *periph, u_int32_t new_priority)
Definition: cam_xpt.c:3243
cam_status xpt_create_path(struct cam_path **new_path_ptr, struct cam_periph *perph, path_id_t path_id, target_id_t target_id, lun_id_t lun_id)
Definition: cam_xpt.c:3527
void xpt_release_device(struct cam_ed *device)
Definition: cam_xpt.c:4907
void xpt_print(struct cam_path *path, const char *fmt,...)
Definition: cam_xpt.c:3814
void xpt_rescan(union ccb *ccb)
Definition: cam_xpt.c:840
path_id_t xpt_path_path_id(struct cam_path *path)
Definition: cam_xpt.c:3880
void xpt_async(u_int32_t async_code, struct cam_path *path, void *async_arg)
Definition: cam_xpt.c:4350
void xpt_announce_periph(struct cam_periph *periph, char *announce_string)
Definition: cam_xpt.c:1049
void xpt_setup_ccb(struct ccb_hdr *ccb_h, struct cam_path *path, u_int32_t priority)
Definition: cam_xpt.c:3520
void xpt_action(union ccb *start_ccb)
Definition: cam_xpt.c:2601
cam_status xpt_register_async(int event, ac_callback_t *cbfunc, void *cbarg, struct cam_path *path)
Definition: cam_xpt.c:5213
union ccb * xpt_alloc_ccb_nowait(void)
Definition: cam_xpt.c:4621
void xpt_free_path(struct cam_path *path)
Definition: cam_xpt.c:3672
void xpt_release_boot(void)
Definition: cam_xpt.c:5157
void xpt_release_ccb(union ccb *free_ccb)
Definition: cam_xpt.c:3924
void xpt_hold_boot(void)
Definition: cam_xpt.c:5148
union ccb * ccb
Definition: mmc_sim_if.m:53
struct ccb_trans_settings_mmc * cts
Definition: mmc_sim_if.m:43
u_int8_t lba_mid
Definition: ata_all.h:78
u_int8_t lba_high
Definition: ata_all.h:79
u_int8_t lba_low
Definition: ata_all.h:77
u_int8_t sector_count
Definition: ata_all.h:86
struct cam_periph * periph
char * periph_name
Definition: cam_periph.h:123
u_int32_t unit_number
Definition: cam_periph.h:127
void * softc
Definition: cam_periph.h:125
struct cam_path * path
Definition: cam_periph.h:124
u_int32_t priority
Definition: cam.h:86
struct ata_res res
Definition: cam_ccb.h:795
cam_proto protocol
Definition: cam_ccb.h:380
struct ata_params ident_data
Definition: cam_ccb.h:382
path_id_t path_id
Definition: cam_ccb.h:365
struct cam_path * path
Definition: cam_ccb.h:364
cam_pinfo pinfo
Definition: cam_ccb.h:349
u_int32_t status
Definition: cam_ccb.h:363
Definition: cam_ccb.h:1345
struct ccb_hdr ccb_h
Definition: cam_ccb.h:1346
struct ccb_ataio ataio
Definition: cam_ccb.h:1376