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