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

Cache object: 5b82b2d857ecf74cbf4f2deee8515802


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