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