1 /* $NetBSD: mlx.c,v 1.57 2008/09/09 12:45:40 tron Exp $ */
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Copyright (c) 1999 Michael Smith
34 * All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * from FreeBSD: mlx.c,v 1.14.2.3 2000/08/04 06:52:50 msmith Exp
61 * Driver for the Mylex DAC960 family of RAID controllers.
65 * o Test and enable channel pause.
66 * o SCSI pass-through.
69 #include <sys/cdefs.h>
70 __KERNEL_RCSID(0, "$NetBSD: mlx.c,v 1.57 2008/09/09 12:45:40 tron Exp $");
74 #include <sys/param.h>
75 #include <sys/systm.h>
76 #include <sys/kernel.h>
77 #include <sys/device.h>
78 #include <sys/queue.h>
82 #include <sys/endian.h>
83 #include <sys/malloc.h>
85 #include <sys/kthread.h>
87 #include <sys/kauth.h>
89 #include <machine/vmparam.h>
92 #include <uvm/uvm_extern.h>
94 #include <dev/ldvar.h>
96 #include <dev/ic/mlxreg.h>
97 #include <dev/ic/mlxio.h>
98 #include <dev/ic/mlxvar.h>
100 #include "locators.h"
102 #define MLX_TIMEOUT 60
105 #define DPRINTF(x) printf x
110 static void mlx_adjqparam(struct mlx_softc
*, int, int);
111 static int mlx_ccb_submit(struct mlx_softc
*, struct mlx_ccb
*);
112 static int mlx_check(struct mlx_softc
*, int);
113 static void mlx_configure(struct mlx_softc
*, int);
114 static void mlx_describe(struct mlx_softc
*);
115 static void *mlx_enquire(struct mlx_softc
*, int, size_t,
116 void (*)(struct mlx_ccb
*), int);
117 static int mlx_fw_message(struct mlx_softc
*, int, int, int);
118 static void mlx_pause_action(struct mlx_softc
*);
119 static void mlx_pause_done(struct mlx_ccb
*);
120 static void mlx_periodic(struct mlx_softc
*);
121 static void mlx_periodic_enquiry(struct mlx_ccb
*);
122 static void mlx_periodic_eventlog_poll(struct mlx_softc
*);
123 static void mlx_periodic_eventlog_respond(struct mlx_ccb
*);
124 static void mlx_periodic_rebuild(struct mlx_ccb
*);
125 static void mlx_periodic_thread(void *);
126 static int mlx_print(void *, const char *);
127 static int mlx_rebuild(struct mlx_softc
*, int, int);
128 static void mlx_shutdown(void *);
129 static int mlx_user_command(struct mlx_softc
*, struct mlx_usercommand
*);
131 dev_type_open(mlxopen
);
132 dev_type_close(mlxclose
);
133 dev_type_ioctl(mlxioctl
);
135 const struct cdevsw mlx_cdevsw
= {
136 mlxopen
, mlxclose
, noread
, nowrite
, mlxioctl
,
137 nostop
, notty
, nopoll
, nommap
, nokqfilter
, D_OTHER
,
140 extern struct cfdriver mlx_cd
;
141 static struct lwp
*mlx_periodic_lwp
;
142 static void *mlx_sdh
;
147 } const mlx_cname
[] = {
148 { 0x00, "960E/960M" },
161 static const char * const mlx_sense_msgs
[] = {
162 "because write recovery failed",
163 "because of SCSI bus reset failure",
164 "because of double check condition",
165 "because it was removed",
166 "because of gross error on SCSI chip",
167 "because of bad tag returned from drive",
168 "because of timeout on SCSI command",
169 "because of reset SCSI command issued from system",
170 "because busy or parity error count exceeded limit",
171 "because of 'kill drive' command from system",
172 "because of selection timeout",
173 "due to SCSI phase sequence error",
174 "due to unknown status"
177 static const char * const mlx_status_msgs
[] = {
178 "normal completion", /* 0 */
179 "irrecoverable data error", /* 1 */
180 "drive does not exist, or is offline", /* 2 */
181 "attempt to write beyond end of drive", /* 3 */
182 "bad data encountered", /* 4 */
183 "invalid log entry request", /* 5 */
184 "attempt to rebuild online drive", /* 6 */
185 "new disk failed during rebuild", /* 7 */
186 "invalid channel/target", /* 8 */
187 "rebuild/check already in progress", /* 9 */
188 "one or more disks are dead", /* 10 */
189 "invalid or non-redundant drive", /* 11 */
190 "channel is busy", /* 12 */
191 "channel is not stopped", /* 13 */
192 "rebuild successfully terminated", /* 14 */
193 "unsupported command", /* 15 */
194 "check condition received", /* 16 */
195 "device is busy", /* 17 */
196 "selection or command timeout", /* 18 */
197 "command terminated abnormally", /* 19 */
198 "controller wedged", /* 20 */
199 "software timeout", /* 21 */
200 "command busy (?)", /* 22 */
205 u_char msg
; /* Index into mlx_status_msgs[]. */
207 } const mlx_msgs
[] = {
208 { MLX_CMD_READSG
, 1, 0x0001 },
209 { MLX_CMD_READSG
, 1, 0x0002 },
210 { MLX_CMD_READSG
, 3, 0x0105 },
211 { MLX_CMD_READSG
, 4, 0x010c },
212 { MLX_CMD_WRITESG
, 1, 0x0001 },
213 { MLX_CMD_WRITESG
, 1, 0x0002 },
214 { MLX_CMD_WRITESG
, 3, 0x0105 },
215 { MLX_CMD_READSG_OLD
, 1, 0x0001 },
216 { MLX_CMD_READSG_OLD
, 1, 0x0002 },
217 { MLX_CMD_READSG_OLD
, 3, 0x0105 },
218 { MLX_CMD_WRITESG_OLD
, 1, 0x0001 },
219 { MLX_CMD_WRITESG_OLD
, 1, 0x0002 },
220 { MLX_CMD_WRITESG_OLD
, 3, 0x0105 },
221 { MLX_CMD_LOGOP
, 5, 0x0105 },
222 { MLX_CMD_REBUILDASYNC
, 6, 0x0002 },
223 { MLX_CMD_REBUILDASYNC
, 7, 0x0004 },
224 { MLX_CMD_REBUILDASYNC
, 8, 0x0105 },
225 { MLX_CMD_REBUILDASYNC
, 9, 0x0106 },
226 { MLX_CMD_REBUILDASYNC
, 14, 0x0107 },
227 { MLX_CMD_CHECKASYNC
, 10, 0x0002 },
228 { MLX_CMD_CHECKASYNC
, 11, 0x0105 },
229 { MLX_CMD_CHECKASYNC
, 9, 0x0106 },
230 { MLX_CMD_STOPCHANNEL
, 12, 0x0106 },
231 { MLX_CMD_STOPCHANNEL
, 8, 0x0105 },
232 { MLX_CMD_STARTCHANNEL
, 13, 0x0005 },
233 { MLX_CMD_STARTCHANNEL
, 8, 0x0105 },
234 { MLX_CMD_DIRECT_CDB
, 16, 0x0002 },
235 { MLX_CMD_DIRECT_CDB
, 17, 0x0008 },
236 { MLX_CMD_DIRECT_CDB
, 18, 0x000e },
237 { MLX_CMD_DIRECT_CDB
, 19, 0x000f },
238 { MLX_CMD_DIRECT_CDB
, 8, 0x0105 },
240 { 0, 20, MLX_STATUS_WEDGED
},
241 { 0, 21, MLX_STATUS_LOST
},
242 { 0, 22, MLX_STATUS_BUSY
},
248 * Initialise the controller and our interface.
251 mlx_init(struct mlx_softc
*mlx
, const char *intrstr
)
254 struct mlx_enquiry_old
*meo
;
255 struct mlx_enquiry2
*me2
;
256 struct mlx_cinfo
*ci
;
257 int rv
, fwminor
, hscode
, hserr
, hsparam1
, hsparam2
, hsmsg
;
259 const char *wantfwstr
;
260 bus_dma_segment_t seg
;
262 SIMPLEQ_INIT(&mlx
->mlx_ccb_queue
);
263 SLIST_INIT(&mlx
->mlx_ccb_freelist
);
264 TAILQ_INIT(&mlx
->mlx_ccb_worklist
);
267 printf("%s: interrupting at %s\n", device_xname(&mlx
->mlx_dv
),
271 * Allocate the scatter/gather lists.
273 size
= MLX_SGL_SIZE
* MLX_MAX_QUEUECNT
;
275 if ((rv
= bus_dmamem_alloc(mlx
->mlx_dmat
, size
, PAGE_SIZE
, 0, &seg
, 1,
276 &rseg
, BUS_DMA_NOWAIT
)) != 0) {
277 aprint_error_dev(&mlx
->mlx_dv
, "unable to allocate sglists, rv = %d\n", rv
);
281 if ((rv
= bus_dmamem_map(mlx
->mlx_dmat
, &seg
, rseg
, size
,
282 (void **)&mlx
->mlx_sgls
,
283 BUS_DMA_NOWAIT
| BUS_DMA_COHERENT
)) != 0) {
284 aprint_error_dev(&mlx
->mlx_dv
, "unable to map sglists, rv = %d\n", rv
);
288 if ((rv
= bus_dmamap_create(mlx
->mlx_dmat
, size
, 1, size
, 0,
289 BUS_DMA_NOWAIT
, &mlx
->mlx_dmamap
)) != 0) {
290 aprint_error_dev(&mlx
->mlx_dv
, "unable to create sglist DMA map, rv = %d\n", rv
);
294 if ((rv
= bus_dmamap_load(mlx
->mlx_dmat
, mlx
->mlx_dmamap
,
295 mlx
->mlx_sgls
, size
, NULL
, BUS_DMA_NOWAIT
)) != 0) {
296 aprint_error_dev(&mlx
->mlx_dv
, "unable to load sglist DMA map, rv = %d\n", rv
);
300 mlx
->mlx_sgls_paddr
= mlx
->mlx_dmamap
->dm_segs
[0].ds_addr
;
301 memset(mlx
->mlx_sgls
, 0, size
);
304 * Allocate and initialize the CCBs.
306 mc
= malloc(sizeof(*mc
) * MLX_MAX_QUEUECNT
, M_DEVBUF
, M_NOWAIT
);
309 for (i
= 0; i
< MLX_MAX_QUEUECNT
; i
++, mc
++) {
311 rv
= bus_dmamap_create(mlx
->mlx_dmat
, MLX_MAX_XFER
,
312 MLX_MAX_SEGS
, MLX_MAX_XFER
, 0,
313 BUS_DMA_NOWAIT
| BUS_DMA_ALLOCNOW
,
318 mlx_ccb_free(mlx
, mc
);
320 if (mlx
->mlx_nccbs
!= MLX_MAX_QUEUECNT
)
321 printf("%s: %d/%d CCBs usable\n", device_xname(&mlx
->mlx_dv
),
322 mlx
->mlx_nccbs
, MLX_MAX_QUEUECNT
);
324 /* Disable interrupts before we start talking to the controller */
325 (*mlx
->mlx_intaction
)(mlx
, 0);
327 /* If we've got a reset routine, then reset the controller now. */
328 if (mlx
->mlx_reset
!= NULL
) {
329 printf("%s: resetting controller...\n", device_xname(&mlx
->mlx_dv
));
330 if ((*mlx
->mlx_reset
)(mlx
) != 0) {
331 aprint_error_dev(&mlx
->mlx_dv
, "reset failed\n");
337 * Wait for the controller to come ready, handshaking with the
338 * firmware if required. This is typically only necessary on
339 * platforms where the controller BIOS does not run.
344 hscode
= (*mlx
->mlx_fw_handshake
)(mlx
, &hserr
, &hsparam1
,
348 printf("%s: initialization complete\n",
349 device_xname(&mlx
->mlx_dv
));
353 /* Report first time around... */
355 printf("%s: initializing (may take some time)...\n",
356 device_xname(&mlx
->mlx_dv
));
360 /* Did we get a real message? */
362 hscode
= mlx_fw_message(mlx
, hserr
, hsparam1
, hsparam2
);
364 /* Fatal initialisation error? */
371 * Do quirk/feature related things.
375 if (ci
->ci_iftype
> 1) {
376 me2
= mlx_enquire(mlx
, MLX_CMD_ENQUIRY2
,
377 sizeof(struct mlx_enquiry2
), NULL
, 0);
379 aprint_error_dev(&mlx
->mlx_dv
, "ENQUIRY2 failed\n");
383 ci
->ci_firmware_id
[0] = me2
->me_firmware_id
[0];
384 ci
->ci_firmware_id
[1] = me2
->me_firmware_id
[1];
385 ci
->ci_firmware_id
[2] = me2
->me_firmware_id
[2];
386 ci
->ci_firmware_id
[3] = me2
->me_firmware_id
[3];
387 ci
->ci_hardware_id
= me2
->me_hardware_id
[0];
388 ci
->ci_mem_size
= le32toh(me2
->me_mem_size
);
389 ci
->ci_max_sg
= le16toh(me2
->me_max_sg
);
390 ci
->ci_max_commands
= le16toh(me2
->me_max_commands
);
391 ci
->ci_nchan
= me2
->me_actual_channels
;
396 if (ci
->ci_iftype
<= 2) {
398 * These controllers may not report the firmware version in
399 * the ENQUIRY2 response, or may not even support it.
401 meo
= mlx_enquire(mlx
, MLX_CMD_ENQUIRY_OLD
,
402 sizeof(struct mlx_enquiry_old
), NULL
, 0);
404 aprint_error_dev(&mlx
->mlx_dv
, "ENQUIRY_OLD failed\n");
407 ci
->ci_firmware_id
[0] = meo
->me_fwmajor
;
408 ci
->ci_firmware_id
[1] = meo
->me_fwminor
;
409 ci
->ci_firmware_id
[2] = 0;
410 ci
->ci_firmware_id
[3] = '0';
412 if (ci
->ci_iftype
== 1) {
413 ci
->ci_hardware_id
= 0; /* XXX */
414 ci
->ci_mem_size
= 0; /* XXX */
415 ci
->ci_max_sg
= 17; /* XXX */
416 ci
->ci_max_commands
= meo
->me_max_commands
;
423 fwminor
= ci
->ci_firmware_id
[1];
425 switch (ci
->ci_firmware_id
[0]) {
427 if (ci
->ci_iftype
== 1) {
430 } else if (fwminor
< 42)
450 /* Print a little information about the controller. */
453 if (wantfwstr
!= NULL
) {
454 printf("%s: WARNING: this f/w revision is not recommended\n",
455 device_xname(&mlx
->mlx_dv
));
456 printf("%s: WARNING: use revision %s or later\n",
457 device_xname(&mlx
->mlx_dv
), wantfwstr
);
460 /* We don't (yet) know where the event log is up to. */
461 mlx
->mlx_currevent
= -1;
463 /* No user-requested background operation is in progress. */
465 mlx
->mlx_rebuildstat
.rs_code
= MLX_REBUILDSTAT_IDLE
;
467 /* Set maximum number of queued commands for `regular' operations. */
468 mlx
->mlx_max_queuecnt
=
469 min(ci
->ci_max_commands
, MLX_MAX_QUEUECNT
) -
472 if (mlx
->mlx_max_queuecnt
< MLX_NCCBS_CONTROL
+ MLX_MAX_DRIVES
)
473 printf("%s: WARNING: few CCBs available\n",
474 device_xname(&mlx
->mlx_dv
));
475 if (ci
->ci_max_sg
< MLX_MAX_SEGS
) {
476 aprint_error_dev(&mlx
->mlx_dv
, "oops, not enough S/G segments\n");
481 /* Attach child devices and enable interrupts. */
482 mlx_configure(mlx
, 0);
483 (*mlx
->mlx_intaction
)(mlx
, 1);
484 mlx
->mlx_flags
|= MLXF_INITOK
;
486 if (mlx_sdh
== NULL
) {
488 * Set our `shutdownhook' before we start any device
491 mlx_sdh
= shutdownhook_establish(mlx_shutdown
, NULL
);
493 /* Create a status monitoring thread. */
494 rv
= kthread_create(PRI_NONE
, 0, NULL
, mlx_periodic_thread
,
495 NULL
, &mlx_periodic_lwp
, "mlxtask");
497 printf("mlx_init: unable to create thread (%d)\n", rv
);
502 * Tell the world about the controller.
505 mlx_describe(struct mlx_softc
*mlx
)
507 struct mlx_cinfo
*ci
;
508 static char tbuf
[80];
515 for (i
= 0; i
< sizeof(mlx_cname
) / sizeof(mlx_cname
[0]); i
++)
516 if (ci
->ci_hardware_id
== mlx_cname
[i
].hwid
) {
517 model
= mlx_cname
[i
].name
;
522 snprintf(tbuf
, sizeof(tbuf
), " model 0x%x", ci
->ci_hardware_id
);
526 printf("%s: DAC%s, %d channel%s, firmware %d.%02d-%c-%02d",
527 device_xname(&mlx
->mlx_dv
), model
, ci
->ci_nchan
,
528 ci
->ci_nchan
> 1 ? "s" : "",
529 ci
->ci_firmware_id
[0], ci
->ci_firmware_id
[1],
530 ci
->ci_firmware_id
[3], ci
->ci_firmware_id
[2]);
531 if (ci
->ci_mem_size
!= 0)
532 printf(", %dMB RAM", ci
->ci_mem_size
>> 20);
537 * Locate disk resources and attach children to them.
540 mlx_configure(struct mlx_softc
*mlx
, int waitok
)
542 struct mlx_enquiry
*me
;
543 struct mlx_enquiry_old
*meo
;
544 struct mlx_enq_sys_drive
*mes
;
545 struct mlx_sysdrive
*ms
;
546 struct mlx_attach_args mlxa
;
549 int locs
[MLXCF_NLOCS
];
551 mlx
->mlx_flags
|= MLXF_RESCANNING
;
553 if (mlx
->mlx_ci
.ci_iftype
<= 2) {
554 meo
= mlx_enquire(mlx
, MLX_CMD_ENQUIRY_OLD
,
555 sizeof(struct mlx_enquiry_old
), NULL
, waitok
);
557 aprint_error_dev(&mlx
->mlx_dv
, "ENQUIRY_OLD failed\n");
560 mlx
->mlx_numsysdrives
= meo
->me_num_sys_drvs
;
563 me
= mlx_enquire(mlx
, MLX_CMD_ENQUIRY
,
564 sizeof(struct mlx_enquiry
), NULL
, waitok
);
566 aprint_error_dev(&mlx
->mlx_dv
, "ENQUIRY failed\n");
569 mlx
->mlx_numsysdrives
= me
->me_num_sys_drvs
;
573 mes
= mlx_enquire(mlx
, MLX_CMD_ENQSYSDRIVE
,
574 sizeof(*mes
) * MLX_MAX_DRIVES
, NULL
, waitok
);
576 aprint_error_dev(&mlx
->mlx_dv
, "error fetching drive status\n");
580 /* Allow 1 queued command per unit while re-configuring. */
581 mlx_adjqparam(mlx
, 1, 0);
583 ms
= &mlx
->mlx_sysdrive
[0];
585 for (i
= 0; i
< MLX_MAX_DRIVES
; i
++, ms
++) {
586 size
= le32toh(mes
[i
].sd_size
);
587 ms
->ms_state
= mes
[i
].sd_state
;
590 * If an existing device has changed in some way (e.g. no
591 * longer present) then detach it.
593 if (ms
->ms_dv
!= NULL
&& (size
!= ms
->ms_size
||
594 (mes
[i
].sd_raidlevel
& 0xf) != ms
->ms_raidlevel
))
595 config_detach(ms
->ms_dv
, DETACH_FORCE
);
598 ms
->ms_raidlevel
= mes
[i
].sd_raidlevel
& 0xf;
599 ms
->ms_state
= mes
[i
].sd_state
;
602 if (i
>= mlx
->mlx_numsysdrives
)
604 if (size
== 0xffffffffU
|| size
== 0)
608 * Attach a new device.
612 locs
[MLXCF_UNIT
] = i
;
614 ms
->ms_dv
= config_found_sm_loc(&mlx
->mlx_dv
, "mlx", locs
,
615 &mlxa
, mlx_print
, config_stdsubmatch
);
616 nunits
+= (ms
->ms_dv
!= NULL
);
622 mlx_adjqparam(mlx
, mlx
->mlx_max_queuecnt
/ nunits
,
623 mlx
->mlx_max_queuecnt
% nunits
);
625 mlx
->mlx_flags
&= ~MLXF_RESCANNING
;
629 * Print autoconfiguration message for a sub-device.
632 mlx_print(void *aux
, const char *pnp
)
634 struct mlx_attach_args
*mlxa
;
636 mlxa
= (struct mlx_attach_args
*)aux
;
639 aprint_normal("block device at %s", pnp
);
640 aprint_normal(" unit %d", mlxa
->mlxa_unit
);
645 * Shut down all configured `mlx' devices.
648 mlx_shutdown(void *cookie
)
650 struct mlx_softc
*mlx
;
653 for (i
= 0; i
< mlx_cd
.cd_ndevs
; i
++)
654 if ((mlx
= device_lookup_private(&mlx_cd
, i
)) != NULL
)
659 * Adjust queue parameters for all child devices.
662 mlx_adjqparam(struct mlx_softc
*mlx
, int mpu
, int slop
)
665 extern struct cfdriver ld_cd
;
669 for (i
= 0; i
< ld_cd
.cd_ndevs
; i
++) {
670 if ((ld
= device_lookup_private(&ld_cd
, i
)) == NULL
)
672 if (device_parent(ld
->sc_dv
) != &mlx
->mlx_dv
)
674 ldadjqparam(ld
, mpu
+ (slop
-- > 0));
680 * Accept an open operation on the control device.
683 mlxopen(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
685 struct mlx_softc
*mlx
;
687 if ((mlx
= device_lookup_private(&mlx_cd
, minor(dev
))) == NULL
)
689 if ((mlx
->mlx_flags
& MLXF_INITOK
) == 0)
691 if ((mlx
->mlx_flags
& MLXF_OPEN
) != 0)
694 mlx
->mlx_flags
|= MLXF_OPEN
;
699 * Accept the last close on the control device.
702 mlxclose(dev_t dev
, int flag
, int mode
,
705 struct mlx_softc
*mlx
;
707 mlx
= device_lookup_private(&mlx_cd
, minor(dev
));
708 mlx
->mlx_flags
&= ~MLXF_OPEN
;
713 * Handle control operations.
716 mlxioctl(dev_t dev
, u_long cmd
, void *data
, int flag
,
719 struct mlx_softc
*mlx
;
720 struct mlx_rebuild_request
*rb
;
721 struct mlx_rebuild_status
*rs
;
722 struct mlx_pause
*mp
;
723 struct mlx_sysdrive
*ms
;
724 int i
, rv
, *arg
, result
;
726 mlx
= device_lookup_private(&mlx_cd
, minor(dev
));
728 rb
= (struct mlx_rebuild_request
*)data
;
729 rs
= (struct mlx_rebuild_status
*)data
;
734 case MLX_RESCAN_DRIVES
:
736 * Scan the controller to see whether new drives have
737 * appeared, or old ones disappeared.
739 mlx_configure(mlx
, 1);
742 case MLX_PAUSE_CHANNEL
:
744 * Pause one or more SCSI channels for a period of time, to
745 * assist in the process of hot-swapping devices.
747 * Note that at least the 3.51 firmware on the DAC960PL
748 * doesn't seem to do this right.
750 if ((mlx
->mlx_flags
& MLXF_PAUSEWORKS
) == 0)
753 mp
= (struct mlx_pause
*)data
;
755 if ((mp
->mp_which
== MLX_PAUSE_CANCEL
) &&
756 (mlx
->mlx_pause
.mp_when
!= 0)) {
757 /* Cancel a pending pause operation. */
758 mlx
->mlx_pause
.mp_which
= 0;
762 /* Fix for legal channels. */
763 mp
->mp_which
&= ((1 << mlx
->mlx_ci
.ci_nchan
) -1);
765 /* Check time values. */
766 if (mp
->mp_when
< 0 || mp
->mp_when
> 3600 ||
767 mp
->mp_howlong
< 1 || mp
->mp_howlong
> (0xf * 30)) {
772 /* Check for a pause currently running. */
773 if ((mlx
->mlx_pause
.mp_which
!= 0) &&
774 (mlx
->mlx_pause
.mp_when
== 0)) {
779 /* Looks ok, go with it. */
780 mlx
->mlx_pause
.mp_which
= mp
->mp_which
;
781 mlx
->mlx_pause
.mp_when
= time_second
+ mp
->mp_when
;
782 mlx
->mlx_pause
.mp_howlong
=
783 mlx
->mlx_pause
.mp_when
+ mp
->mp_howlong
;
788 rv
= kauth_authorize_device_passthru(l
->l_cred
, dev
,
789 KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL
, data
);
794 * Accept a command passthrough-style.
796 return (mlx_user_command(mlx
, (struct mlx_usercommand
*)data
));
798 case MLX_REBUILDASYNC
:
800 * Start a rebuild on a given SCSI disk
802 if (mlx
->mlx_bg
!= 0) {
803 rb
->rr_status
= 0x0106;
808 rb
->rr_status
= mlx_rebuild(mlx
, rb
->rr_channel
, rb
->rr_target
);
809 switch (rb
->rr_status
) {
814 rv
= ENOMEM
; /* Couldn't set up the command. */
834 mlx
->mlx_bg
= MLX_BG_REBUILD
;
838 case MLX_REBUILDSTAT
:
840 * Get the status of the current rebuild or consistency check.
842 *rs
= mlx
->mlx_rebuildstat
;
845 case MLX_GET_SYSDRIVE
:
847 * Return the system drive number matching the `ld' device
848 * unit in (arg), if it happens to belong to us.
850 for (i
= 0; i
< MLX_MAX_DRIVES
; i
++) {
851 ms
= &mlx
->mlx_sysdrive
[i
];
852 if (ms
->ms_dv
!= NULL
)
853 if (device_xname(ms
->ms_dv
)[2] == '0' + *arg
) {
862 * Return controller info.
864 memcpy(arg
, &mlx
->mlx_ci
, sizeof(mlx
->mlx_ci
));
871 case MLXD_CHECKASYNC
:
872 if ((u_int
)*arg
>= MLX_MAX_DRIVES
)
874 ms
= &mlx
->mlx_sysdrive
[*arg
];
875 if (*arg
> MLX_MAX_DRIVES
|| ms
->ms_dv
== NULL
)
886 * Disconnect from the specified drive; it may be about to go
889 return (config_detach(ms
->ms_dv
, 0));
893 * Return the current status of this drive.
898 case MLXD_CHECKASYNC
:
900 * Start a background consistency check on this drive.
902 if (mlx
->mlx_bg
!= 0) {
907 switch (result
= mlx_check(mlx
, *arg
)) {
912 rv
= ENOMEM
; /* Couldn't set up the command. */
929 mlx
->mlx_bg
= MLX_BG_CHECK
;
934 return (ENOTTY
); /* XXX shut up gcc */
938 mlx_periodic_thread(void *cookie
)
940 struct mlx_softc
*mlx
;
944 for (i
= 0; i
< mlx_cd
.cd_ndevs
; i
++)
945 if ((mlx
= device_lookup_private(&mlx_cd
, i
)) != NULL
)
946 if (mlx
->mlx_ci
.ci_iftype
> 1)
949 tsleep(mlx_periodic_thread
, PWAIT
, "mlxzzz", hz
* 2);
954 mlx_periodic(struct mlx_softc
*mlx
)
956 struct mlx_ccb
*mc
, *nmc
;
959 if ((mlx
->mlx_pause
.mp_which
!= 0) &&
960 (mlx
->mlx_pause
.mp_when
> 0) &&
961 (time_second
>= mlx
->mlx_pause
.mp_when
)) {
965 mlx_pause_action(mlx
);
966 mlx
->mlx_pause
.mp_when
= 0;
967 } else if ((mlx
->mlx_pause
.mp_which
!= 0) &&
968 (mlx
->mlx_pause
.mp_when
== 0)) {
970 * Stop pause if required.
972 if (time_second
>= mlx
->mlx_pause
.mp_howlong
) {
973 mlx_pause_action(mlx
);
974 mlx
->mlx_pause
.mp_which
= 0;
976 } else if (time_second
> (mlx
->mlx_lastpoll
+ 10)) {
978 * Run normal periodic activities...
980 mlx
->mlx_lastpoll
= time_second
;
983 * Check controller status.
985 if ((mlx
->mlx_flags
& MLXF_PERIODIC_CTLR
) == 0) {
986 mlx
->mlx_flags
|= MLXF_PERIODIC_CTLR
;
988 if (mlx
->mlx_ci
.ci_iftype
<= 2)
989 etype
= MLX_CMD_ENQUIRY_OLD
;
991 etype
= MLX_CMD_ENQUIRY
;
993 mlx_enquire(mlx
, etype
, max(sizeof(struct mlx_enquiry
),
994 sizeof(struct mlx_enquiry_old
)),
995 mlx_periodic_enquiry
, 1);
999 * Check system drive status.
1001 if ((mlx
->mlx_flags
& MLXF_PERIODIC_DRIVE
) == 0) {
1002 mlx
->mlx_flags
|= MLXF_PERIODIC_DRIVE
;
1003 mlx_enquire(mlx
, MLX_CMD_ENQSYSDRIVE
,
1004 sizeof(struct mlx_enq_sys_drive
) * MLX_MAX_DRIVES
,
1005 mlx_periodic_enquiry
, 1);
1010 * Get drive rebuild/check status.
1012 if ((mlx
->mlx_flags
& MLXF_PERIODIC_REBUILD
) == 0) {
1013 mlx
->mlx_flags
|= MLXF_PERIODIC_REBUILD
;
1014 mlx_enquire(mlx
, MLX_CMD_REBUILDSTAT
,
1015 sizeof(struct mlx_rebuild_stat
), mlx_periodic_rebuild
, 1);
1019 * Time-out busy CCBs.
1022 for (mc
= TAILQ_FIRST(&mlx
->mlx_ccb_worklist
); mc
!= NULL
; mc
= nmc
) {
1023 nmc
= TAILQ_NEXT(mc
, mc_chain
.tailq
);
1024 if (mc
->mc_expiry
> time_second
) {
1026 * The remaining CCBs will expire after this one, so
1027 * there's no point in going further.
1031 TAILQ_REMOVE(&mlx
->mlx_ccb_worklist
, mc
, mc_chain
.tailq
);
1032 mc
->mc_status
= MLX_STATUS_LOST
;
1033 if (mc
->mc_mx
.mx_handler
!= NULL
)
1034 (*mc
->mc_mx
.mx_handler
)(mc
);
1035 else if ((mc
->mc_flags
& MC_WAITING
) != 0)
1042 * Handle the result of an ENQUIRY command instigated by periodic status
1046 mlx_periodic_enquiry(struct mlx_ccb
*mc
)
1048 struct mlx_softc
*mlx
;
1049 struct mlx_enquiry
*me
;
1050 struct mlx_enquiry_old
*meo
;
1051 struct mlx_enq_sys_drive
*mes
;
1052 struct mlx_sysdrive
*dr
;
1053 const char *statestr
;
1057 mlx
= (struct mlx_softc
*)mc
->mc_mx
.mx_dv
;
1058 mlx_ccb_unmap(mlx
, mc
);
1061 * Command completed OK?
1063 if (mc
->mc_status
!= 0) {
1064 aprint_error_dev(&mlx
->mlx_dv
, "periodic enquiry failed - %s\n",
1065 mlx_ccb_diagnose(mc
));
1070 * Respond to command.
1072 switch (mc
->mc_mbox
[0]) {
1073 case MLX_CMD_ENQUIRY_OLD
:
1075 * This is currently a bit fruitless, as we don't know how
1076 * to extract the eventlog pointer yet.
1078 me
= (struct mlx_enquiry
*)mc
->mc_mx
.mx_context
;
1079 meo
= (struct mlx_enquiry_old
*)mc
->mc_mx
.mx_context
;
1081 /* Convert data in-place to new format */
1082 i
= sizeof(me
->me_dead
) / sizeof(me
->me_dead
[0]);
1084 me
->me_dead
[i
].dd_chan
= meo
->me_dead
[i
].dd_chan
;
1085 me
->me_dead
[i
].dd_targ
= meo
->me_dead
[i
].dd_targ
;
1088 me
->me_misc_flags
= 0;
1089 me
->me_rebuild_count
= meo
->me_rebuild_count
;
1090 me
->me_dead_count
= meo
->me_dead_count
;
1091 me
->me_critical_sd_count
= meo
->me_critical_sd_count
;
1092 me
->me_event_log_seq_num
= 0;
1093 me
->me_offline_sd_count
= meo
->me_offline_sd_count
;
1094 me
->me_max_commands
= meo
->me_max_commands
;
1095 me
->me_rebuild_flag
= meo
->me_rebuild_flag
;
1096 me
->me_fwmajor
= meo
->me_fwmajor
;
1097 me
->me_fwminor
= meo
->me_fwminor
;
1098 me
->me_status_flags
= meo
->me_status_flags
;
1099 me
->me_flash_age
= meo
->me_flash_age
;
1101 i
= sizeof(me
->me_drvsize
) / sizeof(me
->me_drvsize
[0]);
1102 j
= sizeof(meo
->me_drvsize
) / sizeof(meo
->me_drvsize
[0]);
1106 me
->me_drvsize
[i
] = 0;
1108 me
->me_drvsize
[i
] = meo
->me_drvsize
[i
];
1111 me
->me_num_sys_drvs
= meo
->me_num_sys_drvs
;
1115 case MLX_CMD_ENQUIRY
:
1117 * Generic controller status update. We could do more with
1118 * this than just checking the event log.
1120 me
= (struct mlx_enquiry
*)mc
->mc_mx
.mx_context
;
1121 lsn
= le16toh(me
->me_event_log_seq_num
);
1123 if (mlx
->mlx_currevent
== -1) {
1124 /* Initialise our view of the event log. */
1125 mlx
->mlx_currevent
= lsn
;
1126 mlx
->mlx_lastevent
= lsn
;
1127 } else if (lsn
!= mlx
->mlx_lastevent
&&
1128 (mlx
->mlx_flags
& MLXF_EVENTLOG_BUSY
) == 0) {
1129 /* Record where current events are up to */
1130 mlx
->mlx_currevent
= lsn
;
1132 /* Mark the event log as busy. */
1133 mlx
->mlx_flags
|= MLXF_EVENTLOG_BUSY
;
1135 /* Drain new eventlog entries. */
1136 mlx_periodic_eventlog_poll(mlx
);
1140 case MLX_CMD_ENQSYSDRIVE
:
1142 * Perform drive status comparison to see if something
1143 * has failed. Don't perform the comparison if we're
1144 * reconfiguring, since the system drive table will be
1147 if ((mlx
->mlx_flags
& MLXF_RESCANNING
) != 0)
1150 mes
= (struct mlx_enq_sys_drive
*)mc
->mc_mx
.mx_context
;
1151 dr
= &mlx
->mlx_sysdrive
[0];
1153 for (i
= 0; i
< mlx
->mlx_numsysdrives
; i
++, dr
++) {
1154 /* Has state been changed by controller? */
1155 if (dr
->ms_state
!= mes
[i
].sd_state
) {
1156 switch (mes
[i
].sd_state
) {
1157 case MLX_SYSD_OFFLINE
:
1158 statestr
= "offline";
1161 case MLX_SYSD_ONLINE
:
1162 statestr
= "online";
1165 case MLX_SYSD_CRITICAL
:
1166 statestr
= "critical";
1170 statestr
= "unknown";
1174 printf("%s: unit %d %s\n", device_xname(&mlx
->mlx_dv
),
1177 /* Save new state. */
1178 dr
->ms_state
= mes
[i
].sd_state
;
1185 printf("%s: mlx_periodic_enquiry: eh?\n",
1186 device_xname(&mlx
->mlx_dv
));
1192 if (mc
->mc_mbox
[0] == MLX_CMD_ENQSYSDRIVE
)
1193 mlx
->mlx_flags
&= ~MLXF_PERIODIC_DRIVE
;
1195 mlx
->mlx_flags
&= ~MLXF_PERIODIC_CTLR
;
1197 free(mc
->mc_mx
.mx_context
, M_DEVBUF
);
1198 mlx_ccb_free(mlx
, mc
);
1202 * Instigate a poll for one event log message on (mlx). We only poll for
1203 * one message at a time, to keep our command usage down.
1206 mlx_periodic_eventlog_poll(struct mlx_softc
*mlx
)
1214 if ((rv
= mlx_ccb_alloc(mlx
, &mc
, 1)) != 0)
1217 if ((result
= malloc(1024, M_DEVBUF
, M_WAITOK
)) == NULL
) {
1221 if ((rv
= mlx_ccb_map(mlx
, mc
, result
, 1024, MC_XFER_IN
)) != 0)
1223 if (mc
->mc_nsgent
!= 1) {
1224 mlx_ccb_unmap(mlx
, mc
);
1225 printf("mlx_periodic_eventlog_poll: too many segs\n");
1229 /* Build the command to get one log entry. */
1230 mlx_make_type3(mc
, MLX_CMD_LOGOP
, MLX_LOGOP_GET
, 1,
1231 mlx
->mlx_lastevent
, 0, 0, mc
->mc_xfer_phys
, 0);
1233 mc
->mc_mx
.mx_handler
= mlx_periodic_eventlog_respond
;
1234 mc
->mc_mx
.mx_dv
= &mlx
->mlx_dv
;
1235 mc
->mc_mx
.mx_context
= result
;
1237 /* Start the command. */
1238 mlx_ccb_enqueue(mlx
, mc
);
1243 mlx_ccb_free(mlx
, mc
);
1245 free(result
, M_DEVBUF
);
1250 * Handle the result of polling for a log message, generate diagnostic
1251 * output. If this wasn't the last message waiting for us, we'll go collect
1255 mlx_periodic_eventlog_respond(struct mlx_ccb
*mc
)
1257 struct mlx_softc
*mlx
;
1258 struct mlx_eventlog_entry
*el
;
1260 u_int8_t sensekey
, chan
, targ
;
1262 mlx
= (struct mlx_softc
*)mc
->mc_mx
.mx_dv
;
1263 el
= mc
->mc_mx
.mx_context
;
1264 mlx_ccb_unmap(mlx
, mc
);
1266 mlx
->mlx_lastevent
++;
1268 if (mc
->mc_status
== 0) {
1269 switch (el
->el_type
) {
1270 case MLX_LOGMSG_SENSE
: /* sense data */
1271 sensekey
= el
->el_sense
& 0x0f;
1272 chan
= (el
->el_target
>> 4) & 0x0f;
1273 targ
= el
->el_target
& 0x0f;
1276 * This is the only sort of message we understand at
1277 * the moment. The tests here are probably
1282 * Mylex vendor-specific message indicating a drive
1285 if (sensekey
== 9 && el
->el_asc
== 0x80) {
1286 if (el
->el_asq
< sizeof(mlx_sense_msgs
) /
1287 sizeof(mlx_sense_msgs
[0]))
1288 reason
= mlx_sense_msgs
[el
->el_asq
];
1290 reason
= "for unknown reason";
1292 printf("%s: physical drive %d:%d killed %s\n",
1293 device_xname(&mlx
->mlx_dv
), chan
, targ
, reason
);
1297 * SCSI drive was reset?
1299 if (sensekey
== 6 && el
->el_asc
== 0x29)
1300 printf("%s: physical drive %d:%d reset\n",
1301 device_xname(&mlx
->mlx_dv
), chan
, targ
);
1306 if (!(sensekey
== 0 ||
1308 el
->el_asc
== 0x04 &&
1309 (el
->el_asq
== 0x01 || el
->el_asq
== 0x02)))) {
1310 printf("%s: physical drive %d:%d error log: "
1311 "sense = %d asc = %x asq = %x\n",
1312 device_xname(&mlx
->mlx_dv
), chan
, targ
, sensekey
,
1313 el
->el_asc
, el
->el_asq
);
1314 printf("%s: info = %d:%d:%d:%d "
1315 " csi = %d:%d:%d:%d\n",
1316 device_xname(&mlx
->mlx_dv
),
1317 el
->el_information
[0],
1318 el
->el_information
[1],
1319 el
->el_information
[2],
1320 el
->el_information
[3],
1321 el
->el_csi
[0], el
->el_csi
[1],
1322 el
->el_csi
[2], el
->el_csi
[3]);
1328 aprint_error_dev(&mlx
->mlx_dv
, "unknown log message type 0x%x\n",
1333 aprint_error_dev(&mlx
->mlx_dv
, "error reading message log - %s\n",
1334 mlx_ccb_diagnose(mc
));
1337 * Give up on all the outstanding messages, as we may have
1340 mlx
->mlx_lastevent
= mlx
->mlx_currevent
;
1343 free(mc
->mc_mx
.mx_context
, M_DEVBUF
);
1344 mlx_ccb_free(mlx
, mc
);
1347 * Is there another message to obtain?
1349 if (mlx
->mlx_lastevent
!= mlx
->mlx_currevent
)
1350 mlx_periodic_eventlog_poll(mlx
);
1352 mlx
->mlx_flags
&= ~MLXF_EVENTLOG_BUSY
;
1356 * Handle check/rebuild operations in progress.
1359 mlx_periodic_rebuild(struct mlx_ccb
*mc
)
1361 struct mlx_softc
*mlx
;
1363 struct mlx_rebuild_status
*mr
;
1365 mlx
= (struct mlx_softc
*)mc
->mc_mx
.mx_dv
;
1366 mr
= mc
->mc_mx
.mx_context
;
1367 mlx_ccb_unmap(mlx
, mc
);
1369 switch (mc
->mc_status
) {
1372 * Operation running, update stats.
1374 mlx
->mlx_rebuildstat
= *mr
;
1376 /* Spontaneous rebuild/check? */
1377 if (mlx
->mlx_bg
== 0) {
1378 mlx
->mlx_bg
= MLX_BG_SPONTANEOUS
;
1379 printf("%s: background check/rebuild started\n",
1380 device_xname(&mlx
->mlx_dv
));
1386 * Nothing running, finalise stats and report.
1388 switch (mlx
->mlx_bg
) {
1390 /* XXX Print drive? */
1391 opstr
= "consistency check";
1394 case MLX_BG_REBUILD
:
1395 /* XXX Print channel:target? */
1396 opstr
= "drive rebuild";
1399 case MLX_BG_SPONTANEOUS
:
1402 * If we have previously been non-idle, report the
1405 if (mlx
->mlx_rebuildstat
.rs_code
!=
1406 MLX_REBUILDSTAT_IDLE
)
1407 opstr
= "background check/rebuild";
1413 printf("%s: %s completed\n", device_xname(&mlx
->mlx_dv
),
1417 mlx
->mlx_rebuildstat
.rs_code
= MLX_REBUILDSTAT_IDLE
;
1421 free(mc
->mc_mx
.mx_context
, M_DEVBUF
);
1422 mlx_ccb_free(mlx
, mc
);
1423 mlx
->mlx_flags
&= ~MLXF_PERIODIC_REBUILD
;
1427 * It's time to perform a channel pause action for (mlx), either start or
1431 mlx_pause_action(struct mlx_softc
*mlx
)
1434 int failsafe
, i
, cmd
;
1436 /* What are we doing here? */
1437 if (mlx
->mlx_pause
.mp_when
== 0) {
1438 cmd
= MLX_CMD_STARTCHANNEL
;
1441 cmd
= MLX_CMD_STOPCHANNEL
;
1444 * Channels will always start again after the failsafe
1445 * period, which is specified in multiples of 30 seconds.
1446 * This constrains us to a maximum pause of 450 seconds.
1448 failsafe
= ((mlx
->mlx_pause
.mp_howlong
- time_second
) + 5) / 30;
1450 if (failsafe
> 0xf) {
1452 mlx
->mlx_pause
.mp_howlong
=
1453 time_second
+ (0xf * 30) - 5;
1457 /* Build commands for every channel requested. */
1458 for (i
= 0; i
< mlx
->mlx_ci
.ci_nchan
; i
++) {
1459 if ((1 << i
) & mlx
->mlx_pause
.mp_which
) {
1460 if (mlx_ccb_alloc(mlx
, &mc
, 1) != 0) {
1461 aprint_error_dev(&mlx
->mlx_dv
, "%s failed for channel %d\n",
1462 cmd
== MLX_CMD_STOPCHANNEL
?
1463 "pause" : "resume", i
);
1467 /* Build the command. */
1468 mlx_make_type2(mc
, cmd
, (failsafe
<< 4) | i
, 0, 0,
1470 mc
->mc_mx
.mx_handler
= mlx_pause_done
;
1471 mc
->mc_mx
.mx_dv
= &mlx
->mlx_dv
;
1473 mlx_ccb_enqueue(mlx
, mc
);
1479 mlx_pause_done(struct mlx_ccb
*mc
)
1481 struct mlx_softc
*mlx
;
1482 int command
, channel
;
1484 mlx
= (struct mlx_softc
*)mc
->mc_mx
.mx_dv
;
1485 command
= mc
->mc_mbox
[0];
1486 channel
= mc
->mc_mbox
[2] & 0xf;
1488 if (mc
->mc_status
!= 0)
1489 aprint_error_dev(&mlx
->mlx_dv
, "%s command failed - %s\n",
1490 command
== MLX_CMD_STOPCHANNEL
? "pause" : "resume",
1491 mlx_ccb_diagnose(mc
));
1492 else if (command
== MLX_CMD_STOPCHANNEL
)
1493 printf("%s: channel %d pausing for %ld seconds\n",
1494 device_xname(&mlx
->mlx_dv
), channel
,
1495 (long)(mlx
->mlx_pause
.mp_howlong
- time_second
));
1497 printf("%s: channel %d resuming\n", device_xname(&mlx
->mlx_dv
),
1500 mlx_ccb_free(mlx
, mc
);
1504 * Perform an Enquiry command using a type-3 command buffer and a return a
1505 * single linear result buffer. If the completion function is specified, it
1506 * will be called with the completed command (and the result response will
1507 * not be valid until that point). Otherwise, the command will either be
1508 * busy-waited for (interrupts must be blocked), or slept for.
1511 mlx_enquire(struct mlx_softc
*mlx
, int command
, size_t bufsize
,
1512 void (*handler
)(struct mlx_ccb
*mc
), int waitok
)
1521 if ((rv
= mlx_ccb_alloc(mlx
, &mc
, 1)) != 0)
1524 result
= malloc(bufsize
, M_DEVBUF
, waitok
? M_WAITOK
: M_NOWAIT
);
1525 if (result
== NULL
) {
1526 printf("mlx_enquire: malloc() failed\n");
1529 if ((rv
= mlx_ccb_map(mlx
, mc
, result
, bufsize
, MC_XFER_IN
)) != 0)
1532 if (mc
->mc_nsgent
!= 1) {
1533 printf("mlx_enquire: too many segs\n");
1537 /* Build an enquiry command. */
1538 mlx_make_type2(mc
, command
, 0, 0, 0, 0, 0, 0, mc
->mc_xfer_phys
, 0);
1540 /* Do we want a completion callback? */
1541 if (handler
!= NULL
) {
1542 mc
->mc_mx
.mx_context
= result
;
1543 mc
->mc_mx
.mx_dv
= &mlx
->mlx_dv
;
1544 mc
->mc_mx
.mx_handler
= handler
;
1545 mlx_ccb_enqueue(mlx
, mc
);
1547 /* Run the command in either polled or wait mode. */
1549 rv
= mlx_ccb_wait(mlx
, mc
);
1551 rv
= mlx_ccb_poll(mlx
, mc
, 5000);
1555 /* We got a command, but nobody else will free it. */
1556 if (handler
== NULL
&& mc
!= NULL
) {
1558 mlx_ccb_unmap(mlx
, mc
);
1559 mlx_ccb_free(mlx
, mc
);
1562 /* We got an error, and we allocated a result. */
1563 if (rv
!= 0 && result
!= NULL
) {
1565 mlx_ccb_free(mlx
, mc
);
1566 free(result
, M_DEVBUF
);
1574 * Perform a Flush command on the nominated controller.
1576 * May be called with interrupts enabled or disabled; will not return until
1577 * the flush operation completes or fails.
1580 mlx_flush(struct mlx_softc
*mlx
, int async
)
1585 if ((rv
= mlx_ccb_alloc(mlx
, &mc
, 1)) != 0)
1588 /* Build a flush command and fire it off. */
1589 mlx_make_type2(mc
, MLX_CMD_FLUSH
, 0, 0, 0, 0, 0, 0, 0, 0);
1592 rv
= mlx_ccb_wait(mlx
, mc
);
1594 rv
= mlx_ccb_poll(mlx
, mc
, MLX_TIMEOUT
* 1000);
1598 /* Command completed OK? */
1599 if (mc
->mc_status
!= 0) {
1600 aprint_error_dev(&mlx
->mlx_dv
, "FLUSH failed - %s\n",
1601 mlx_ccb_diagnose(mc
));
1606 mlx_ccb_free(mlx
, mc
);
1612 * Start a background consistency check on (drive).
1615 mlx_check(struct mlx_softc
*mlx
, int drive
)
1620 /* Get ourselves a command buffer. */
1623 if (mlx_ccb_alloc(mlx
, &mc
, 1) != 0)
1626 /* Build a checkasync command, set the "fix it" flag. */
1627 mlx_make_type2(mc
, MLX_CMD_CHECKASYNC
, 0, 0, 0, 0, 0, drive
| 0x80,
1630 /* Start the command and wait for it to be returned. */
1631 if (mlx_ccb_wait(mlx
, mc
) != 0)
1634 /* Command completed OK? */
1635 if (mc
->mc_status
!= 0)
1636 aprint_error_dev(&mlx
->mlx_dv
, "CHECK ASYNC failed - %s\n",
1637 mlx_ccb_diagnose(mc
));
1639 printf("%s: consistency check started",
1640 device_xname(mlx
->mlx_sysdrive
[drive
].ms_dv
));
1645 mlx_ccb_free(mlx
, mc
);
1651 * Start a background rebuild of the physical drive at (channel),(target).
1653 * May be called with interrupts enabled or disabled; will return as soon as
1654 * the operation has started or been refused.
1657 mlx_rebuild(struct mlx_softc
*mlx
, int channel
, int target
)
1663 if (mlx_ccb_alloc(mlx
, &mc
, 1) != 0)
1666 /* Build a rebuildasync command, set the "fix it" flag. */
1667 mlx_make_type2(mc
, MLX_CMD_REBUILDASYNC
, channel
, target
, 0, 0, 0, 0,
1670 /* Start the command and wait for it to be returned. */
1671 if (mlx_ccb_wait(mlx
, mc
) != 0)
1674 /* Command completed OK? */
1675 aprint_normal_dev(&mlx
->mlx_dv
, "");
1676 if (mc
->mc_status
!= 0)
1677 printf("REBUILD ASYNC failed - %s\n", mlx_ccb_diagnose(mc
));
1679 printf("rebuild started for %d:%d\n", channel
, target
);
1681 error
= mc
->mc_status
;
1685 mlx_ccb_free(mlx
, mc
);
1691 * Take a command from user-space and try to run it.
1693 * XXX Note that this can't perform very much in the way of error checking,
1694 * XXX and as such, applications _must_ be considered trustworthy.
1696 * XXX Commands using S/G for data are not supported.
1699 mlx_user_command(struct mlx_softc
*mlx
, struct mlx_usercommand
*mu
)
1702 struct mlx_dcdb
*dcdb
;
1706 if ((mu
->mu_bufdir
& ~MU_XFER_MASK
) != 0)
1713 /* Get ourselves a command and copy in from user space. */
1714 if ((rv
= mlx_ccb_alloc(mlx
, &mc
, 1)) != 0) {
1715 DPRINTF(("mlx_user_command: mlx_ccb_alloc = %d\n", rv
));
1719 memcpy(mc
->mc_mbox
, mu
->mu_command
, sizeof(mc
->mc_mbox
));
1722 * If we need a buffer for data transfer, allocate one and copy in
1723 * its initial contents.
1725 if (mu
->mu_datasize
> 0) {
1726 if (mu
->mu_datasize
> MAXPHYS
)
1729 kbuf
= malloc(mu
->mu_datasize
, M_DEVBUF
, M_WAITOK
);
1731 DPRINTF(("mlx_user_command: malloc = NULL\n"));
1736 if ((mu
->mu_bufdir
& MU_XFER_OUT
) != 0) {
1737 rv
= copyin(mu
->mu_buf
, kbuf
, mu
->mu_datasize
);
1739 DPRINTF(("mlx_user_command: copyin = %d\n",
1745 /* Map the buffer so the controller can see it. */
1746 rv
= mlx_ccb_map(mlx
, mc
, kbuf
, mu
->mu_datasize
, mu
->mu_bufdir
);
1748 DPRINTF(("mlx_user_command: mlx_ccb_map = %d\n", rv
));
1751 if (mc
->mc_nsgent
> 1) {
1752 DPRINTF(("mlx_user_command: too many s/g entries\n"));
1758 * If this is a passthrough SCSI command, the DCDB is packed at
1759 * the beginning of the data area. Fix up the DCDB to point to
1760 * the correct physical address and override any bufptr
1761 * supplied by the caller since we know what it's meant to be.
1763 if (mc
->mc_mbox
[0] == MLX_CMD_DIRECT_CDB
) {
1764 dcdb
= (struct mlx_dcdb
*)kbuf
;
1765 dcdb
->dcdb_physaddr
= mc
->mc_xfer_phys
+ sizeof(*dcdb
);
1772 * If there's a data buffer, fix up the command's buffer pointer.
1774 if (mu
->mu_datasize
> 0) {
1775 /* Range check the pointer to physical buffer address. */
1776 if (mu
->mu_bufptr
< 0 ||
1777 mu
->mu_bufptr
> sizeof(mu
->mu_command
) - 4) {
1778 DPRINTF(("mlx_user_command: bufptr botch\n"));
1783 mc
->mc_mbox
[mu
->mu_bufptr
] = mc
->mc_xfer_phys
;
1784 mc
->mc_mbox
[mu
->mu_bufptr
+1] = mc
->mc_xfer_phys
>> 8;
1785 mc
->mc_mbox
[mu
->mu_bufptr
+2] = mc
->mc_xfer_phys
>> 16;
1786 mc
->mc_mbox
[mu
->mu_bufptr
+3] = mc
->mc_xfer_phys
>> 24;
1789 /* Submit the command and wait. */
1790 if ((rv
= mlx_ccb_wait(mlx
, mc
)) != 0) {
1792 printf("mlx_user_command: mlx_ccb_wait = %d\n", rv
);
1798 /* Copy out status and data */
1799 mu
->mu_status
= mc
->mc_status
;
1801 mlx_ccb_unmap(mlx
, mc
);
1802 mlx_ccb_free(mlx
, mc
);
1806 if (mu
->mu_datasize
> 0 && (mu
->mu_bufdir
& MU_XFER_IN
) != 0) {
1807 rv
= copyout(kbuf
, mu
->mu_buf
, mu
->mu_datasize
);
1810 printf("mlx_user_command: copyout = %d\n", rv
);
1815 free(kbuf
, M_DEVBUF
);
1821 * Allocate and initialise a CCB.
1824 mlx_ccb_alloc(struct mlx_softc
*mlx
, struct mlx_ccb
**mcp
, int control
)
1830 mc
= SLIST_FIRST(&mlx
->mlx_ccb_freelist
);
1832 if (mlx
->mlx_nccbs_ctrl
>= MLX_NCCBS_CONTROL
) {
1837 mc
->mc_flags
|= MC_CONTROL
;
1838 mlx
->mlx_nccbs_ctrl
++;
1840 SLIST_REMOVE_HEAD(&mlx
->mlx_ccb_freelist
, mc_chain
.slist
);
1851 mlx_ccb_free(struct mlx_softc
*mlx
, struct mlx_ccb
*mc
)
1856 if ((mc
->mc_flags
& MC_CONTROL
) != 0)
1857 mlx
->mlx_nccbs_ctrl
--;
1859 SLIST_INSERT_HEAD(&mlx
->mlx_ccb_freelist
, mc
, mc_chain
.slist
);
1864 * If a CCB is specified, enqueue it. Pull CCBs off the software queue in
1865 * the order that they were enqueued and try to submit their mailboxes to
1866 * the controller for execution.
1869 mlx_ccb_enqueue(struct mlx_softc
*mlx
, struct mlx_ccb
*mc
)
1876 SIMPLEQ_INSERT_TAIL(&mlx
->mlx_ccb_queue
, mc
, mc_chain
.simpleq
);
1878 while ((mc
= SIMPLEQ_FIRST(&mlx
->mlx_ccb_queue
)) != NULL
) {
1879 if (mlx_ccb_submit(mlx
, mc
) != 0)
1881 SIMPLEQ_REMOVE_HEAD(&mlx
->mlx_ccb_queue
, mc_chain
.simpleq
);
1882 TAILQ_INSERT_TAIL(&mlx
->mlx_ccb_worklist
, mc
, mc_chain
.tailq
);
1889 * Map the specified CCB's data buffer onto the bus, and fill the
1890 * scatter-gather list.
1893 mlx_ccb_map(struct mlx_softc
*mlx
, struct mlx_ccb
*mc
, void *data
, int size
,
1896 struct mlx_sgentry
*sge
;
1897 int nsegs
, i
, rv
, sgloff
;
1900 xfer
= mc
->mc_xfer_map
;
1902 rv
= bus_dmamap_load(mlx
->mlx_dmat
, xfer
, data
, size
, NULL
,
1903 BUS_DMA_NOWAIT
| BUS_DMA_STREAMING
|
1904 ((dir
& MC_XFER_IN
) ? BUS_DMA_READ
: BUS_DMA_WRITE
));
1908 nsegs
= xfer
->dm_nsegs
;
1909 mc
->mc_xfer_size
= size
;
1910 mc
->mc_flags
|= dir
;
1911 mc
->mc_nsgent
= nsegs
;
1912 mc
->mc_xfer_phys
= xfer
->dm_segs
[0].ds_addr
;
1914 sgloff
= MLX_SGL_SIZE
* mc
->mc_ident
;
1915 sge
= (struct mlx_sgentry
*)((char *)mlx
->mlx_sgls
+ sgloff
);
1917 for (i
= 0; i
< nsegs
; i
++, sge
++) {
1918 sge
->sge_addr
= htole32(xfer
->dm_segs
[i
].ds_addr
);
1919 sge
->sge_count
= htole32(xfer
->dm_segs
[i
].ds_len
);
1922 if ((dir
& MC_XFER_OUT
) != 0)
1923 i
= BUS_DMASYNC_PREWRITE
;
1926 if ((dir
& MC_XFER_IN
) != 0)
1927 i
|= BUS_DMASYNC_PREREAD
;
1929 bus_dmamap_sync(mlx
->mlx_dmat
, xfer
, 0, mc
->mc_xfer_size
, i
);
1930 bus_dmamap_sync(mlx
->mlx_dmat
, mlx
->mlx_dmamap
, sgloff
,
1931 MLX_SGL_SIZE
, BUS_DMASYNC_PREWRITE
);
1937 * Unmap the specified CCB's data buffer.
1940 mlx_ccb_unmap(struct mlx_softc
*mlx
, struct mlx_ccb
*mc
)
1944 bus_dmamap_sync(mlx
->mlx_dmat
, mlx
->mlx_dmamap
,
1945 MLX_SGL_SIZE
* mc
->mc_ident
, MLX_SGL_SIZE
,
1946 BUS_DMASYNC_POSTWRITE
);
1948 if ((mc
->mc_flags
& MC_XFER_OUT
) != 0)
1949 i
= BUS_DMASYNC_POSTWRITE
;
1952 if ((mc
->mc_flags
& MC_XFER_IN
) != 0)
1953 i
|= BUS_DMASYNC_POSTREAD
;
1955 bus_dmamap_sync(mlx
->mlx_dmat
, mc
->mc_xfer_map
, 0, mc
->mc_xfer_size
, i
);
1956 bus_dmamap_unload(mlx
->mlx_dmat
, mc
->mc_xfer_map
);
1960 * Submit the CCB, and busy-wait for it to complete. Return non-zero on
1961 * timeout or submission error. Must be called with interrupts blocked.
1964 mlx_ccb_poll(struct mlx_softc
*mlx
, struct mlx_ccb
*mc
, int timo
)
1968 mc
->mc_mx
.mx_handler
= NULL
;
1970 if ((rv
= mlx_ccb_submit(mlx
, mc
)) != 0)
1972 TAILQ_INSERT_TAIL(&mlx
->mlx_ccb_worklist
, mc
, mc_chain
.tailq
);
1974 for (timo
*= 10; timo
!= 0; timo
--) {
1976 if (mc
->mc_status
!= MLX_STATUS_BUSY
)
1982 if (mc
->mc_status
!= 0) {
1983 aprint_error_dev(&mlx
->mlx_dv
, "command failed - %s\n",
1984 mlx_ccb_diagnose(mc
));
1989 printf("%s: command timed out\n", device_xname(&mlx
->mlx_dv
));
1997 * Enqueue the CCB, and sleep until it completes. Return non-zero on
2001 mlx_ccb_wait(struct mlx_softc
*mlx
, struct mlx_ccb
*mc
)
2005 mc
->mc_flags
|= MC_WAITING
;
2006 mc
->mc_mx
.mx_handler
= NULL
;
2009 mlx_ccb_enqueue(mlx
, mc
);
2010 tsleep(mc
, PRIBIO
, "mlxwccb", 0);
2013 if (mc
->mc_status
!= 0) {
2014 aprint_error_dev(&mlx
->mlx_dv
, "command failed - %s\n",
2015 mlx_ccb_diagnose(mc
));
2023 * Try to submit a CCB's mailbox to the controller for execution. Return
2024 * non-zero on timeout or error. Must be called with interrupts blocked.
2027 mlx_ccb_submit(struct mlx_softc
*mlx
, struct mlx_ccb
*mc
)
2031 /* Save the ident so we can handle this command when complete. */
2032 mc
->mc_mbox
[1] = (u_int8_t
)(mc
->mc_ident
+ 1);
2034 /* Mark the command as currently being processed. */
2035 mc
->mc_status
= MLX_STATUS_BUSY
;
2036 mc
->mc_expiry
= time_second
+ MLX_TIMEOUT
;
2038 /* Spin waiting for the mailbox. */
2039 for (i
= 100; i
!= 0; i
--) {
2041 r
= (*mlx
->mlx_submit
)(mlx
, mc
);
2050 DPRINTF(("mlx_ccb_submit: rejected; queueing\n"));
2051 mc
->mc_status
= MLX_STATUS_WEDGED
;
2056 * Return a string that describes why a command has failed.
2059 mlx_ccb_diagnose(struct mlx_ccb
*mc
)
2061 static char tbuf
[80];
2064 for (i
= 0; i
< sizeof(mlx_msgs
) / sizeof(mlx_msgs
[0]); i
++)
2065 if ((mc
->mc_mbox
[0] == mlx_msgs
[i
].command
||
2066 mlx_msgs
[i
].command
== 0) &&
2067 mc
->mc_status
== mlx_msgs
[i
].status
) {
2068 snprintf(tbuf
, sizeof(tbuf
), "%s (0x%x)",
2069 mlx_status_msgs
[mlx_msgs
[i
].msg
], mc
->mc_status
);
2073 snprintf(tbuf
, sizeof(tbuf
), "unknown response 0x%x for command 0x%x",
2074 (int)mc
->mc_status
, (int)mc
->mc_mbox
[0]);
2080 * Poll the controller for completed commands. Returns non-zero if one or
2081 * more commands were completed. Must be called with interrupts blocked.
2084 mlx_intr(void *cookie
)
2086 struct mlx_softc
*mlx
;
2089 u_int ident
, status
;
2094 while ((*mlx
->mlx_findcomplete
)(mlx
, &ident
, &status
) != 0) {
2098 if (ident
>= MLX_MAX_QUEUECNT
) {
2099 aprint_error_dev(&mlx
->mlx_dv
, "bad completion returned\n");
2103 mc
= mlx
->mlx_ccbs
+ ident
;
2105 if (mc
->mc_status
!= MLX_STATUS_BUSY
) {
2106 aprint_error_dev(&mlx
->mlx_dv
, "bad completion returned\n");
2110 TAILQ_REMOVE(&mlx
->mlx_ccb_worklist
, mc
, mc_chain
.tailq
);
2112 /* Record status and notify the initiator, if requested. */
2113 mc
->mc_status
= status
;
2114 if (mc
->mc_mx
.mx_handler
!= NULL
)
2115 (*mc
->mc_mx
.mx_handler
)(mc
);
2116 else if ((mc
->mc_flags
& MC_WAITING
) != 0)
2120 /* If we've completed any commands, try posting some more. */
2122 mlx_ccb_enqueue(mlx
, NULL
);
2128 * Emit a string describing the firmware handshake status code, and return a
2129 * flag indicating whether the code represents a fatal error.
2131 * Error code interpretations are from the Linux driver, and don't directly
2132 * match the messages printed by Mylex's BIOS. This may change if
2133 * documentation on the codes is forthcoming.
2136 mlx_fw_message(struct mlx_softc
*mlx
, int error
, int param1
, int param2
)
2142 fmt
= "physical drive %d:%d not responding";
2147 * We could be neater about this and give some indication
2148 * when we receive more of them.
2150 if ((mlx
->mlx_flags
& MLXF_SPINUP_REPORTED
) == 0) {
2151 printf("%s: spinning up drives...\n",
2152 device_xname(&mlx
->mlx_dv
));
2153 mlx
->mlx_flags
|= MLXF_SPINUP_REPORTED
;
2158 fmt
= "configuration checksum error";
2162 fmt
= "mirror race recovery failed";
2166 fmt
= "mirror race recovery in progress";
2170 fmt
= "physical drive %d:%d COD mismatch";
2174 fmt
= "logical drive installation aborted";
2178 fmt
= "mirror race on a critical system drive";
2182 fmt
= "new controller configuration found";
2186 aprint_error_dev(&mlx
->mlx_dv
, "FATAL MEMORY PARITY ERROR\n");
2190 aprint_error_dev(&mlx
->mlx_dv
, "unknown firmware init error %02x:%02x:%02x\n",
2191 error
, param1
, param2
);
2195 aprint_normal_dev(&mlx
->mlx_dv
, "");
2196 aprint_normal(fmt
, param2
, param1
);
2197 aprint_normal("\n");