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