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