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