Home | History | Annotate | Line # | Download | only in ic
mlx.c revision 1.34
      1 /*	$NetBSD: mlx.c,v 1.34 2005/07/30 17:37:11 mhitch 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.34 2005/07/30 17:37:11 mhitch 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] = '0';
    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 tbuf[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(tbuf, sizeof(tbuf), " model 0x%x", ci->ci_hardware_id);
    554 		model = tbuf;
    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] == '0' + *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 tbuf[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(tbuf, sizeof(tbuf), "%s (0x%x)",
   2142 			    mlx_status_msgs[mlx_msgs[i].msg], mc->mc_status);
   2143 			return (tbuf);
   2144 		}
   2145 
   2146 	snprintf(tbuf, sizeof(tbuf), "unknown response 0x%x for command 0x%x",
   2147 	    (int)mc->mc_status, (int)mc->mc_mbox[0]);
   2148 
   2149 	return (tbuf);
   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 }
   2277