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

Cache object: 01cef36c8d9aead27fec22bdf2078d29


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