The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/cam/ata/ata_pmp.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.