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/dev/ic/mlx.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 /*      $NetBSD: mlx.c,v 1.57 2008/09/09 12:45:40 tron Exp $    */
    2 
    3 /*-
    4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Andrew Doran.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 /*-
   33  * Copyright (c) 1999 Michael Smith
   34  * All rights reserved.
   35  *
   36  * Redistribution and use in source and binary forms, with or without
   37  * modification, are permitted provided that the following conditions
   38  * are met:
   39  * 1. Redistributions of source code must retain the above copyright
   40  *    notice, this list of conditions and the following disclaimer.
   41  * 2. Redistributions in binary form must reproduce the above copyright
   42  *    notice, this list of conditions and the following disclaimer in the
   43  *    documentation and/or other materials provided with the distribution.
   44  *
   45  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   46  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   47  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   48  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   49  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   50  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   51  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   52  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   53  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   54  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   55  * SUCH DAMAGE.
   56  *
   57  * from FreeBSD: mlx.c,v 1.14.2.3 2000/08/04 06:52:50 msmith Exp
   58  */
   59 
   60 /*
   61  * Driver for the Mylex DAC960 family of RAID controllers.
   62  *
   63  * TODO:
   64  *
   65  * o Test and enable channel pause.
   66  * o SCSI pass-through.
   67  */
   68 
   69 #include <sys/cdefs.h>
   70 __KERNEL_RCSID(0, "$NetBSD: mlx.c,v 1.57 2008/09/09 12:45:40 tron Exp $");
   71 
   72 #include "ld.h"
   73 
   74 #include <sys/param.h>
   75 #include <sys/systm.h>
   76 #include <sys/kernel.h>
   77 #include <sys/device.h>
   78 #include <sys/queue.h>
   79 #include <sys/proc.h>
   80 #include <sys/buf.h>
   81 #include <sys/bufq.h>
   82 #include <sys/endian.h>
   83 #include <sys/malloc.h>
   84 #include <sys/conf.h>
   85 #include <sys/kthread.h>
   86 #include <sys/disk.h>
   87 #include <sys/kauth.h>
   88 
   89 #include <machine/vmparam.h>
   90 #include <sys/bus.h>
   91 
   92 #include <uvm/uvm_extern.h>
   93 
   94 #include <dev/ldvar.h>
   95 
   96 #include <dev/ic/mlxreg.h>
   97 #include <dev/ic/mlxio.h>
   98 #include <dev/ic/mlxvar.h>
   99 
  100 #include "locators.h"
  101 
  102 #define MLX_TIMEOUT     60
  103 
  104 #ifdef DIAGNOSTIC
  105 #define DPRINTF(x)      printf x
  106 #else
  107 #define DPRINTF(x)
  108 #endif
  109 
  110 static void     mlx_adjqparam(struct mlx_softc *, int, int);
  111 static int      mlx_ccb_submit(struct mlx_softc *, struct mlx_ccb *);
  112 static int      mlx_check(struct mlx_softc *, int);
  113 static void     mlx_configure(struct mlx_softc *, int);
  114 static void     mlx_describe(struct mlx_softc *);
  115 static void     *mlx_enquire(struct mlx_softc *, int, size_t,
  116                              void (*)(struct mlx_ccb *), int);
  117 static int      mlx_fw_message(struct mlx_softc *, int, int, int);
  118 static void     mlx_pause_action(struct mlx_softc *);
  119 static void     mlx_pause_done(struct mlx_ccb *);
  120 static void     mlx_periodic(struct mlx_softc *);
  121 static void     mlx_periodic_enquiry(struct mlx_ccb *);
  122 static void     mlx_periodic_eventlog_poll(struct mlx_softc *);
  123 static void     mlx_periodic_eventlog_respond(struct mlx_ccb *);
  124 static void     mlx_periodic_rebuild(struct mlx_ccb *);
  125 static void     mlx_periodic_thread(void *);
  126 static int      mlx_print(void *, const char *);
  127 static int      mlx_rebuild(struct mlx_softc *, int, int);
  128 static void     mlx_shutdown(void *);
  129 static int      mlx_user_command(struct mlx_softc *, struct mlx_usercommand *);
  130 
  131 dev_type_open(mlxopen);
  132 dev_type_close(mlxclose);
  133 dev_type_ioctl(mlxioctl);
  134 
  135 const struct cdevsw mlx_cdevsw = {
  136         mlxopen, mlxclose, noread, nowrite, mlxioctl,
  137         nostop, notty, nopoll, nommap, nokqfilter, D_OTHER,
  138 };
  139 
  140 extern struct   cfdriver mlx_cd;
  141 static struct   lwp *mlx_periodic_lwp;
  142 static void     *mlx_sdh;
  143 
  144 static struct {
  145         int     hwid;
  146         const char      *name;
  147 } const mlx_cname[] = {
  148         { 0x00, "960E/960M" },
  149         { 0x01, "960P/PD" },
  150         { 0x02, "960PL" },
  151         { 0x10, "960PG" },
  152         { 0x11, "960PJ" },
  153         { 0x12, "960PR" },
  154         { 0x13, "960PT" },
  155         { 0x14, "960PTL0" },
  156         { 0x15, "960PRL" },
  157         { 0x16, "960PTL1" },
  158         { 0x20, "1164PVX" },
  159 };
  160 
  161 static const char * const mlx_sense_msgs[] = {
  162         "because write recovery failed",
  163         "because of SCSI bus reset failure",
  164         "because of double check condition",
  165         "because it was removed",
  166         "because of gross error on SCSI chip",
  167         "because of bad tag returned from drive",
  168         "because of timeout on SCSI command",
  169         "because of reset SCSI command issued from system",
  170         "because busy or parity error count exceeded limit",
  171         "because of 'kill drive' command from system",
  172         "because of selection timeout",
  173         "due to SCSI phase sequence error",
  174         "due to unknown status"
  175 };
  176 
  177 static const char * const mlx_status_msgs[] = {
  178         "normal completion",                            /* 0 */
  179         "irrecoverable data error",                     /* 1 */
  180         "drive does not exist, or is offline",          /* 2 */
  181         "attempt to write beyond end of drive",         /* 3 */
  182         "bad data encountered",                         /* 4 */
  183         "invalid log entry request",                    /* 5 */
  184         "attempt to rebuild online drive",              /* 6 */
  185         "new disk failed during rebuild",               /* 7 */
  186         "invalid channel/target",                       /* 8 */
  187         "rebuild/check already in progress",            /* 9 */
  188         "one or more disks are dead",                   /* 10 */
  189         "invalid or non-redundant drive",               /* 11 */
  190         "channel is busy",                              /* 12 */
  191         "channel is not stopped",                       /* 13 */
  192         "rebuild successfully terminated",              /* 14 */
  193         "unsupported command",                          /* 15 */
  194         "check condition received",                     /* 16 */
  195         "device is busy",                               /* 17 */
  196         "selection or command timeout",                 /* 18 */
  197         "command terminated abnormally",                /* 19 */
  198         "controller wedged",                            /* 20 */
  199         "software timeout",                             /* 21 */
  200         "command busy (?)",                             /* 22 */
  201 };
  202 
  203 static struct {
  204         u_char  command;
  205         u_char  msg;            /* Index into mlx_status_msgs[]. */
  206         u_short status;
  207 } const mlx_msgs[] = {
  208         { MLX_CMD_READSG,       1,      0x0001 },
  209         { MLX_CMD_READSG,       1,      0x0002 },
  210         { MLX_CMD_READSG,       3,      0x0105 },
  211         { MLX_CMD_READSG,       4,      0x010c },
  212         { MLX_CMD_WRITESG,      1,      0x0001 },
  213         { MLX_CMD_WRITESG,      1,      0x0002 },
  214         { MLX_CMD_WRITESG,      3,      0x0105 },
  215         { MLX_CMD_READSG_OLD,   1,      0x0001 },
  216         { MLX_CMD_READSG_OLD,   1,      0x0002 },
  217         { MLX_CMD_READSG_OLD,   3,      0x0105 },
  218         { MLX_CMD_WRITESG_OLD,  1,      0x0001 },
  219         { MLX_CMD_WRITESG_OLD,  1,      0x0002 },
  220         { MLX_CMD_WRITESG_OLD,  3,      0x0105 },
  221         { MLX_CMD_LOGOP,        5,      0x0105 },
  222         { MLX_CMD_REBUILDASYNC, 6,      0x0002 },
  223         { MLX_CMD_REBUILDASYNC, 7,      0x0004 },
  224         { MLX_CMD_REBUILDASYNC, 8,      0x0105 },
  225         { MLX_CMD_REBUILDASYNC, 9,      0x0106 },
  226         { MLX_CMD_REBUILDASYNC, 14,     0x0107 },
  227         { MLX_CMD_CHECKASYNC,   10,     0x0002 },
  228         { MLX_CMD_CHECKASYNC,   11,     0x0105 },
  229         { MLX_CMD_CHECKASYNC,   9,      0x0106 },
  230         { MLX_CMD_STOPCHANNEL,  12,     0x0106 },
  231         { MLX_CMD_STOPCHANNEL,  8,      0x0105 },
  232         { MLX_CMD_STARTCHANNEL, 13,     0x0005 },
  233         { MLX_CMD_STARTCHANNEL, 8,      0x0105 },
  234         { MLX_CMD_DIRECT_CDB,   16,     0x0002 },
  235         { MLX_CMD_DIRECT_CDB,   17,     0x0008 },
  236         { MLX_CMD_DIRECT_CDB,   18,     0x000e },
  237         { MLX_CMD_DIRECT_CDB,   19,     0x000f },
  238         { MLX_CMD_DIRECT_CDB,   8,      0x0105 },
  239 
  240         { 0,                    20,     MLX_STATUS_WEDGED },
  241         { 0,                    21,     MLX_STATUS_LOST },
  242         { 0,                    22,     MLX_STATUS_BUSY },
  243 
  244         { 0,                    14,     0x0104 },
  245 };
  246 
  247 /*
  248  * Initialise the controller and our interface.
  249  */
  250 void
  251 mlx_init(struct mlx_softc *mlx, const char *intrstr)
  252 {
  253         struct mlx_ccb *mc;
  254         struct mlx_enquiry_old *meo;
  255         struct mlx_enquiry2 *me2;
  256         struct mlx_cinfo *ci;
  257         int rv, fwminor, hscode, hserr, hsparam1, hsparam2, hsmsg;
  258         int size, i, rseg;
  259         const char *wantfwstr;
  260         bus_dma_segment_t seg;
  261 
  262         SIMPLEQ_INIT(&mlx->mlx_ccb_queue);
  263         SLIST_INIT(&mlx->mlx_ccb_freelist);
  264         TAILQ_INIT(&mlx->mlx_ccb_worklist);
  265 
  266         if (intrstr != NULL)
  267                 printf("%s: interrupting at %s\n", device_xname(&mlx->mlx_dv),
  268                     intrstr);
  269 
  270         /*
  271          * Allocate the scatter/gather lists.
  272          */
  273         size = MLX_SGL_SIZE * MLX_MAX_QUEUECNT;
  274 
  275         if ((rv = bus_dmamem_alloc(mlx->mlx_dmat, size, PAGE_SIZE, 0, &seg, 1,
  276             &rseg, BUS_DMA_NOWAIT)) != 0) {
  277                 aprint_error_dev(&mlx->mlx_dv, "unable to allocate sglists, rv = %d\n", rv);
  278                 return;
  279         }
  280 
  281         if ((rv = bus_dmamem_map(mlx->mlx_dmat, &seg, rseg, size,
  282             (void **)&mlx->mlx_sgls,
  283             BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
  284                 aprint_error_dev(&mlx->mlx_dv, "unable to map sglists, rv = %d\n", rv);
  285                 return;
  286         }
  287 
  288         if ((rv = bus_dmamap_create(mlx->mlx_dmat, size, 1, size, 0,
  289             BUS_DMA_NOWAIT, &mlx->mlx_dmamap)) != 0) {
  290                 aprint_error_dev(&mlx->mlx_dv, "unable to create sglist DMA map, rv = %d\n", rv);
  291                 return;
  292         }
  293 
  294         if ((rv = bus_dmamap_load(mlx->mlx_dmat, mlx->mlx_dmamap,
  295             mlx->mlx_sgls, size, NULL, BUS_DMA_NOWAIT)) != 0) {
  296                 aprint_error_dev(&mlx->mlx_dv, "unable to load sglist DMA map, rv = %d\n", rv);
  297                 return;
  298         }
  299 
  300         mlx->mlx_sgls_paddr = mlx->mlx_dmamap->dm_segs[0].ds_addr;
  301         memset(mlx->mlx_sgls, 0, size);
  302 
  303         /*
  304          * Allocate and initialize the CCBs.
  305          */
  306         mc = malloc(sizeof(*mc) * MLX_MAX_QUEUECNT, M_DEVBUF, M_NOWAIT);
  307         mlx->mlx_ccbs = mc;
  308 
  309         for (i = 0; i < MLX_MAX_QUEUECNT; i++, mc++) {
  310                 mc->mc_ident = i;
  311                 rv = bus_dmamap_create(mlx->mlx_dmat, MLX_MAX_XFER,
  312                     MLX_MAX_SEGS, MLX_MAX_XFER, 0,
  313                     BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
  314                     &mc->mc_xfer_map);
  315                 if (rv != 0)
  316                         break;
  317                 mlx->mlx_nccbs++;
  318                 mlx_ccb_free(mlx, mc);
  319         }
  320         if (mlx->mlx_nccbs != MLX_MAX_QUEUECNT)
  321                 printf("%s: %d/%d CCBs usable\n", device_xname(&mlx->mlx_dv),
  322                     mlx->mlx_nccbs, MLX_MAX_QUEUECNT);
  323 
  324         /* Disable interrupts before we start talking to the controller */
  325         (*mlx->mlx_intaction)(mlx, 0);
  326 
  327         /* If we've got a reset routine, then reset the controller now. */
  328         if (mlx->mlx_reset != NULL) {
  329                 printf("%s: resetting controller...\n", device_xname(&mlx->mlx_dv));
  330                 if ((*mlx->mlx_reset)(mlx) != 0) {
  331                         aprint_error_dev(&mlx->mlx_dv, "reset failed\n");
  332                         return;
  333                 }
  334         }
  335 
  336         /*
  337          * Wait for the controller to come ready, handshaking with the
  338          * firmware if required.  This is typically only necessary on
  339          * platforms where the controller BIOS does not run.
  340          */
  341         hsmsg = 0;
  342 
  343         for (;;) {
  344                 hscode = (*mlx->mlx_fw_handshake)(mlx, &hserr, &hsparam1,
  345                     &hsparam2);
  346                 if (hscode == 0) {
  347                         if (hsmsg != 0)
  348                                 printf("%s: initialization complete\n",
  349                                     device_xname(&mlx->mlx_dv));
  350                         break;
  351                 }
  352 
  353                 /* Report first time around... */
  354                 if (hsmsg == 0) {
  355                         printf("%s: initializing (may take some time)...\n",
  356                             device_xname(&mlx->mlx_dv));
  357                         hsmsg = 1;
  358                 }
  359 
  360                 /* Did we get a real message? */
  361                 if (hscode == 2) {
  362                         hscode = mlx_fw_message(mlx, hserr, hsparam1, hsparam2);
  363 
  364                         /* Fatal initialisation error? */
  365                         if (hscode != 0)
  366                                 return;
  367                 }
  368         }
  369 
  370         /*
  371          * Do quirk/feature related things.
  372          */
  373         ci = &mlx->mlx_ci;
  374 
  375         if (ci->ci_iftype > 1) {
  376                 me2 = mlx_enquire(mlx, MLX_CMD_ENQUIRY2,
  377                     sizeof(struct mlx_enquiry2), NULL, 0);
  378                 if (me2 == NULL) {
  379                         aprint_error_dev(&mlx->mlx_dv, "ENQUIRY2 failed\n");
  380                         return;
  381                 }
  382 
  383                 ci->ci_firmware_id[0] = me2->me_firmware_id[0];
  384                 ci->ci_firmware_id[1] = me2->me_firmware_id[1];
  385                 ci->ci_firmware_id[2] = me2->me_firmware_id[2];
  386                 ci->ci_firmware_id[3] = me2->me_firmware_id[3];
  387                 ci->ci_hardware_id = me2->me_hardware_id[0];
  388                 ci->ci_mem_size = le32toh(me2->me_mem_size);
  389                 ci->ci_max_sg = le16toh(me2->me_max_sg);
  390                 ci->ci_max_commands = le16toh(me2->me_max_commands);
  391                 ci->ci_nchan = me2->me_actual_channels;
  392 
  393                 free(me2, M_DEVBUF);
  394         }
  395 
  396         if (ci->ci_iftype <= 2) {
  397                 /*
  398                  * These controllers may not report the firmware version in
  399                  * the ENQUIRY2 response, or may not even support it.
  400                  */
  401                 meo = mlx_enquire(mlx, MLX_CMD_ENQUIRY_OLD,
  402                     sizeof(struct mlx_enquiry_old), NULL, 0);
  403                 if (meo == NULL) {
  404                         aprint_error_dev(&mlx->mlx_dv, "ENQUIRY_OLD failed\n");
  405                         return;
  406                 }
  407                 ci->ci_firmware_id[0] = meo->me_fwmajor;
  408                 ci->ci_firmware_id[1] = meo->me_fwminor;
  409                 ci->ci_firmware_id[2] = 0;
  410                 ci->ci_firmware_id[3] = '';
  411 
  412                 if (ci->ci_iftype == 1) {
  413                         ci->ci_hardware_id = 0; /* XXX */
  414                         ci->ci_mem_size = 0;    /* XXX */
  415                         ci->ci_max_sg = 17;     /* XXX */
  416                         ci->ci_max_commands = meo->me_max_commands;
  417                 }
  418 
  419                 free(meo, M_DEVBUF);
  420         }
  421 
  422         wantfwstr = NULL;
  423         fwminor = ci->ci_firmware_id[1];
  424 
  425         switch (ci->ci_firmware_id[0]) {
  426         case 2:
  427                 if (ci->ci_iftype == 1) {
  428                         if (fwminor < 14)
  429                                 wantfwstr = "2.14";
  430                 } else if (fwminor < 42)
  431                         wantfwstr = "2.42";
  432                 break;
  433 
  434         case 3:
  435                 if (fwminor < 51)
  436                         wantfwstr = "3.51";
  437                 break;
  438 
  439         case 4:
  440                 if (fwminor < 6)
  441                         wantfwstr = "4.06";
  442                 break;
  443 
  444         case 5:
  445                 if (fwminor < 7)
  446                         wantfwstr = "5.07";
  447                 break;
  448         }
  449 
  450         /* Print a little information about the controller. */
  451         mlx_describe(mlx);
  452 
  453         if (wantfwstr != NULL) {
  454                 printf("%s: WARNING: this f/w revision is not recommended\n",
  455                     device_xname(&mlx->mlx_dv));
  456                 printf("%s: WARNING: use revision %s or later\n",
  457                     device_xname(&mlx->mlx_dv), wantfwstr);
  458         }
  459 
  460         /* We don't (yet) know where the event log is up to. */
  461         mlx->mlx_currevent = -1;
  462 
  463         /* No user-requested background operation is in progress. */
  464         mlx->mlx_bg = 0;
  465         mlx->mlx_rebuildstat.rs_code = MLX_REBUILDSTAT_IDLE;
  466 
  467         /* Set maximum number of queued commands for `regular' operations. */
  468         mlx->mlx_max_queuecnt =
  469             min(ci->ci_max_commands, MLX_MAX_QUEUECNT) -
  470             MLX_NCCBS_CONTROL;
  471 #ifdef DIAGNOSTIC
  472         if (mlx->mlx_max_queuecnt < MLX_NCCBS_CONTROL + MLX_MAX_DRIVES)
  473                 printf("%s: WARNING: few CCBs available\n",
  474                     device_xname(&mlx->mlx_dv));
  475         if (ci->ci_max_sg < MLX_MAX_SEGS) {
  476                 aprint_error_dev(&mlx->mlx_dv, "oops, not enough S/G segments\n");
  477                 return;
  478         }
  479 #endif
  480 
  481         /* Attach child devices and enable interrupts. */
  482         mlx_configure(mlx, 0);
  483         (*mlx->mlx_intaction)(mlx, 1);
  484         mlx->mlx_flags |= MLXF_INITOK;
  485 
  486         if (mlx_sdh == NULL) {
  487                 /*
  488                  * Set our `shutdownhook' before we start any device
  489                  * activity.
  490                  */
  491                 mlx_sdh = shutdownhook_establish(mlx_shutdown, NULL);
  492 
  493                 /* Create a status monitoring thread. */
  494                 rv = kthread_create(PRI_NONE, 0, NULL, mlx_periodic_thread,
  495                     NULL, &mlx_periodic_lwp, "mlxtask");
  496                 if (rv != 0)
  497                         printf("mlx_init: unable to create thread (%d)\n", rv);
  498         }
  499 }
  500 
  501 /*
  502  * Tell the world about the controller.
  503  */
  504 static void
  505 mlx_describe(struct mlx_softc *mlx)
  506 {
  507         struct mlx_cinfo *ci;
  508         static char tbuf[80];
  509         const char *model;
  510         int i;
  511 
  512         model = NULL;
  513         ci = &mlx->mlx_ci;
  514 
  515         for (i = 0; i < sizeof(mlx_cname) / sizeof(mlx_cname[0]); i++)
  516                 if (ci->ci_hardware_id == mlx_cname[i].hwid) {
  517                         model = mlx_cname[i].name;
  518                         break;
  519                 }
  520 
  521         if (model == NULL) {
  522                 snprintf(tbuf, sizeof(tbuf), " model 0x%x", ci->ci_hardware_id);
  523                 model = tbuf;
  524         }
  525 
  526         printf("%s: DAC%s, %d channel%s, firmware %d.%02d-%c-%02d",
  527             device_xname(&mlx->mlx_dv), model, ci->ci_nchan,
  528             ci->ci_nchan > 1 ? "s" : "",
  529             ci->ci_firmware_id[0], ci->ci_firmware_id[1],
  530             ci->ci_firmware_id[3], ci->ci_firmware_id[2]);
  531         if (ci->ci_mem_size != 0)
  532                 printf(", %dMB RAM", ci->ci_mem_size >> 20);
  533         printf("\n");
  534 }
  535 
  536 /*
  537  * Locate disk resources and attach children to them.
  538  */
  539 static void
  540 mlx_configure(struct mlx_softc *mlx, int waitok)
  541 {
  542         struct mlx_enquiry *me;
  543         struct mlx_enquiry_old *meo;
  544         struct mlx_enq_sys_drive *mes;
  545         struct mlx_sysdrive *ms;
  546         struct mlx_attach_args mlxa;
  547         int i, nunits;
  548         u_int size;
  549         int locs[MLXCF_NLOCS];
  550 
  551         mlx->mlx_flags |= MLXF_RESCANNING;
  552 
  553         if (mlx->mlx_ci.ci_iftype <= 2) {
  554                 meo = mlx_enquire(mlx, MLX_CMD_ENQUIRY_OLD,
  555                     sizeof(struct mlx_enquiry_old), NULL, waitok);
  556                 if (meo == NULL) {
  557                         aprint_error_dev(&mlx->mlx_dv, "ENQUIRY_OLD failed\n");
  558                         goto out;
  559                 }
  560                 mlx->mlx_numsysdrives = meo->me_num_sys_drvs;
  561                 free(meo, M_DEVBUF);
  562         } else {
  563                 me = mlx_enquire(mlx, MLX_CMD_ENQUIRY,
  564                     sizeof(struct mlx_enquiry), NULL, waitok);
  565                 if (me == NULL) {
  566                         aprint_error_dev(&mlx->mlx_dv, "ENQUIRY failed\n");
  567                         goto out;
  568                 }
  569                 mlx->mlx_numsysdrives = me->me_num_sys_drvs;
  570                 free(me, M_DEVBUF);
  571         }
  572 
  573         mes = mlx_enquire(mlx, MLX_CMD_ENQSYSDRIVE,
  574             sizeof(*mes) * MLX_MAX_DRIVES, NULL, waitok);
  575         if (mes == NULL) {
  576                 aprint_error_dev(&mlx->mlx_dv, "error fetching drive status\n");
  577                 goto out;
  578         }
  579 
  580         /* Allow 1 queued command per unit while re-configuring. */
  581         mlx_adjqparam(mlx, 1, 0);
  582 
  583         ms = &mlx->mlx_sysdrive[0];
  584         nunits = 0;
  585         for (i = 0; i < MLX_MAX_DRIVES; i++, ms++) {
  586                 size = le32toh(mes[i].sd_size);
  587                 ms->ms_state = mes[i].sd_state;
  588 
  589                 /*
  590                  * If an existing device has changed in some way (e.g. no
  591                  * longer present) then detach it.
  592                  */
  593                 if (ms->ms_dv != NULL && (size != ms->ms_size ||
  594                     (mes[i].sd_raidlevel & 0xf) != ms->ms_raidlevel))
  595                         config_detach(ms->ms_dv, DETACH_FORCE);
  596 
  597                 ms->ms_size = size;
  598                 ms->ms_raidlevel = mes[i].sd_raidlevel & 0xf;
  599                 ms->ms_state = mes[i].sd_state;
  600                 ms->ms_dv = NULL;
  601 
  602                 if (i >= mlx->mlx_numsysdrives)
  603                         continue;
  604                 if (size == 0xffffffffU || size == 0)
  605                         continue;
  606 
  607                 /*
  608                  * Attach a new device.
  609                  */
  610                 mlxa.mlxa_unit = i;
  611 
  612                 locs[MLXCF_UNIT] = i;
  613 
  614                 ms->ms_dv = config_found_sm_loc(&mlx->mlx_dv, "mlx", locs,
  615                                 &mlxa, mlx_print, config_stdsubmatch);
  616                 nunits += (ms->ms_dv != NULL);
  617         }
  618 
  619         free(mes, M_DEVBUF);
  620 
  621         if (nunits != 0)
  622                 mlx_adjqparam(mlx, mlx->mlx_max_queuecnt / nunits,
  623                     mlx->mlx_max_queuecnt % nunits);
  624  out:
  625         mlx->mlx_flags &= ~MLXF_RESCANNING;
  626 }
  627 
  628 /*
  629  * Print autoconfiguration message for a sub-device.
  630  */
  631 static int
  632 mlx_print(void *aux, const char *pnp)
  633 {
  634         struct mlx_attach_args *mlxa;
  635 
  636         mlxa = (struct mlx_attach_args *)aux;
  637 
  638         if (pnp != NULL)
  639                 aprint_normal("block device at %s", pnp);
  640         aprint_normal(" unit %d", mlxa->mlxa_unit);
  641         return (UNCONF);
  642 }
  643 
  644 /*
  645  * Shut down all configured `mlx' devices.
  646  */
  647 static void
  648 mlx_shutdown(void *cookie)
  649 {
  650         struct mlx_softc *mlx;
  651         int i;
  652 
  653         for (i = 0; i < mlx_cd.cd_ndevs; i++)
  654                 if ((mlx = device_lookup_private(&mlx_cd, i)) != NULL)
  655                         mlx_flush(mlx, 0);
  656 }
  657 
  658 /*
  659  * Adjust queue parameters for all child devices.
  660  */
  661 static void
  662 mlx_adjqparam(struct mlx_softc *mlx, int mpu, int slop)
  663 {
  664 #if NLD > 0
  665         extern struct cfdriver ld_cd;
  666         struct ld_softc *ld;
  667         int i;
  668 
  669         for (i = 0; i < ld_cd.cd_ndevs; i++) {
  670                 if ((ld = device_lookup_private(&ld_cd, i)) == NULL)
  671                         continue;
  672                 if (device_parent(ld->sc_dv) != &mlx->mlx_dv)
  673                         continue;
  674                 ldadjqparam(ld, mpu + (slop-- > 0));
  675         }
  676 #endif
  677 }
  678 
  679 /*
  680  * Accept an open operation on the control device.
  681  */
  682 int
  683 mlxopen(dev_t dev, int flag, int mode, struct lwp *l)
  684 {
  685         struct mlx_softc *mlx;
  686 
  687         if ((mlx = device_lookup_private(&mlx_cd, minor(dev))) == NULL)
  688                 return (ENXIO);
  689         if ((mlx->mlx_flags & MLXF_INITOK) == 0)
  690                 return (ENXIO);
  691         if ((mlx->mlx_flags & MLXF_OPEN) != 0)
  692                 return (EBUSY);
  693 
  694         mlx->mlx_flags |= MLXF_OPEN;
  695         return (0);
  696 }
  697 
  698 /*
  699  * Accept the last close on the control device.
  700  */
  701 int
  702 mlxclose(dev_t dev, int flag, int mode,
  703     struct lwp *l)
  704 {
  705         struct mlx_softc *mlx;
  706 
  707         mlx = device_lookup_private(&mlx_cd, minor(dev));
  708         mlx->mlx_flags &= ~MLXF_OPEN;
  709         return (0);
  710 }
  711 
  712 /*
  713  * Handle control operations.
  714  */
  715 int
  716 mlxioctl(dev_t dev, u_long cmd, void *data, int flag,
  717     struct lwp *l)
  718 {
  719         struct mlx_softc *mlx;
  720         struct mlx_rebuild_request *rb;
  721         struct mlx_rebuild_status *rs;
  722         struct mlx_pause *mp;
  723         struct mlx_sysdrive *ms;
  724         int i, rv, *arg, result;
  725 
  726         mlx = device_lookup_private(&mlx_cd, minor(dev));
  727 
  728         rb = (struct mlx_rebuild_request *)data;
  729         rs = (struct mlx_rebuild_status *)data;
  730         arg = (int *)data;
  731         rv = 0;
  732 
  733         switch (cmd) {
  734         case MLX_RESCAN_DRIVES:
  735                 /*
  736                  * Scan the controller to see whether new drives have
  737                  * appeared, or old ones disappeared.
  738                  */
  739                 mlx_configure(mlx, 1);
  740                 return (0);
  741 
  742         case MLX_PAUSE_CHANNEL:
  743                 /*
  744                  * Pause one or more SCSI channels for a period of time, to
  745                  * assist in the process of hot-swapping devices.
  746                  *
  747                  * Note that at least the 3.51 firmware on the DAC960PL
  748                  * doesn't seem to do this right.
  749                  */
  750                 if ((mlx->mlx_flags & MLXF_PAUSEWORKS) == 0)
  751                         return (EOPNOTSUPP);
  752 
  753                 mp = (struct mlx_pause *)data;
  754 
  755                 if ((mp->mp_which == MLX_PAUSE_CANCEL) &&
  756                     (mlx->mlx_pause.mp_when != 0)) {
  757                         /* Cancel a pending pause operation. */
  758                         mlx->mlx_pause.mp_which = 0;
  759                         break;
  760                 }
  761 
  762                 /* Fix for legal channels. */
  763                 mp->mp_which &= ((1 << mlx->mlx_ci.ci_nchan) -1);
  764 
  765                 /* Check time values. */
  766                 if (mp->mp_when < 0 || mp->mp_when > 3600 ||
  767                     mp->mp_howlong < 1 || mp->mp_howlong > (0xf * 30)) {
  768                         rv = EINVAL;
  769                         break;
  770                 }
  771 
  772                 /* Check for a pause currently running. */
  773                 if ((mlx->mlx_pause.mp_which != 0) &&
  774                     (mlx->mlx_pause.mp_when == 0)) {
  775                         rv = EBUSY;
  776                         break;
  777                 }
  778 
  779                 /* Looks ok, go with it. */
  780                 mlx->mlx_pause.mp_which = mp->mp_which;
  781                 mlx->mlx_pause.mp_when = time_second + mp->mp_when;
  782                 mlx->mlx_pause.mp_howlong =
  783                     mlx->mlx_pause.mp_when + mp->mp_howlong;
  784 
  785                 return (0);
  786 
  787         case MLX_COMMAND:
  788                 rv = kauth_authorize_device_passthru(l->l_cred, dev,
  789                     KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL, data);
  790                 if (rv)
  791                         return (rv);
  792 
  793                 /*
  794                  * Accept a command passthrough-style.
  795                  */
  796                 return (mlx_user_command(mlx, (struct mlx_usercommand *)data));
  797 
  798         case MLX_REBUILDASYNC:
  799                 /*
  800                  * Start a rebuild on a given SCSI disk
  801                  */
  802                 if (mlx->mlx_bg != 0) {
  803                         rb->rr_status = 0x0106;
  804                         rv = EBUSY;
  805                         break;
  806                 }
  807 
  808                 rb->rr_status = mlx_rebuild(mlx, rb->rr_channel, rb->rr_target);
  809                 switch (rb->rr_status) {
  810                 case 0:
  811                         rv = 0;
  812                         break;
  813                 case 0x10000:
  814                         rv = ENOMEM;    /* Couldn't set up the command. */
  815                         break;
  816                 case 0x0002:
  817                         rv = EBUSY;
  818                         break;
  819                 case 0x0104:
  820                         rv = EIO;
  821                         break;
  822                 case 0x0105:
  823                         rv = ERANGE;
  824                         break;
  825                 case 0x0106:
  826                         rv = EBUSY;
  827                         break;
  828                 default:
  829                         rv = EINVAL;
  830                         break;
  831                 }
  832 
  833                 if (rv == 0)
  834                         mlx->mlx_bg = MLX_BG_REBUILD;
  835 
  836                 return (0);
  837 
  838         case MLX_REBUILDSTAT:
  839                 /*
  840                  * Get the status of the current rebuild or consistency check.
  841                  */
  842                 *rs = mlx->mlx_rebuildstat;
  843                 return (0);
  844 
  845         case MLX_GET_SYSDRIVE:
  846                 /*
  847                  * Return the system drive number matching the `ld' device
  848                  * unit in (arg), if it happens to belong to us.
  849                  */
  850                 for (i = 0; i < MLX_MAX_DRIVES; i++) {
  851                         ms = &mlx->mlx_sysdrive[i];
  852                         if (ms->ms_dv != NULL)
  853                                 if (device_xname(ms->ms_dv)[2] == '' + *arg) {
  854                                         *arg = i;
  855                                         return (0);
  856                                 }
  857                 }
  858                 return (ENOENT);
  859 
  860         case MLX_GET_CINFO:
  861                 /*
  862                  * Return controller info.
  863                  */
  864                 memcpy(arg, &mlx->mlx_ci, sizeof(mlx->mlx_ci));
  865                 return (0);
  866         }
  867 
  868         switch (cmd) {
  869         case MLXD_DETACH:
  870         case MLXD_STATUS:
  871         case MLXD_CHECKASYNC:
  872                 if ((u_int)*arg >= MLX_MAX_DRIVES)
  873                         return (EINVAL);
  874                 ms = &mlx->mlx_sysdrive[*arg];
  875                 if (*arg > MLX_MAX_DRIVES || ms->ms_dv == NULL)
  876                         return (ENOENT);
  877                 break;
  878 
  879         default:
  880                 return (ENOTTY);
  881         }
  882 
  883         switch (cmd) {
  884         case MLXD_DETACH:
  885                 /*
  886                  * Disconnect from the specified drive; it may be about to go
  887                  * away.
  888                  */
  889                 return (config_detach(ms->ms_dv, 0));
  890 
  891         case MLXD_STATUS:
  892                 /*
  893                  * Return the current status of this drive.
  894                  */
  895                 *arg = ms->ms_state;
  896                 return (0);
  897 
  898         case MLXD_CHECKASYNC:
  899                 /*
  900                  * Start a background consistency check on this drive.
  901                  */
  902                 if (mlx->mlx_bg != 0) {
  903                         *arg = 0x0106;
  904                         return (EBUSY);
  905                 }
  906 
  907                 switch (result = mlx_check(mlx, *arg)) {
  908                 case 0:
  909                         rv = 0;
  910                         break;
  911                 case 0x10000:
  912                         rv = ENOMEM;    /* Couldn't set up the command. */
  913                         break;
  914                 case 0x0002:
  915                         rv = EIO;
  916                         break;
  917                 case 0x0105:
  918                         rv = ERANGE;
  919                         break;
  920                 case 0x0106:
  921                         rv = EBUSY;
  922                         break;
  923                 default:
  924                         rv = EINVAL;
  925                         break;
  926                 }
  927 
  928                 if (rv == 0)
  929                         mlx->mlx_bg = MLX_BG_CHECK;
  930                 *arg = result;
  931                 return (rv);
  932         }
  933 
  934         return (ENOTTY);        /* XXX shut up gcc */
  935 }
  936 
  937 static void
  938 mlx_periodic_thread(void *cookie)
  939 {
  940         struct mlx_softc *mlx;
  941         int i;
  942 
  943         for (;;) {
  944                 for (i = 0; i < mlx_cd.cd_ndevs; i++)
  945                         if ((mlx = device_lookup_private(&mlx_cd, i)) != NULL)
  946                                 if (mlx->mlx_ci.ci_iftype > 1)
  947                                         mlx_periodic(mlx);
  948 
  949                 tsleep(mlx_periodic_thread, PWAIT, "mlxzzz", hz * 2);
  950         }
  951 }
  952 
  953 static void
  954 mlx_periodic(struct mlx_softc *mlx)
  955 {
  956         struct mlx_ccb *mc, *nmc;
  957         int etype, s;
  958 
  959         if ((mlx->mlx_pause.mp_which != 0) &&
  960             (mlx->mlx_pause.mp_when > 0) &&
  961             (time_second >= mlx->mlx_pause.mp_when)) {
  962                 /*
  963                  * Start bus pause.
  964                  */
  965                 mlx_pause_action(mlx);
  966                 mlx->mlx_pause.mp_when = 0;
  967         } else if ((mlx->mlx_pause.mp_which != 0) &&
  968                    (mlx->mlx_pause.mp_when == 0)) {
  969                 /*
  970                  * Stop pause if required.
  971                  */
  972                 if (time_second >= mlx->mlx_pause.mp_howlong) {
  973                         mlx_pause_action(mlx);
  974                         mlx->mlx_pause.mp_which = 0;
  975                 }
  976         } else if (time_second > (mlx->mlx_lastpoll + 10)) {
  977                 /*
  978                  * Run normal periodic activities...
  979                  */
  980                 mlx->mlx_lastpoll = time_second;
  981 
  982                 /*
  983                  * Check controller status.
  984                  */
  985                 if ((mlx->mlx_flags & MLXF_PERIODIC_CTLR) == 0) {
  986                         mlx->mlx_flags |= MLXF_PERIODIC_CTLR;
  987 
  988                         if (mlx->mlx_ci.ci_iftype <= 2)
  989                                 etype = MLX_CMD_ENQUIRY_OLD;
  990                         else
  991                                 etype =  MLX_CMD_ENQUIRY;
  992 
  993                         mlx_enquire(mlx, etype, max(sizeof(struct mlx_enquiry),
  994                             sizeof(struct mlx_enquiry_old)),
  995                             mlx_periodic_enquiry, 1);
  996                 }
  997 
  998                 /*
  999                  * Check system drive status.
 1000                  */
 1001                 if ((mlx->mlx_flags & MLXF_PERIODIC_DRIVE) == 0) {
 1002                         mlx->mlx_flags |= MLXF_PERIODIC_DRIVE;
 1003                         mlx_enquire(mlx, MLX_CMD_ENQSYSDRIVE,
 1004                             sizeof(struct mlx_enq_sys_drive) * MLX_MAX_DRIVES,
 1005                             mlx_periodic_enquiry, 1);
 1006                 }
 1007         }
 1008 
 1009         /*
 1010          * Get drive rebuild/check status.
 1011          */
 1012         if ((mlx->mlx_flags & MLXF_PERIODIC_REBUILD) == 0) {
 1013                 mlx->mlx_flags |= MLXF_PERIODIC_REBUILD;
 1014                 mlx_enquire(mlx, MLX_CMD_REBUILDSTAT,
 1015                     sizeof(struct mlx_rebuild_stat), mlx_periodic_rebuild, 1);
 1016         }
 1017 
 1018         /*
 1019          * Time-out busy CCBs.
 1020          */
 1021         s = splbio();
 1022         for (mc = TAILQ_FIRST(&mlx->mlx_ccb_worklist); mc != NULL; mc = nmc) {
 1023                 nmc = TAILQ_NEXT(mc, mc_chain.tailq);
 1024                 if (mc->mc_expiry > time_second) {
 1025                         /*
 1026                          * The remaining CCBs will expire after this one, so
 1027                          * there's no point in going further.
 1028                          */
 1029                         break;
 1030                 }
 1031                 TAILQ_REMOVE(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq);
 1032                 mc->mc_status = MLX_STATUS_LOST;
 1033                 if (mc->mc_mx.mx_handler != NULL)
 1034                         (*mc->mc_mx.mx_handler)(mc);
 1035                 else if ((mc->mc_flags & MC_WAITING) != 0)
 1036                         wakeup(mc);
 1037         }
 1038         splx(s);
 1039 }
 1040 
 1041 /*
 1042  * Handle the result of an ENQUIRY command instigated by periodic status
 1043  * polling.
 1044  */
 1045 static void
 1046 mlx_periodic_enquiry(struct mlx_ccb *mc)
 1047 {
 1048         struct mlx_softc *mlx;
 1049         struct mlx_enquiry *me;
 1050         struct mlx_enquiry_old *meo;
 1051         struct mlx_enq_sys_drive *mes;
 1052         struct mlx_sysdrive *dr;
 1053         const char *statestr;
 1054         int i, j;
 1055         u_int lsn;
 1056 
 1057         mlx = (struct mlx_softc *)mc->mc_mx.mx_dv;
 1058         mlx_ccb_unmap(mlx, mc);
 1059 
 1060         /*
 1061          * Command completed OK?
 1062          */
 1063         if (mc->mc_status != 0) {
 1064                 aprint_error_dev(&mlx->mlx_dv, "periodic enquiry failed - %s\n",
 1065                     mlx_ccb_diagnose(mc));
 1066                 goto out;
 1067         }
 1068 
 1069         /*
 1070          * Respond to command.
 1071          */
 1072         switch (mc->mc_mbox[0]) {
 1073         case MLX_CMD_ENQUIRY_OLD:
 1074                 /*
 1075                  * This is currently a bit fruitless, as we don't know how
 1076                  * to extract the eventlog pointer yet.
 1077                  */
 1078                 me = (struct mlx_enquiry *)mc->mc_mx.mx_context;
 1079                 meo = (struct mlx_enquiry_old *)mc->mc_mx.mx_context;
 1080 
 1081                 /* Convert data in-place to new format */
 1082                 i = sizeof(me->me_dead) / sizeof(me->me_dead[0]);
 1083                 while (--i >= 0) {
 1084                         me->me_dead[i].dd_chan = meo->me_dead[i].dd_chan;
 1085                         me->me_dead[i].dd_targ = meo->me_dead[i].dd_targ;
 1086                 }
 1087 
 1088                 me->me_misc_flags = 0;
 1089                 me->me_rebuild_count = meo->me_rebuild_count;
 1090                 me->me_dead_count = meo->me_dead_count;
 1091                 me->me_critical_sd_count = meo->me_critical_sd_count;
 1092                 me->me_event_log_seq_num = 0;
 1093                 me->me_offline_sd_count = meo->me_offline_sd_count;
 1094                 me->me_max_commands = meo->me_max_commands;
 1095                 me->me_rebuild_flag = meo->me_rebuild_flag;
 1096                 me->me_fwmajor = meo->me_fwmajor;
 1097                 me->me_fwminor = meo->me_fwminor;
 1098                 me->me_status_flags = meo->me_status_flags;
 1099                 me->me_flash_age = meo->me_flash_age;
 1100 
 1101                 i = sizeof(me->me_drvsize) / sizeof(me->me_drvsize[0]);
 1102                 j = sizeof(meo->me_drvsize) / sizeof(meo->me_drvsize[0]);
 1103 
 1104                 while (--i >= 0) {
 1105                         if (i >= j)
 1106                                 me->me_drvsize[i] = 0;
 1107                         else
 1108                                 me->me_drvsize[i] = meo->me_drvsize[i];
 1109                 }
 1110 
 1111                 me->me_num_sys_drvs = meo->me_num_sys_drvs;
 1112 
 1113                 /* FALLTHROUGH */
 1114 
 1115         case MLX_CMD_ENQUIRY:
 1116                 /*
 1117                  * Generic controller status update.  We could do more with
 1118                  * this than just checking the event log.
 1119                  */
 1120                 me = (struct mlx_enquiry *)mc->mc_mx.mx_context;
 1121                 lsn = le16toh(me->me_event_log_seq_num);
 1122 
 1123                 if (mlx->mlx_currevent == -1) {
 1124                         /* Initialise our view of the event log. */
 1125                         mlx->mlx_currevent = lsn;
 1126                         mlx->mlx_lastevent = lsn;
 1127                 } else if (lsn != mlx->mlx_lastevent &&
 1128                            (mlx->mlx_flags & MLXF_EVENTLOG_BUSY) == 0) {
 1129                         /* Record where current events are up to */
 1130                         mlx->mlx_currevent = lsn;
 1131 
 1132                         /* Mark the event log as busy. */
 1133                         mlx->mlx_flags |= MLXF_EVENTLOG_BUSY;
 1134 
 1135                         /* Drain new eventlog entries. */
 1136                         mlx_periodic_eventlog_poll(mlx);
 1137                 }
 1138                 break;
 1139 
 1140         case MLX_CMD_ENQSYSDRIVE:
 1141                 /*
 1142                  * Perform drive status comparison to see if something
 1143                  * has failed.  Don't perform the comparison if we're
 1144                  * reconfiguring, since the system drive table will be
 1145                  * changing.
 1146                  */
 1147                 if ((mlx->mlx_flags & MLXF_RESCANNING) != 0)
 1148                         break;
 1149 
 1150                 mes = (struct mlx_enq_sys_drive *)mc->mc_mx.mx_context;
 1151                 dr = &mlx->mlx_sysdrive[0];
 1152 
 1153                 for (i = 0; i < mlx->mlx_numsysdrives; i++) {
 1154                         /* Has state been changed by controller? */
 1155                         if (dr->ms_state != mes[i].sd_state) {
 1156                                 switch (mes[i].sd_state) {
 1157                                 case MLX_SYSD_OFFLINE:
 1158                                         statestr = "offline";
 1159                                         break;
 1160 
 1161                                 case MLX_SYSD_ONLINE:
 1162                                         statestr = "online";
 1163                                         break;
 1164 
 1165                                 case MLX_SYSD_CRITICAL:
 1166                                         statestr = "critical";
 1167                                         break;
 1168 
 1169                                 default:
 1170                                         statestr = "unknown";
 1171                                         break;
 1172                                 }
 1173 
 1174                                 printf("%s: unit %d %s\n", device_xname(&mlx->mlx_dv),
 1175                                     i, statestr);
 1176 
 1177                                 /* Save new state. */
 1178                                 dr->ms_state = mes[i].sd_state;
 1179                         }
 1180                 }
 1181                 break;
 1182 
 1183 #ifdef DIAGNOSTIC
 1184         default:
 1185                 printf("%s: mlx_periodic_enquiry: eh?\n",
 1186                     device_xname(&mlx->mlx_dv));
 1187                 break;
 1188 #endif
 1189         }
 1190 
 1191  out:
 1192         if (mc->mc_mbox[0] == MLX_CMD_ENQSYSDRIVE)
 1193                 mlx->mlx_flags &= ~MLXF_PERIODIC_DRIVE;
 1194         else
 1195                 mlx->mlx_flags &= ~MLXF_PERIODIC_CTLR;
 1196 
 1197         free(mc->mc_mx.mx_context, M_DEVBUF);
 1198         mlx_ccb_free(mlx, mc);
 1199 }
 1200 
 1201 /*
 1202  * Instigate a poll for one event log message on (mlx).  We only poll for
 1203  * one message at a time, to keep our command usage down.
 1204  */
 1205 static void
 1206 mlx_periodic_eventlog_poll(struct mlx_softc *mlx)
 1207 {
 1208         struct mlx_ccb *mc;
 1209         void *result;
 1210         int rv;
 1211 
 1212         result = NULL;
 1213 
 1214         if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0)
 1215                 goto out;
 1216 
 1217         if ((result = malloc(1024, M_DEVBUF, M_WAITOK)) == NULL) {
 1218                 rv = ENOMEM;
 1219                 goto out;
 1220         }
 1221         if ((rv = mlx_ccb_map(mlx, mc, result, 1024, MC_XFER_IN)) != 0)
 1222                 goto out;
 1223         if (mc->mc_nsgent != 1) {
 1224                 mlx_ccb_unmap(mlx, mc);
 1225                 printf("mlx_periodic_eventlog_poll: too many segs\n");
 1226                 goto out;
 1227         }
 1228 
 1229         /* Build the command to get one log entry. */
 1230         mlx_make_type3(mc, MLX_CMD_LOGOP, MLX_LOGOP_GET, 1,
 1231             mlx->mlx_lastevent, 0, 0, mc->mc_xfer_phys, 0);
 1232 
 1233         mc->mc_mx.mx_handler = mlx_periodic_eventlog_respond;
 1234         mc->mc_mx.mx_dv = &mlx->mlx_dv;
 1235         mc->mc_mx.mx_context = result;
 1236 
 1237         /* Start the command. */
 1238         mlx_ccb_enqueue(mlx, mc);
 1239 
 1240  out:
 1241         if (rv != 0) {
 1242                 if (mc != NULL)
 1243                         mlx_ccb_free(mlx, mc);
 1244                 if (result != NULL)
 1245                         free(result, M_DEVBUF);
 1246         }
 1247 }
 1248 
 1249 /*
 1250  * Handle the result of polling for a log message, generate diagnostic
 1251  * output.  If this wasn't the last message waiting for us, we'll go collect
 1252  * another.
 1253  */
 1254 static void
 1255 mlx_periodic_eventlog_respond(struct mlx_ccb *mc)
 1256 {
 1257         struct mlx_softc *mlx;
 1258         struct mlx_eventlog_entry *el;
 1259         const char *reason;
 1260         u_int8_t sensekey, chan, targ;
 1261 
 1262         mlx = (struct mlx_softc *)mc->mc_mx.mx_dv;
 1263         el = mc->mc_mx.mx_context;
 1264         mlx_ccb_unmap(mlx, mc);
 1265 
 1266         mlx->mlx_lastevent++;
 1267 
 1268         if (mc->mc_status == 0) {
 1269                 switch (el->el_type) {
 1270                 case MLX_LOGMSG_SENSE:          /* sense data */
 1271                         sensekey = el->el_sense & 0x0f;
 1272                         chan = (el->el_target >> 4) & 0x0f;
 1273                         targ = el->el_target & 0x0f;
 1274 
 1275                         /*
 1276                          * This is the only sort of message we understand at
 1277                          * the moment.  The tests here are probably
 1278                          * incomplete.
 1279                          */
 1280 
 1281                         /*
 1282                          * Mylex vendor-specific message indicating a drive
 1283                          * was killed?
 1284                          */
 1285                         if (sensekey == 9 && el->el_asc == 0x80) {
 1286                                 if (el->el_asq < sizeof(mlx_sense_msgs) /
 1287                                     sizeof(mlx_sense_msgs[0]))
 1288                                         reason = mlx_sense_msgs[el->el_asq];
 1289                                 else
 1290                                         reason = "for unknown reason";
 1291 
 1292                                 printf("%s: physical drive %d:%d killed %s\n",
 1293                                     device_xname(&mlx->mlx_dv), chan, targ, reason);
 1294                         }
 1295 
 1296                         /*
 1297                          * SCSI drive was reset?
 1298                          */
 1299                         if (sensekey == 6 && el->el_asc == 0x29)
 1300                                 printf("%s: physical drive %d:%d reset\n",
 1301                                     device_xname(&mlx->mlx_dv), chan, targ);
 1302 
 1303                         /*
 1304                          * SCSI drive error?
 1305                          */
 1306                         if (!(sensekey == 0 ||
 1307                             (sensekey == 2 &&
 1308                             el->el_asc == 0x04 &&
 1309                             (el->el_asq == 0x01 || el->el_asq == 0x02)))) {
 1310                                 printf("%s: physical drive %d:%d error log: "
 1311                                     "sense = %d asc = %x asq = %x\n",
 1312                                     device_xname(&mlx->mlx_dv), chan, targ, sensekey,
 1313                                     el->el_asc, el->el_asq);
 1314                                 printf("%s:   info = %d:%d:%d:%d "
 1315                                     " csi = %d:%d:%d:%d\n",
 1316                                     device_xname(&mlx->mlx_dv),
 1317                                     el->el_information[0],
 1318                                     el->el_information[1],
 1319                                     el->el_information[2],
 1320                                     el->el_information[3],
 1321                                     el->el_csi[0], el->el_csi[1],
 1322                                     el->el_csi[2], el->el_csi[3]);
 1323                         }
 1324 
 1325                         break;
 1326 
 1327                 default:
 1328                         aprint_error_dev(&mlx->mlx_dv, "unknown log message type 0x%x\n",
 1329                             el->el_type);
 1330                         break;
 1331                 }
 1332         } else {
 1333                 aprint_error_dev(&mlx->mlx_dv, "error reading message log - %s\n",
 1334                     mlx_ccb_diagnose(mc));
 1335 
 1336                 /*
 1337                  * Give up on all the outstanding messages, as we may have
 1338                  * come unsynched.
 1339                  */
 1340                 mlx->mlx_lastevent = mlx->mlx_currevent;
 1341         }
 1342 
 1343         free(mc->mc_mx.mx_context, M_DEVBUF);
 1344         mlx_ccb_free(mlx, mc);
 1345 
 1346         /*
 1347          * Is there another message to obtain?
 1348          */
 1349         if (mlx->mlx_lastevent != mlx->mlx_currevent)
 1350                 mlx_periodic_eventlog_poll(mlx);
 1351         else
 1352                 mlx->mlx_flags &= ~MLXF_EVENTLOG_BUSY;
 1353 }
 1354 
 1355 /*
 1356  * Handle check/rebuild operations in progress.
 1357  */
 1358 static void
 1359 mlx_periodic_rebuild(struct mlx_ccb *mc)
 1360 {
 1361         struct mlx_softc *mlx;
 1362         const char *opstr;
 1363         struct mlx_rebuild_status *mr;
 1364 
 1365         mlx = (struct mlx_softc *)mc->mc_mx.mx_dv;
 1366         mr = mc->mc_mx.mx_context;
 1367         mlx_ccb_unmap(mlx, mc);
 1368 
 1369         switch (mc->mc_status) {
 1370         case 0:
 1371                 /*
 1372                  * Operation running, update stats.
 1373                  */
 1374                 mlx->mlx_rebuildstat = *mr;
 1375 
 1376                 /* Spontaneous rebuild/check? */
 1377                 if (mlx->mlx_bg == 0) {
 1378                         mlx->mlx_bg = MLX_BG_SPONTANEOUS;
 1379                         printf("%s: background check/rebuild started\n",
 1380                             device_xname(&mlx->mlx_dv));
 1381                 }
 1382                 break;
 1383 
 1384         case 0x0105:
 1385                 /*
 1386                  * Nothing running, finalise stats and report.
 1387                  */
 1388                 switch (mlx->mlx_bg) {
 1389                 case MLX_BG_CHECK:
 1390                         /* XXX Print drive? */
 1391                         opstr = "consistency check";
 1392                         break;
 1393 
 1394                 case MLX_BG_REBUILD:
 1395                         /* XXX Print channel:target? */
 1396                         opstr = "drive rebuild";
 1397                         break;
 1398 
 1399                 case MLX_BG_SPONTANEOUS:
 1400                 default:
 1401                         /*
 1402                          * If we have previously been non-idle, report the
 1403                          * transition
 1404                          */
 1405                         if (mlx->mlx_rebuildstat.rs_code !=
 1406                             MLX_REBUILDSTAT_IDLE)
 1407                                 opstr = "background check/rebuild";
 1408                         else
 1409                                 opstr = NULL;
 1410                 }
 1411 
 1412                 if (opstr != NULL)
 1413                         printf("%s: %s completed\n", device_xname(&mlx->mlx_dv),
 1414                             opstr);
 1415 
 1416                 mlx->mlx_bg = 0;
 1417                 mlx->mlx_rebuildstat.rs_code = MLX_REBUILDSTAT_IDLE;
 1418                 break;
 1419         }
 1420 
 1421         free(mc->mc_mx.mx_context, M_DEVBUF);
 1422         mlx_ccb_free(mlx, mc);
 1423         mlx->mlx_flags &= ~MLXF_PERIODIC_REBUILD;
 1424 }
 1425 
 1426 /*
 1427  * It's time to perform a channel pause action for (mlx), either start or
 1428  * stop the pause.
 1429  */
 1430 static void
 1431 mlx_pause_action(struct mlx_softc *mlx)
 1432 {
 1433         struct mlx_ccb *mc;
 1434         int failsafe, i, cmd;
 1435 
 1436         /* What are we doing here? */
 1437         if (mlx->mlx_pause.mp_when == 0) {
 1438                 cmd = MLX_CMD_STARTCHANNEL;
 1439                 failsafe = 0;
 1440         } else {
 1441                 cmd = MLX_CMD_STOPCHANNEL;
 1442 
 1443                 /*
 1444                  * Channels will always start again after the failsafe
 1445                  * period, which is specified in multiples of 30 seconds.
 1446                  * This constrains us to a maximum pause of 450 seconds.
 1447                  */
 1448                 failsafe = ((mlx->mlx_pause.mp_howlong - time_second) + 5) / 30;
 1449 
 1450                 if (failsafe > 0xf) {
 1451                         failsafe = 0xf;
 1452                         mlx->mlx_pause.mp_howlong =
 1453                              time_second + (0xf * 30) - 5;
 1454                 }
 1455         }
 1456 
 1457         /* Build commands for every channel requested. */
 1458         for (i = 0; i < mlx->mlx_ci.ci_nchan; i++) {
 1459                 if ((1 << i) & mlx->mlx_pause.mp_which) {
 1460                         if (mlx_ccb_alloc(mlx, &mc, 1) != 0) {
 1461                                 aprint_error_dev(&mlx->mlx_dv, "%s failed for channel %d\n",
 1462                                     cmd == MLX_CMD_STOPCHANNEL ?
 1463                                     "pause" : "resume", i);
 1464                                 continue;
 1465                         }
 1466 
 1467                         /* Build the command. */
 1468                         mlx_make_type2(mc, cmd, (failsafe << 4) | i, 0, 0,
 1469                             0, 0, 0, 0, 0);
 1470                         mc->mc_mx.mx_handler = mlx_pause_done;
 1471                         mc->mc_mx.mx_dv = &mlx->mlx_dv;
 1472 
 1473                         mlx_ccb_enqueue(mlx, mc);
 1474                 }
 1475         }
 1476 }
 1477 
 1478 static void
 1479 mlx_pause_done(struct mlx_ccb *mc)
 1480 {
 1481         struct mlx_softc *mlx;
 1482         int command, channel;
 1483 
 1484         mlx = (struct mlx_softc *)mc->mc_mx.mx_dv;
 1485         command = mc->mc_mbox[0];
 1486         channel = mc->mc_mbox[2] & 0xf;
 1487 
 1488         if (mc->mc_status != 0)
 1489                 aprint_error_dev(&mlx->mlx_dv, "%s command failed - %s\n",
 1490                     command == MLX_CMD_STOPCHANNEL ? "pause" : "resume",
 1491                     mlx_ccb_diagnose(mc));
 1492         else if (command == MLX_CMD_STOPCHANNEL)
 1493                 printf("%s: channel %d pausing for %ld seconds\n",
 1494                     device_xname(&mlx->mlx_dv), channel,
 1495                     (long)(mlx->mlx_pause.mp_howlong - time_second));
 1496         else
 1497                 printf("%s: channel %d resuming\n", device_xname(&mlx->mlx_dv),
 1498                     channel);
 1499 
 1500         mlx_ccb_free(mlx, mc);
 1501 }
 1502 
 1503 /*
 1504  * Perform an Enquiry command using a type-3 command buffer and a return a
 1505  * single linear result buffer.  If the completion function is specified, it
 1506  * will be called with the completed command (and the result response will
 1507  * not be valid until that point).  Otherwise, the command will either be
 1508  * busy-waited for (interrupts must be blocked), or slept for.
 1509  */
 1510 static void *
 1511 mlx_enquire(struct mlx_softc *mlx, int command, size_t bufsize,
 1512             void (*handler)(struct mlx_ccb *mc), int waitok)
 1513 {
 1514         struct mlx_ccb *mc;
 1515         void *result;
 1516         int rv, mapped;
 1517 
 1518         result = NULL;
 1519         mapped = 0;
 1520 
 1521         if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0)
 1522                 goto out;
 1523 
 1524         result = malloc(bufsize, M_DEVBUF, waitok ? M_WAITOK : M_NOWAIT);
 1525         if (result == NULL) {
 1526                 printf("mlx_enquire: malloc() failed\n");
 1527                 goto out;
 1528         }
 1529         if ((rv = mlx_ccb_map(mlx, mc, result, bufsize, MC_XFER_IN)) != 0)
 1530                 goto out;
 1531         mapped = 1;
 1532         if (mc->mc_nsgent != 1) {
 1533                 printf("mlx_enquire: too many segs\n");
 1534                 goto out;
 1535         }
 1536 
 1537         /* Build an enquiry command. */
 1538         mlx_make_type2(mc, command, 0, 0, 0, 0, 0, 0, mc->mc_xfer_phys, 0);
 1539 
 1540         /* Do we want a completion callback? */
 1541         if (handler != NULL) {
 1542                 mc->mc_mx.mx_context = result;
 1543                 mc->mc_mx.mx_dv = &mlx->mlx_dv;
 1544                 mc->mc_mx.mx_handler = handler;
 1545                 mlx_ccb_enqueue(mlx, mc);
 1546         } else {
 1547                 /* Run the command in either polled or wait mode. */
 1548                 if (waitok)
 1549                         rv = mlx_ccb_wait(mlx, mc);
 1550                 else
 1551                         rv = mlx_ccb_poll(mlx, mc, 5000);
 1552         }
 1553 
 1554  out:
 1555         /* We got a command, but nobody else will free it. */
 1556         if (handler == NULL && mc != NULL) {
 1557                 if (mapped)
 1558                         mlx_ccb_unmap(mlx, mc);
 1559                 mlx_ccb_free(mlx, mc);
 1560         }
 1561 
 1562         /* We got an error, and we allocated a result. */
 1563         if (rv != 0 && result != NULL) {
 1564                 if (mc != NULL)
 1565                         mlx_ccb_free(mlx, mc);
 1566                 free(result, M_DEVBUF);
 1567                 result = NULL;
 1568         }
 1569 
 1570         return (result);
 1571 }
 1572 
 1573 /*
 1574  * Perform a Flush command on the nominated controller.
 1575  *
 1576  * May be called with interrupts enabled or disabled; will not return until
 1577  * the flush operation completes or fails.
 1578  */
 1579 int
 1580 mlx_flush(struct mlx_softc *mlx, int async)
 1581 {
 1582         struct mlx_ccb *mc;
 1583         int rv;
 1584 
 1585         if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0)
 1586                 goto out;
 1587 
 1588         /* Build a flush command and fire it off. */
 1589         mlx_make_type2(mc, MLX_CMD_FLUSH, 0, 0, 0, 0, 0, 0, 0, 0);
 1590 
 1591         if (async)
 1592                 rv = mlx_ccb_wait(mlx, mc);
 1593         else
 1594                 rv = mlx_ccb_poll(mlx, mc, MLX_TIMEOUT * 1000);
 1595         if (rv != 0)
 1596                 goto out;
 1597 
 1598         /* Command completed OK? */
 1599         if (mc->mc_status != 0) {
 1600                 aprint_error_dev(&mlx->mlx_dv, "FLUSH failed - %s\n",
 1601                     mlx_ccb_diagnose(mc));
 1602                 rv = EIO;
 1603         }
 1604  out:
 1605         if (mc != NULL)
 1606                 mlx_ccb_free(mlx, mc);
 1607 
 1608         return (rv);
 1609 }
 1610 
 1611 /*
 1612  * Start a background consistency check on (drive).
 1613  */
 1614 static int
 1615 mlx_check(struct mlx_softc *mlx, int drive)
 1616 {
 1617         struct mlx_ccb *mc;
 1618         int rv;
 1619 
 1620         /* Get ourselves a command buffer. */
 1621         rv = 0x10000;
 1622 
 1623         if (mlx_ccb_alloc(mlx, &mc, 1) != 0)
 1624                 goto out;
 1625 
 1626         /* Build a checkasync command, set the "fix it" flag. */
 1627         mlx_make_type2(mc, MLX_CMD_CHECKASYNC, 0, 0, 0, 0, 0, drive | 0x80,
 1628             0, 0);
 1629 
 1630         /* Start the command and wait for it to be returned. */
 1631         if (mlx_ccb_wait(mlx, mc) != 0)
 1632                 goto out;
 1633 
 1634         /* Command completed OK? */
 1635         if (mc->mc_status != 0)
 1636                 aprint_error_dev(&mlx->mlx_dv, "CHECK ASYNC failed - %s\n",
 1637                     mlx_ccb_diagnose(mc));
 1638         else
 1639                 printf("%s: consistency check started",
 1640                     device_xname(mlx->mlx_sysdrive[drive].ms_dv));
 1641 
 1642         rv = mc->mc_status;
 1643  out:
 1644         if (mc != NULL)
 1645                 mlx_ccb_free(mlx, mc);
 1646 
 1647         return (rv);
 1648 }
 1649 
 1650 /*
 1651  * Start a background rebuild of the physical drive at (channel),(target).
 1652  *
 1653  * May be called with interrupts enabled or disabled; will return as soon as
 1654  * the operation has started or been refused.
 1655  */
 1656 static int
 1657 mlx_rebuild(struct mlx_softc *mlx, int channel, int target)
 1658 {
 1659         struct mlx_ccb *mc;
 1660         int error;
 1661 
 1662         error = 0x10000;
 1663         if (mlx_ccb_alloc(mlx, &mc, 1) != 0)
 1664                 goto out;
 1665 
 1666         /* Build a rebuildasync command, set the "fix it" flag. */
 1667         mlx_make_type2(mc, MLX_CMD_REBUILDASYNC, channel, target, 0, 0, 0, 0,
 1668             0, 0);
 1669 
 1670         /* Start the command and wait for it to be returned. */
 1671         if (mlx_ccb_wait(mlx, mc) != 0)
 1672                 goto out;
 1673 
 1674         /* Command completed OK? */
 1675         aprint_normal_dev(&mlx->mlx_dv, "");
 1676         if (mc->mc_status != 0)
 1677                 printf("REBUILD ASYNC failed - %s\n", mlx_ccb_diagnose(mc));
 1678         else
 1679                 printf("rebuild started for %d:%d\n", channel, target);
 1680 
 1681         error = mc->mc_status;
 1682 
 1683  out:
 1684         if (mc != NULL)
 1685                 mlx_ccb_free(mlx, mc);
 1686 
 1687         return (error);
 1688 }
 1689 
 1690 /*
 1691  * Take a command from user-space and try to run it.
 1692  *
 1693  * XXX Note that this can't perform very much in the way of error checking,
 1694  * XXX and as such, applications _must_ be considered trustworthy.
 1695  *
 1696  * XXX Commands using S/G for data are not supported.
 1697  */
 1698 static int
 1699 mlx_user_command(struct mlx_softc *mlx, struct mlx_usercommand *mu)
 1700 {
 1701         struct mlx_ccb *mc;
 1702         struct mlx_dcdb *dcdb;
 1703         void *kbuf;
 1704         int rv, mapped;
 1705 
 1706         if ((mu->mu_bufdir & ~MU_XFER_MASK) != 0)
 1707                 return (EINVAL);
 1708 
 1709         kbuf = NULL;
 1710         dcdb = NULL;
 1711         mapped = 0;
 1712 
 1713         /* Get ourselves a command and copy in from user space. */
 1714         if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0) {
 1715                 DPRINTF(("mlx_user_command: mlx_ccb_alloc = %d\n", rv));
 1716                 goto out;
 1717         }
 1718 
 1719         memcpy(mc->mc_mbox, mu->mu_command, sizeof(mc->mc_mbox));
 1720 
 1721         /*
 1722          * If we need a buffer for data transfer, allocate one and copy in
 1723          * its initial contents.
 1724          */
 1725         if (mu->mu_datasize > 0) {
 1726                 if (mu->mu_datasize > MAXPHYS)
 1727                         return (EINVAL);
 1728 
 1729                 kbuf = malloc(mu->mu_datasize, M_DEVBUF, M_WAITOK);
 1730                 if (kbuf == NULL) {
 1731                         DPRINTF(("mlx_user_command: malloc = NULL\n"));
 1732                         rv = ENOMEM;
 1733                         goto out;
 1734                 }
 1735 
 1736                 if ((mu->mu_bufdir & MU_XFER_OUT) != 0) {
 1737                         rv = copyin(mu->mu_buf, kbuf, mu->mu_datasize);
 1738                         if (rv != 0) {
 1739                                 DPRINTF(("mlx_user_command: copyin = %d\n",
 1740                                     rv));
 1741                                 goto out;
 1742                         }
 1743                 }
 1744 
 1745                 /* Map the buffer so the controller can see it. */
 1746                 rv = mlx_ccb_map(mlx, mc, kbuf, mu->mu_datasize, mu->mu_bufdir);
 1747                 if (rv != 0) {
 1748                         DPRINTF(("mlx_user_command: mlx_ccb_map = %d\n", rv));
 1749                         goto out;
 1750                 }
 1751                 if (mc->mc_nsgent > 1) {
 1752                         DPRINTF(("mlx_user_command: too many s/g entries\n"));
 1753                         rv = EFBIG;
 1754                         goto out;
 1755                 }
 1756                 mapped = 1;
 1757                 /*
 1758                  * If this is a passthrough SCSI command, the DCDB is packed at
 1759                  * the beginning of the data area.  Fix up the DCDB to point to
 1760                  * the correct physical address and override any bufptr
 1761                  * supplied by the caller since we know what it's meant to be.
 1762                  */
 1763                 if (mc->mc_mbox[0] == MLX_CMD_DIRECT_CDB) {
 1764                         dcdb = (struct mlx_dcdb *)kbuf;
 1765                         dcdb->dcdb_physaddr = mc->mc_xfer_phys + sizeof(*dcdb);
 1766                         mu->mu_bufptr = 8;
 1767                 }
 1768         }
 1769 
 1770 
 1771         /*
 1772          * If there's a data buffer, fix up the command's buffer pointer.
 1773          */
 1774         if (mu->mu_datasize > 0) {
 1775                 /* Range check the pointer to physical buffer address. */
 1776                 if (mu->mu_bufptr < 0 ||
 1777                     mu->mu_bufptr > sizeof(mu->mu_command) - 4) {
 1778                         DPRINTF(("mlx_user_command: bufptr botch\n"));
 1779                         rv = EINVAL;
 1780                         goto out;
 1781                 }
 1782 
 1783                 mc->mc_mbox[mu->mu_bufptr] = mc->mc_xfer_phys;
 1784                 mc->mc_mbox[mu->mu_bufptr+1] = mc->mc_xfer_phys >> 8;
 1785                 mc->mc_mbox[mu->mu_bufptr+2] = mc->mc_xfer_phys >> 16;
 1786                 mc->mc_mbox[mu->mu_bufptr+3] = mc->mc_xfer_phys >> 24;
 1787         }
 1788 
 1789         /* Submit the command and wait. */
 1790         if ((rv = mlx_ccb_wait(mlx, mc)) != 0) {
 1791 #ifdef DEBUG
 1792                 printf("mlx_user_command: mlx_ccb_wait = %d\n", rv);
 1793 #endif
 1794         }
 1795 
 1796  out:
 1797         if (mc != NULL) {
 1798                 /* Copy out status and data */
 1799                 mu->mu_status = mc->mc_status;
 1800                 if (mapped)
 1801                         mlx_ccb_unmap(mlx, mc);
 1802                 mlx_ccb_free(mlx, mc);
 1803         }
 1804 
 1805         if (kbuf != NULL) {
 1806                 if (mu->mu_datasize > 0 && (mu->mu_bufdir & MU_XFER_IN) != 0) {
 1807                         rv = copyout(kbuf, mu->mu_buf, mu->mu_datasize);
 1808 #ifdef DIAGNOSTIC
 1809                         if (rv != 0)
 1810                                 printf("mlx_user_command: copyout = %d\n", rv);
 1811 #endif
 1812                 }
 1813         }
 1814         if (kbuf != NULL)
 1815                 free(kbuf, M_DEVBUF);
 1816 
 1817         return (rv);
 1818 }
 1819 
 1820 /*
 1821  * Allocate and initialise a CCB.
 1822  */
 1823 int
 1824 mlx_ccb_alloc(struct mlx_softc *mlx, struct mlx_ccb **mcp, int control)
 1825 {
 1826         struct mlx_ccb *mc;
 1827         int s;
 1828 
 1829         s = splbio();
 1830         mc = SLIST_FIRST(&mlx->mlx_ccb_freelist);
 1831         if (control) {
 1832                 if (mlx->mlx_nccbs_ctrl >= MLX_NCCBS_CONTROL) {
 1833                         splx(s);
 1834                         *mcp = NULL;
 1835                         return (EAGAIN);
 1836                 }
 1837                 mc->mc_flags |= MC_CONTROL;
 1838                 mlx->mlx_nccbs_ctrl++;
 1839         }
 1840         SLIST_REMOVE_HEAD(&mlx->mlx_ccb_freelist, mc_chain.slist);
 1841         splx(s);
 1842 
 1843         *mcp = mc;
 1844         return (0);
 1845 }
 1846 
 1847 /*
 1848  * Free a CCB.
 1849  */
 1850 void
 1851 mlx_ccb_free(struct mlx_softc *mlx, struct mlx_ccb *mc)
 1852 {
 1853         int s;
 1854 
 1855         s = splbio();
 1856         if ((mc->mc_flags & MC_CONTROL) != 0)
 1857                 mlx->mlx_nccbs_ctrl--;
 1858         mc->mc_flags = 0;
 1859         SLIST_INSERT_HEAD(&mlx->mlx_ccb_freelist, mc, mc_chain.slist);
 1860         splx(s);
 1861 }
 1862 
 1863 /*
 1864  * If a CCB is specified, enqueue it.  Pull CCBs off the software queue in
 1865  * the order that they were enqueued and try to submit their mailboxes to
 1866  * the controller for execution.
 1867  */
 1868 void
 1869 mlx_ccb_enqueue(struct mlx_softc *mlx, struct mlx_ccb *mc)
 1870 {
 1871         int s;
 1872 
 1873         s = splbio();
 1874 
 1875         if (mc != NULL)
 1876                 SIMPLEQ_INSERT_TAIL(&mlx->mlx_ccb_queue, mc, mc_chain.simpleq);
 1877 
 1878         while ((mc = SIMPLEQ_FIRST(&mlx->mlx_ccb_queue)) != NULL) {
 1879                 if (mlx_ccb_submit(mlx, mc) != 0)
 1880                         break;
 1881                 SIMPLEQ_REMOVE_HEAD(&mlx->mlx_ccb_queue, mc_chain.simpleq);
 1882                 TAILQ_INSERT_TAIL(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq);
 1883         }
 1884 
 1885         splx(s);
 1886 }
 1887 
 1888 /*
 1889  * Map the specified CCB's data buffer onto the bus, and fill the
 1890  * scatter-gather list.
 1891  */
 1892 int
 1893 mlx_ccb_map(struct mlx_softc *mlx, struct mlx_ccb *mc, void *data, int size,
 1894             int dir)
 1895 {
 1896         struct mlx_sgentry *sge;
 1897         int nsegs, i, rv, sgloff;
 1898         bus_dmamap_t xfer;
 1899 
 1900         xfer = mc->mc_xfer_map;
 1901 
 1902         rv = bus_dmamap_load(mlx->mlx_dmat, xfer, data, size, NULL,
 1903             BUS_DMA_NOWAIT | BUS_DMA_STREAMING |
 1904             ((dir & MC_XFER_IN) ? BUS_DMA_READ : BUS_DMA_WRITE));
 1905         if (rv != 0)
 1906                 return (rv);
 1907 
 1908         nsegs = xfer->dm_nsegs;
 1909         mc->mc_xfer_size = size;
 1910         mc->mc_flags |= dir;
 1911         mc->mc_nsgent = nsegs;
 1912         mc->mc_xfer_phys = xfer->dm_segs[0].ds_addr;
 1913 
 1914         sgloff = MLX_SGL_SIZE * mc->mc_ident;
 1915         sge = (struct mlx_sgentry *)((char *)mlx->mlx_sgls + sgloff);
 1916 
 1917         for (i = 0; i < nsegs; i++, sge++) {
 1918                 sge->sge_addr = htole32(xfer->dm_segs[i].ds_addr);
 1919                 sge->sge_count = htole32(xfer->dm_segs[i].ds_len);
 1920         }
 1921 
 1922         if ((dir & MC_XFER_OUT) != 0)
 1923                 i = BUS_DMASYNC_PREWRITE;
 1924         else
 1925                 i = 0;
 1926         if ((dir & MC_XFER_IN) != 0)
 1927                 i |= BUS_DMASYNC_PREREAD;
 1928 
 1929         bus_dmamap_sync(mlx->mlx_dmat, xfer, 0, mc->mc_xfer_size, i);
 1930         bus_dmamap_sync(mlx->mlx_dmat, mlx->mlx_dmamap, sgloff,
 1931             MLX_SGL_SIZE, BUS_DMASYNC_PREWRITE);
 1932 
 1933         return (0);
 1934 }
 1935 
 1936 /*
 1937  * Unmap the specified CCB's data buffer.
 1938  */
 1939 void
 1940 mlx_ccb_unmap(struct mlx_softc *mlx, struct mlx_ccb *mc)
 1941 {
 1942         int i;
 1943 
 1944         bus_dmamap_sync(mlx->mlx_dmat, mlx->mlx_dmamap,
 1945             MLX_SGL_SIZE * mc->mc_ident, MLX_SGL_SIZE,
 1946             BUS_DMASYNC_POSTWRITE);
 1947 
 1948         if ((mc->mc_flags & MC_XFER_OUT) != 0)
 1949                 i = BUS_DMASYNC_POSTWRITE;
 1950         else
 1951                 i = 0;
 1952         if ((mc->mc_flags & MC_XFER_IN) != 0)
 1953                 i |= BUS_DMASYNC_POSTREAD;
 1954 
 1955         bus_dmamap_sync(mlx->mlx_dmat, mc->mc_xfer_map, 0, mc->mc_xfer_size, i);
 1956         bus_dmamap_unload(mlx->mlx_dmat, mc->mc_xfer_map);
 1957 }
 1958 
 1959 /*
 1960  * Submit the CCB, and busy-wait for it to complete.  Return non-zero on
 1961  * timeout or submission error.  Must be called with interrupts blocked.
 1962  */
 1963 int
 1964 mlx_ccb_poll(struct mlx_softc *mlx, struct mlx_ccb *mc, int timo)
 1965 {
 1966         int rv;
 1967 
 1968         mc->mc_mx.mx_handler = NULL;
 1969 
 1970         if ((rv = mlx_ccb_submit(mlx, mc)) != 0)
 1971                 return (rv);
 1972         TAILQ_INSERT_TAIL(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq);
 1973 
 1974         for (timo *= 10; timo != 0; timo--) {
 1975                 mlx_intr(mlx);
 1976                 if (mc->mc_status != MLX_STATUS_BUSY)
 1977                         break;
 1978                 DELAY(100);
 1979         }
 1980 
 1981         if (timo != 0) {
 1982                 if (mc->mc_status != 0) {
 1983                         aprint_error_dev(&mlx->mlx_dv, "command failed - %s\n",
 1984                             mlx_ccb_diagnose(mc));
 1985                         rv = EIO;
 1986                 } else
 1987                         rv = 0;
 1988         } else {
 1989                 printf("%s: command timed out\n", device_xname(&mlx->mlx_dv));
 1990                 rv = EIO;
 1991         }
 1992 
 1993         return (rv);
 1994 }
 1995 
 1996 /*
 1997  * Enqueue the CCB, and sleep until it completes.  Return non-zero on
 1998  * timeout or error.
 1999  */
 2000 int
 2001 mlx_ccb_wait(struct mlx_softc *mlx, struct mlx_ccb *mc)
 2002 {
 2003         int s;
 2004 
 2005         mc->mc_flags |= MC_WAITING;
 2006         mc->mc_mx.mx_handler = NULL;
 2007 
 2008         s = splbio();
 2009         mlx_ccb_enqueue(mlx, mc);
 2010         tsleep(mc, PRIBIO, "mlxwccb", 0);
 2011         splx(s);
 2012 
 2013         if (mc->mc_status != 0) {
 2014                 aprint_error_dev(&mlx->mlx_dv, "command failed - %s\n",
 2015                     mlx_ccb_diagnose(mc));
 2016                 return (EIO);
 2017         }
 2018 
 2019         return (0);
 2020 }
 2021 
 2022 /*
 2023  * Try to submit a CCB's mailbox to the controller for execution.  Return
 2024  * non-zero on timeout or error.  Must be called with interrupts blocked.
 2025  */
 2026 static int
 2027 mlx_ccb_submit(struct mlx_softc *mlx, struct mlx_ccb *mc)
 2028 {
 2029         int i, s, r;
 2030 
 2031         /* Save the ident so we can handle this command when complete. */
 2032         mc->mc_mbox[1] = (u_int8_t)(mc->mc_ident + 1);
 2033 
 2034         /* Mark the command as currently being processed. */
 2035         mc->mc_status = MLX_STATUS_BUSY;
 2036         mc->mc_expiry = time_second + MLX_TIMEOUT;
 2037 
 2038         /* Spin waiting for the mailbox. */
 2039         for (i = 100; i != 0; i--) {
 2040                 s = splbio();
 2041                 r = (*mlx->mlx_submit)(mlx, mc);
 2042                 splx(s);
 2043                 if (r != 0)
 2044                         break;
 2045                 DELAY(100);
 2046         }
 2047         if (i != 0)
 2048                 return (0);
 2049 
 2050         DPRINTF(("mlx_ccb_submit: rejected; queueing\n"));
 2051         mc->mc_status = MLX_STATUS_WEDGED;
 2052         return (EIO);
 2053 }
 2054 
 2055 /*
 2056  * Return a string that describes why a command has failed.
 2057  */
 2058 const char *
 2059 mlx_ccb_diagnose(struct mlx_ccb *mc)
 2060 {
 2061         static char tbuf[80];
 2062         int i;
 2063 
 2064         for (i = 0; i < sizeof(mlx_msgs) / sizeof(mlx_msgs[0]); i++)
 2065                 if ((mc->mc_mbox[0] == mlx_msgs[i].command ||
 2066                     mlx_msgs[i].command == 0) &&
 2067                     mc->mc_status == mlx_msgs[i].status) {
 2068                         snprintf(tbuf, sizeof(tbuf), "%s (0x%x)",
 2069                             mlx_status_msgs[mlx_msgs[i].msg], mc->mc_status);
 2070                         return (tbuf);
 2071                 }
 2072 
 2073         snprintf(tbuf, sizeof(tbuf), "unknown response 0x%x for command 0x%x",
 2074             (int)mc->mc_status, (int)mc->mc_mbox[0]);
 2075 
 2076         return (tbuf);
 2077 }
 2078 
 2079 /*
 2080  * Poll the controller for completed commands.  Returns non-zero if one or
 2081  * more commands were completed.  Must be called with interrupts blocked.
 2082  */
 2083 int
 2084 mlx_intr(void *cookie)
 2085 {
 2086         struct mlx_softc *mlx;
 2087         struct mlx_ccb *mc;
 2088         int result;
 2089         u_int ident, status;
 2090 
 2091         mlx = cookie;
 2092         result = 0;
 2093 
 2094         while ((*mlx->mlx_findcomplete)(mlx, &ident, &status) != 0) {
 2095                 result = 1;
 2096                 ident--;
 2097 
 2098                 if (ident >= MLX_MAX_QUEUECNT) {
 2099                         aprint_error_dev(&mlx->mlx_dv, "bad completion returned\n");
 2100                         continue;
 2101                 }
 2102 
 2103                 mc = mlx->mlx_ccbs + ident;
 2104 
 2105                 if (mc->mc_status != MLX_STATUS_BUSY) {
 2106                         aprint_error_dev(&mlx->mlx_dv, "bad completion returned\n");
 2107                         continue;
 2108                 }
 2109 
 2110                 TAILQ_REMOVE(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq);
 2111 
 2112                 /* Record status and notify the initiator, if requested. */
 2113                 mc->mc_status = status;
 2114                 if (mc->mc_mx.mx_handler != NULL)
 2115                         (*mc->mc_mx.mx_handler)(mc);
 2116                 else if ((mc->mc_flags & MC_WAITING) != 0)
 2117                         wakeup(mc);
 2118         }
 2119 
 2120         /* If we've completed any commands, try posting some more. */
 2121         if (result)
 2122                 mlx_ccb_enqueue(mlx, NULL);
 2123 
 2124         return (result);
 2125 }
 2126 
 2127 /*
 2128  * Emit a string describing the firmware handshake status code, and return a
 2129  * flag indicating whether the code represents a fatal error.
 2130  *
 2131  * Error code interpretations are from the Linux driver, and don't directly
 2132  * match the messages printed by Mylex's BIOS.  This may change if
 2133  * documentation on the codes is forthcoming.
 2134  */
 2135 static int
 2136 mlx_fw_message(struct mlx_softc *mlx, int error, int param1, int param2)
 2137 {
 2138         const char *fmt;
 2139 
 2140         switch (error) {
 2141         case 0x00:
 2142                 fmt = "physical drive %d:%d not responding";
 2143                 break;
 2144 
 2145         case 0x08:
 2146                 /*
 2147                  * We could be neater about this and give some indication
 2148                  * when we receive more of them.
 2149                  */
 2150                 if ((mlx->mlx_flags & MLXF_SPINUP_REPORTED) == 0) {
 2151                         printf("%s: spinning up drives...\n",
 2152                             device_xname(&mlx->mlx_dv));
 2153                         mlx->mlx_flags |= MLXF_SPINUP_REPORTED;
 2154                 }
 2155                 return (0);
 2156 
 2157         case 0x30:
 2158                 fmt = "configuration checksum error";
 2159                 break;
 2160 
 2161         case 0x60:
 2162                 fmt = "mirror race recovery failed";
 2163                 break;
 2164 
 2165         case 0x70:
 2166                 fmt = "mirror race recovery in progress";
 2167                 break;
 2168 
 2169         case 0x90:
 2170                 fmt = "physical drive %d:%d COD mismatch";
 2171                 break;
 2172 
 2173         case 0xa0:
 2174                 fmt = "logical drive installation aborted";
 2175                 break;
 2176 
 2177         case 0xb0:
 2178                 fmt = "mirror race on a critical system drive";
 2179                 break;
 2180 
 2181         case 0xd0:
 2182                 fmt = "new controller configuration found";
 2183                 break;
 2184 
 2185         case 0xf0:
 2186                 aprint_error_dev(&mlx->mlx_dv, "FATAL MEMORY PARITY ERROR\n");
 2187                 return (1);
 2188 
 2189         default:
 2190                 aprint_error_dev(&mlx->mlx_dv, "unknown firmware init error %02x:%02x:%02x\n",
 2191                     error, param1, param2);
 2192                 return (0);
 2193         }
 2194 
 2195         aprint_normal_dev(&mlx->mlx_dv, "");
 2196         aprint_normal(fmt, param2, param1);
 2197         aprint_normal("\n");
 2198 
 2199         return (0);
 2200 }

Cache object: c42a66cb42e65c32ddd083ee690c2af9


[ 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.