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