1 /* $NetBSD: mlx.c,v 1.16 2002/04/23 11:57:45 ad 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.16 2002/04/23 11:57:45 ad 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 *arg = i; 860 return (0); 861 } 862 } 863 return (ENOENT); 864 } 865 866 switch (cmd) { 867 case MLXD_DETACH: 868 case MLXD_STATUS: 869 case MLXD_CHECKASYNC: 870 if ((u_int)*arg >= MLX_MAX_DRIVES) 871 return (EINVAL); 872 ms = &mlx->mlx_sysdrive[*arg]; 873 if (*arg > MLX_MAX_DRIVES || ms->ms_dv == NULL) 874 return (ENOENT); 875 break; 876 877 default: 878 return (ENOTTY); 879 } 880 881 switch (cmd) { 882 case MLXD_DETACH: 883 /* 884 * Disconnect from the specified drive; it may be about to go 885 * away. 886 */ 887 return (config_detach(ms->ms_dv, 0)); 888 889 case MLXD_STATUS: 890 /* 891 * Return the current status of this drive. 892 */ 893 *arg = ms->ms_state; 894 return (0); 895 896 case MLXD_CHECKASYNC: 897 /* 898 * Start a background consistency check on this drive. 899 */ 900 if (mlx->mlx_bg != 0) { 901 *arg = 0x0106; 902 return (EBUSY); 903 } 904 905 switch (result = mlx_check(mlx, *arg)) { 906 case 0: 907 rv = 0; 908 break; 909 case 0x10000: 910 rv = ENOMEM; /* Couldn't set up the command. */ 911 break; 912 case 0x0002: 913 rv = EIO; 914 break; 915 case 0x0105: 916 rv = ERANGE; 917 break; 918 case 0x0106: 919 rv = EBUSY; 920 break; 921 default: 922 rv = EINVAL; 923 break; 924 } 925 926 if (rv == 0) 927 mlx->mlx_bg = MLX_BG_CHECK; 928 *arg = result; 929 return (rv); 930 } 931 932 return (ENOTTY); /* XXX shut up gcc */ 933 } 934 935 /* 936 * Fire off commands to periodically check the status of connected drives. 937 * Check for commands that have timed out. 938 */ 939 static void 940 mlx_periodic_create(void *cookie) 941 { 942 int rv; 943 944 rv = kthread_create1(mlx_periodic_thread, NULL, &mlx_periodic_proc, 945 "mlxmonitor"); 946 if (rv == 0) 947 return; 948 949 printf("mlx_periodic_create: unable to create thread (%d)\n", rv); 950 } 951 952 static void 953 mlx_periodic_thread(void *cookie) 954 { 955 struct mlx_softc *mlx; 956 int i; 957 958 for (;;) { 959 for (i = 0; i < mlx_cd.cd_ndevs; i++) 960 if ((mlx = device_lookup(&mlx_cd, i)) != NULL) 961 mlx_periodic(mlx); 962 963 tsleep(mlx_periodic_thread, PWAIT, "mlxzzz", hz); 964 } 965 } 966 967 static void 968 mlx_periodic(struct mlx_softc *mlx) 969 { 970 struct mlx_ccb *mc, *nmc; 971 int etype, s; 972 time_t ct; 973 974 ct = mlx_curtime(); 975 976 if ((mlx->mlx_pause.mp_which != 0) && 977 (mlx->mlx_pause.mp_when > 0) && 978 (ct >= mlx->mlx_pause.mp_when)) { 979 /* 980 * Start bus pause. 981 */ 982 mlx_pause_action(mlx); 983 mlx->mlx_pause.mp_when = 0; 984 } else if ((mlx->mlx_pause.mp_which != 0) && 985 (mlx->mlx_pause.mp_when == 0)) { 986 /* 987 * Stop pause if required. 988 */ 989 if (ct >= mlx->mlx_pause.mp_howlong) { 990 mlx_pause_action(mlx); 991 mlx->mlx_pause.mp_which = 0; 992 } 993 } else if (ct > (mlx->mlx_lastpoll + 10)) { 994 /* 995 * Run normal periodic activities... 996 */ 997 mlx->mlx_lastpoll = ct; 998 999 /* 1000 * Check controller status. 1001 */ 1002 if ((mlx->mlx_flags & MLXF_PERIODIC_CTLR) == 0) { 1003 mlx->mlx_flags |= MLXF_PERIODIC_CTLR; 1004 1005 if (mlx->mlx_iftype == 2) 1006 etype = MLX_CMD_ENQUIRY_OLD; 1007 else 1008 etype = MLX_CMD_ENQUIRY; 1009 1010 mlx_enquire(mlx, etype, max(sizeof(struct mlx_enquiry), 1011 sizeof(struct mlx_enquiry_old)), 1012 mlx_periodic_enquiry, 1); 1013 } 1014 1015 /* 1016 * Check system drive status. 1017 */ 1018 if ((mlx->mlx_flags & MLXF_PERIODIC_DRIVE) == 0) { 1019 mlx->mlx_flags |= MLXF_PERIODIC_DRIVE; 1020 mlx_enquire(mlx, MLX_CMD_ENQSYSDRIVE, 1021 sizeof(struct mlx_enq_sys_drive) * MLX_MAX_DRIVES, 1022 mlx_periodic_enquiry, 1); 1023 } 1024 } 1025 1026 /* 1027 * Get drive rebuild/check status. 1028 */ 1029 if ((mlx->mlx_flags & MLXF_PERIODIC_REBUILD) == 0) { 1030 mlx->mlx_flags |= MLXF_PERIODIC_REBUILD; 1031 mlx_enquire(mlx, MLX_CMD_REBUILDSTAT, 1032 sizeof(struct mlx_rebuild_stat), mlx_periodic_rebuild, 1); 1033 } 1034 1035 /* 1036 * Time-out busy CCBs. 1037 */ 1038 s = splbio(); 1039 for (mc = TAILQ_FIRST(&mlx->mlx_ccb_worklist); mc != NULL; mc = nmc) { 1040 nmc = TAILQ_NEXT(mc, mc_chain.tailq); 1041 if (mc->mc_expiry > ct) { 1042 /* 1043 * The remaining CCBs will expire after this one, so 1044 * there's no point in going further. 1045 */ 1046 break; 1047 } 1048 TAILQ_REMOVE(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq); 1049 mc->mc_status = MLX_STATUS_LOST; 1050 if (mc->mc_mx.mx_handler != NULL) 1051 (*mc->mc_mx.mx_handler)(mc); 1052 else if ((mc->mc_flags & MC_WAITING) != 0) 1053 wakeup(mc); 1054 } 1055 splx(s); 1056 } 1057 1058 /* 1059 * Handle the result of an ENQUIRY command instigated by periodic status 1060 * polling. 1061 */ 1062 static void 1063 mlx_periodic_enquiry(struct mlx_ccb *mc) 1064 { 1065 struct mlx_softc *mlx; 1066 struct mlx_enquiry *me; 1067 struct mlx_enquiry_old *meo; 1068 struct mlx_enq_sys_drive *mes; 1069 struct mlx_sysdrive *dr; 1070 const char *statestr; 1071 int i, j; 1072 u_int lsn; 1073 1074 mlx = (struct mlx_softc *)mc->mc_mx.mx_dv; 1075 1076 /* 1077 * Command completed OK? 1078 */ 1079 if (mc->mc_status != 0) { 1080 printf("%s: periodic enquiry failed - %s\n", 1081 mlx->mlx_dv.dv_xname, mlx_ccb_diagnose(mc)); 1082 goto out; 1083 } 1084 1085 /* 1086 * Respond to command. 1087 */ 1088 switch (mc->mc_mbox[0]) { 1089 case MLX_CMD_ENQUIRY_OLD: 1090 /* 1091 * This is currently a bit fruitless, as we don't know how 1092 * to extract the eventlog pointer yet. 1093 */ 1094 me = (struct mlx_enquiry *)mc->mc_mx.mx_context; 1095 meo = (struct mlx_enquiry_old *)mc->mc_mx.mx_context; 1096 1097 /* Convert data in-place to new format */ 1098 i = sizeof(me->me_dead) / sizeof(me->me_dead[0]); 1099 while (--i >= 0) { 1100 me->me_dead[i].dd_chan = meo->me_dead[i].dd_chan; 1101 me->me_dead[i].dd_targ = meo->me_dead[i].dd_targ; 1102 } 1103 1104 me->me_misc_flags = 0; 1105 me->me_rebuild_count = meo->me_rebuild_count; 1106 me->me_dead_count = meo->me_dead_count; 1107 me->me_critical_sd_count = meo->me_critical_sd_count; 1108 me->me_event_log_seq_num = 0; 1109 me->me_offline_sd_count = meo->me_offline_sd_count; 1110 me->me_max_commands = meo->me_max_commands; 1111 me->me_rebuild_flag = meo->me_rebuild_flag; 1112 me->me_fwmajor = meo->me_fwmajor; 1113 me->me_fwminor = meo->me_fwminor; 1114 me->me_status_flags = meo->me_status_flags; 1115 me->me_flash_age = meo->me_flash_age; 1116 1117 i = sizeof(me->me_drvsize) / sizeof(me->me_drvsize[0]); 1118 j = sizeof(meo->me_drvsize) / sizeof(meo->me_drvsize[0]); 1119 1120 while (--i >= 0) { 1121 if (i >= j) 1122 me->me_drvsize[i] = 0; 1123 else 1124 me->me_drvsize[i] = meo->me_drvsize[i]; 1125 } 1126 1127 me->me_num_sys_drvs = meo->me_num_sys_drvs; 1128 1129 /* FALLTHROUGH */ 1130 1131 case MLX_CMD_ENQUIRY: 1132 /* 1133 * Generic controller status update. We could do more with 1134 * this than just checking the event log. 1135 */ 1136 me = (struct mlx_enquiry *)mc->mc_mx.mx_context; 1137 lsn = le16toh(me->me_event_log_seq_num); 1138 1139 if (mlx->mlx_currevent == -1) { 1140 /* Initialise our view of the event log. */ 1141 mlx->mlx_currevent = lsn; 1142 mlx->mlx_lastevent = lsn; 1143 } else if (lsn != mlx->mlx_lastevent && 1144 (mlx->mlx_flags & MLXF_EVENTLOG_BUSY) == 0) { 1145 /* Record where current events are up to */ 1146 mlx->mlx_currevent = lsn; 1147 1148 /* Mark the event log as busy. */ 1149 mlx->mlx_flags |= MLXF_EVENTLOG_BUSY; 1150 1151 /* Drain new eventlog entries. */ 1152 mlx_periodic_eventlog_poll(mlx); 1153 } 1154 break; 1155 1156 case MLX_CMD_ENQSYSDRIVE: 1157 /* 1158 * Perform drive status comparison to see if something 1159 * has failed. Don't perform the comparison if we're 1160 * reconfiguring, since the system drive table will be 1161 * changing. 1162 */ 1163 if ((mlx->mlx_flags & MLXF_RESCANNING) != 0) 1164 break; 1165 1166 mes = (struct mlx_enq_sys_drive *)mc->mc_mx.mx_context; 1167 dr = &mlx->mlx_sysdrive[0]; 1168 1169 for (i = 0; i < mlx->mlx_numsysdrives; i++) { 1170 /* Has state been changed by controller? */ 1171 if (dr->ms_state != mes[i].sd_state) { 1172 switch (mes[i].sd_state) { 1173 case MLX_SYSD_OFFLINE: 1174 statestr = "offline"; 1175 break; 1176 1177 case MLX_SYSD_ONLINE: 1178 statestr = "online"; 1179 break; 1180 1181 case MLX_SYSD_CRITICAL: 1182 statestr = "critical"; 1183 break; 1184 1185 default: 1186 statestr = "unknown"; 1187 break; 1188 } 1189 1190 printf("%s: unit %d %s\n", mlx->mlx_dv.dv_xname, 1191 i, statestr); 1192 1193 /* Save new state. */ 1194 dr->ms_state = mes[i].sd_state; 1195 } 1196 } 1197 break; 1198 1199 #ifdef DIAGNOSTIC 1200 default: 1201 printf("%s: mlx_periodic_enquiry: eh?\n", 1202 mlx->mlx_dv.dv_xname); 1203 break; 1204 #endif 1205 } 1206 1207 out: 1208 if (mc->mc_mbox[0] == MLX_CMD_ENQSYSDRIVE) 1209 mlx->mlx_flags &= ~MLXF_PERIODIC_DRIVE; 1210 else 1211 mlx->mlx_flags &= ~MLXF_PERIODIC_CTLR; 1212 1213 free(mc->mc_mx.mx_context, M_DEVBUF); 1214 mlx_ccb_free(mlx, mc); 1215 } 1216 1217 /* 1218 * Instigate a poll for one event log message on (mlx). We only poll for 1219 * one message at a time, to keep our command usage down. 1220 */ 1221 static void 1222 mlx_periodic_eventlog_poll(struct mlx_softc *mlx) 1223 { 1224 struct mlx_ccb *mc; 1225 void *result; 1226 int rv; 1227 1228 result = NULL; 1229 1230 if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0) 1231 goto out; 1232 1233 if ((result = malloc(1024, M_DEVBUF, M_WAITOK)) == NULL) { 1234 rv = ENOMEM; 1235 goto out; 1236 } 1237 if ((rv = mlx_ccb_map(mlx, mc, result, 1024, MC_XFER_IN)) != 0) 1238 goto out; 1239 if (mc->mc_nsgent != 1) { 1240 mlx_ccb_unmap(mlx, mc); 1241 printf("mlx_periodic_eventlog_poll: too many segs\n"); 1242 goto out; 1243 } 1244 1245 /* Build the command to get one log entry. */ 1246 mlx_make_type3(mc, MLX_CMD_LOGOP, MLX_LOGOP_GET, 1, 1247 mlx->mlx_lastevent, 0, 0, mc->mc_xfer_phys, 0); 1248 1249 mc->mc_mx.mx_handler = mlx_periodic_eventlog_respond; 1250 mc->mc_mx.mx_dv = &mlx->mlx_dv; 1251 mc->mc_mx.mx_context = result; 1252 1253 /* Start the command. */ 1254 mlx_ccb_enqueue(mlx, mc); 1255 1256 out: 1257 if (rv != 0) { 1258 if (mc != NULL) 1259 mlx_ccb_free(mlx, mc); 1260 if (result != NULL) 1261 free(result, M_DEVBUF); 1262 } 1263 } 1264 1265 /* 1266 * Handle the result of polling for a log message, generate diagnostic 1267 * output. If this wasn't the last message waiting for us, we'll go collect 1268 * another. 1269 */ 1270 static void 1271 mlx_periodic_eventlog_respond(struct mlx_ccb *mc) 1272 { 1273 struct mlx_softc *mlx; 1274 struct mlx_eventlog_entry *el; 1275 const char *reason; 1276 u_int8_t sensekey, chan, targ; 1277 1278 mlx = (struct mlx_softc *)mc->mc_mx.mx_dv; 1279 el = mc->mc_mx.mx_context; 1280 mlx_ccb_unmap(mlx, mc); 1281 1282 mlx->mlx_lastevent++; 1283 1284 if (mc->mc_status == 0) { 1285 switch (el->el_type) { 1286 case MLX_LOGMSG_SENSE: /* sense data */ 1287 sensekey = el->el_sense & 0x0f; 1288 chan = (el->el_target >> 4) & 0x0f; 1289 targ = el->el_target & 0x0f; 1290 1291 /* 1292 * This is the only sort of message we understand at 1293 * the moment. The tests here are probably 1294 * incomplete. 1295 */ 1296 1297 /* 1298 * Mylex vendor-specific message indicating a drive 1299 * was killed? 1300 */ 1301 if (sensekey == 9 && el->el_asc == 0x80) { 1302 if (el->el_asq < sizeof(mlx_sense_msgs) / 1303 sizeof(mlx_sense_msgs[0])) 1304 reason = mlx_sense_msgs[el->el_asq]; 1305 else 1306 reason = "for unknown reason"; 1307 1308 printf("%s: physical drive %d:%d killed %s\n", 1309 mlx->mlx_dv.dv_xname, chan, targ, reason); 1310 } 1311 1312 /* 1313 * SCSI drive was reset? 1314 */ 1315 if (sensekey == 6 && el->el_asc == 0x29) 1316 printf("%s: physical drive %d:%d reset\n", 1317 mlx->mlx_dv.dv_xname, chan, targ); 1318 1319 /* 1320 * SCSI drive error? 1321 */ 1322 if (!(sensekey == 0 || 1323 (sensekey == 2 && 1324 el->el_asc == 0x04 && 1325 (el->el_asq == 0x01 || el->el_asq == 0x02)))) { 1326 printf("%s: physical drive %d:%d error log: " 1327 "sense = %d asc = %x asq = %x\n", 1328 mlx->mlx_dv.dv_xname, chan, targ, sensekey, 1329 el->el_asc, el->el_asq); 1330 printf("%s: info = %d:%d:%d:%d " 1331 " csi = %d:%d:%d:%d\n", 1332 mlx->mlx_dv.dv_xname, 1333 el->el_information[0], 1334 el->el_information[1], 1335 el->el_information[2], 1336 el->el_information[3], 1337 el->el_csi[0], el->el_csi[1], 1338 el->el_csi[2], el->el_csi[3]); 1339 } 1340 1341 break; 1342 1343 default: 1344 printf("%s: unknown log message type 0x%x\n", 1345 mlx->mlx_dv.dv_xname, el->el_type); 1346 break; 1347 } 1348 } else { 1349 printf("%s: error reading message log - %s\n", 1350 mlx->mlx_dv.dv_xname, mlx_ccb_diagnose(mc)); 1351 1352 /* 1353 * Give up on all the outstanding messages, as we may have 1354 * come unsynched. 1355 */ 1356 mlx->mlx_lastevent = mlx->mlx_currevent; 1357 } 1358 1359 free(mc->mc_mx.mx_context, M_DEVBUF); 1360 mlx_ccb_free(mlx, mc); 1361 1362 /* 1363 * Is there another message to obtain? 1364 */ 1365 if (mlx->mlx_lastevent != mlx->mlx_currevent) 1366 mlx_periodic_eventlog_poll(mlx); 1367 else 1368 mlx->mlx_flags &= ~MLXF_EVENTLOG_BUSY; 1369 } 1370 1371 /* 1372 * Handle check/rebuild operations in progress. 1373 */ 1374 static void 1375 mlx_periodic_rebuild(struct mlx_ccb *mc) 1376 { 1377 struct mlx_softc *mlx; 1378 const char *opstr; 1379 struct mlx_rebuild_status *mr; 1380 1381 mlx = (struct mlx_softc *)mc->mc_mx.mx_dv; 1382 mr = mc->mc_mx.mx_context; 1383 mlx_ccb_unmap(mlx, mc); 1384 1385 switch (mc->mc_status) { 1386 case 0: 1387 /* 1388 * Operation running, update stats. 1389 */ 1390 mlx->mlx_rebuildstat = *mr; 1391 1392 /* Spontaneous rebuild/check? */ 1393 if (mlx->mlx_bg == 0) { 1394 mlx->mlx_bg = MLX_BG_SPONTANEOUS; 1395 printf("%s: background check/rebuild started\n", 1396 mlx->mlx_dv.dv_xname); 1397 } 1398 break; 1399 1400 case 0x0105: 1401 /* 1402 * Nothing running, finalise stats and report. 1403 */ 1404 switch (mlx->mlx_bg) { 1405 case MLX_BG_CHECK: 1406 /* XXX Print drive? */ 1407 opstr = "consistency check"; 1408 break; 1409 1410 case MLX_BG_REBUILD: 1411 /* XXX Print channel:target? */ 1412 opstr = "drive rebuild"; 1413 break; 1414 1415 case MLX_BG_SPONTANEOUS: 1416 default: 1417 /* 1418 * If we have previously been non-idle, report the 1419 * transition 1420 */ 1421 if (mlx->mlx_rebuildstat.rs_code != 1422 MLX_REBUILDSTAT_IDLE) 1423 opstr = "background check/rebuild"; 1424 else 1425 opstr = NULL; 1426 } 1427 1428 if (opstr != NULL) 1429 printf("%s: %s completed\n", mlx->mlx_dv.dv_xname, 1430 opstr); 1431 1432 mlx->mlx_bg = 0; 1433 mlx->mlx_rebuildstat.rs_code = MLX_REBUILDSTAT_IDLE; 1434 break; 1435 } 1436 1437 free(mc->mc_mx.mx_context, M_DEVBUF); 1438 mlx_ccb_free(mlx, mc); 1439 mlx->mlx_flags &= ~MLXF_PERIODIC_REBUILD; 1440 } 1441 1442 /* 1443 * It's time to perform a channel pause action for (mlx), either start or 1444 * stop the pause. 1445 */ 1446 static void 1447 mlx_pause_action(struct mlx_softc *mlx) 1448 { 1449 struct mlx_ccb *mc; 1450 int failsafe, i, cmd; 1451 time_t ct; 1452 1453 ct = mlx_curtime(); 1454 1455 /* What are we doing here? */ 1456 if (mlx->mlx_pause.mp_when == 0) { 1457 cmd = MLX_CMD_STARTCHANNEL; 1458 failsafe = 0; 1459 } else { 1460 cmd = MLX_CMD_STOPCHANNEL; 1461 1462 /* 1463 * Channels will always start again after the failsafe 1464 * period, which is specified in multiples of 30 seconds. 1465 * This constrains us to a maximum pause of 450 seconds. 1466 */ 1467 failsafe = ((mlx->mlx_pause.mp_howlong - ct) + 5) / 30; 1468 1469 if (failsafe > 0xf) { 1470 failsafe = 0xf; 1471 mlx->mlx_pause.mp_howlong = ct + (0xf * 30) - 5; 1472 } 1473 } 1474 1475 /* Build commands for every channel requested. */ 1476 for (i = 0; i < mlx->mlx_enq2->me_actual_channels; i++) { 1477 if ((1 << i) & mlx->mlx_pause.mp_which) { 1478 if (mlx_ccb_alloc(mlx, &mc, 1) != 0) { 1479 printf("%s: %s failed for channel %d\n", 1480 mlx->mlx_dv.dv_xname, 1481 cmd == MLX_CMD_STOPCHANNEL ? 1482 "pause" : "resume", i); 1483 continue; 1484 } 1485 1486 /* Build the command. */ 1487 mlx_make_type2(mc, cmd, (failsafe << 4) | i, 0, 0, 1488 0, 0, 0, 0, 0); 1489 mc->mc_mx.mx_handler = mlx_pause_done; 1490 mc->mc_mx.mx_dv = &mlx->mlx_dv; 1491 1492 mlx_ccb_enqueue(mlx, mc); 1493 } 1494 } 1495 } 1496 1497 static void 1498 mlx_pause_done(struct mlx_ccb *mc) 1499 { 1500 struct mlx_softc *mlx; 1501 int command, channel; 1502 1503 mlx = (struct mlx_softc *)mc->mc_mx.mx_dv; 1504 command = mc->mc_mbox[0]; 1505 channel = mc->mc_mbox[2] & 0xf; 1506 1507 if (mc->mc_status != 0) 1508 printf("%s: %s command failed - %s\n", mlx->mlx_dv.dv_xname, 1509 command == MLX_CMD_STOPCHANNEL ? "pause" : "resume", 1510 mlx_ccb_diagnose(mc)); 1511 else if (command == MLX_CMD_STOPCHANNEL) 1512 printf("%s: channel %d pausing for %ld seconds\n", 1513 mlx->mlx_dv.dv_xname, channel, 1514 (long)(mlx->mlx_pause.mp_howlong - mlx_curtime())); 1515 else 1516 printf("%s: channel %d resuming\n", mlx->mlx_dv.dv_xname, 1517 channel); 1518 1519 mlx_ccb_free(mlx, mc); 1520 } 1521 1522 /* 1523 * Perform an Enquiry command using a type-3 command buffer and a return a 1524 * single linear result buffer. If the completion function is specified, it 1525 * will be called with the completed command (and the result response will 1526 * not be valid until that point). Otherwise, the command will either be 1527 * busy-waited for (interrupts must be blocked), or slept for. 1528 */ 1529 static void * 1530 mlx_enquire(struct mlx_softc *mlx, int command, size_t bufsize, 1531 void (*handler)(struct mlx_ccb *mc), int waitok) 1532 { 1533 struct mlx_ccb *mc; 1534 void *result; 1535 int rv, mapped; 1536 1537 result = NULL; 1538 mapped = 0; 1539 1540 if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0) 1541 goto out; 1542 1543 result = malloc(bufsize, M_DEVBUF, waitok ? M_WAITOK : M_NOWAIT); 1544 if (result == NULL) { 1545 printf("mlx_enquire: malloc() failed\n"); 1546 goto out; 1547 } 1548 if ((rv = mlx_ccb_map(mlx, mc, result, bufsize, MC_XFER_IN)) != 0) 1549 goto out; 1550 mapped = 1; 1551 if (mc->mc_nsgent != 1) { 1552 printf("mlx_enquire: too many segs\n"); 1553 goto out; 1554 } 1555 1556 /* Build an enquiry command. */ 1557 mlx_make_type2(mc, command, 0, 0, 0, 0, 0, 0, mc->mc_xfer_phys, 0); 1558 1559 /* Do we want a completion callback? */ 1560 if (handler != NULL) { 1561 mc->mc_mx.mx_context = result; 1562 mc->mc_mx.mx_dv = &mlx->mlx_dv; 1563 mc->mc_mx.mx_handler = handler; 1564 mlx_ccb_enqueue(mlx, mc); 1565 } else { 1566 /* Run the command in either polled or wait mode. */ 1567 if (waitok) 1568 rv = mlx_ccb_wait(mlx, mc); 1569 else 1570 rv = mlx_ccb_poll(mlx, mc, 5000); 1571 } 1572 1573 out: 1574 /* We got a command, but nobody else will free it. */ 1575 if (handler == NULL && mc != NULL) { 1576 if (mapped) 1577 mlx_ccb_unmap(mlx, mc); 1578 mlx_ccb_free(mlx, mc); 1579 } 1580 1581 /* We got an error, and we allocated a result. */ 1582 if (rv != 0 && result != NULL) { 1583 if (handler != NULL && mc != NULL) { 1584 if (mapped) 1585 mlx_ccb_unmap(mlx, mc); 1586 mlx_ccb_free(mlx, mc); 1587 } 1588 free(result, M_DEVBUF); 1589 result = NULL; 1590 } 1591 1592 return (result); 1593 } 1594 1595 /* 1596 * Perform a Flush command on the nominated controller. 1597 * 1598 * May be called with interrupts enabled or disabled; will not return until 1599 * the flush operation completes or fails. 1600 */ 1601 int 1602 mlx_flush(struct mlx_softc *mlx, int async) 1603 { 1604 struct mlx_ccb *mc; 1605 int rv; 1606 1607 if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0) 1608 goto out; 1609 1610 /* Build a flush command and fire it off. */ 1611 mlx_make_type2(mc, MLX_CMD_FLUSH, 0, 0, 0, 0, 0, 0, 0, 0); 1612 1613 if (async) 1614 rv = mlx_ccb_wait(mlx, mc); 1615 else 1616 rv = mlx_ccb_poll(mlx, mc, MLX_TIMEOUT * 1000); 1617 if (rv != 0) 1618 goto out; 1619 1620 /* Command completed OK? */ 1621 if (mc->mc_status != 0) { 1622 printf("%s: FLUSH failed - %s\n", mlx->mlx_dv.dv_xname, 1623 mlx_ccb_diagnose(mc)); 1624 rv = EIO; 1625 } 1626 out: 1627 if (mc != NULL) 1628 mlx_ccb_free(mlx, mc); 1629 1630 return (rv); 1631 } 1632 1633 /* 1634 * Start a background consistency check on (drive). 1635 */ 1636 static int 1637 mlx_check(struct mlx_softc *mlx, int drive) 1638 { 1639 struct mlx_ccb *mc; 1640 int rv; 1641 1642 /* Get ourselves a command buffer. */ 1643 rv = 0x10000; 1644 1645 if (mlx_ccb_alloc(mlx, &mc, 1) != 0) 1646 goto out; 1647 1648 /* Build a checkasync command, set the "fix it" flag. */ 1649 mlx_make_type2(mc, MLX_CMD_CHECKASYNC, 0, 0, 0, 0, 0, drive | 0x80, 1650 0, 0); 1651 1652 /* Start the command and wait for it to be returned. */ 1653 if (mlx_ccb_wait(mlx, mc) != 0) 1654 goto out; 1655 1656 /* Command completed OK? */ 1657 if (mc->mc_status != 0) 1658 printf("%s: CHECK ASYNC failed - %s\n", mlx->mlx_dv.dv_xname, 1659 mlx_ccb_diagnose(mc)); 1660 else 1661 printf("%s: consistency check started", 1662 mlx->mlx_sysdrive[drive].ms_dv->dv_xname); 1663 1664 rv = mc->mc_status; 1665 out: 1666 if (mc != NULL) 1667 mlx_ccb_free(mlx, mc); 1668 1669 return (rv); 1670 } 1671 1672 /* 1673 * Start a background rebuild of the physical drive at (channel),(target). 1674 * 1675 * May be called with interrupts enabled or disabled; will return as soon as 1676 * the operation has started or been refused. 1677 */ 1678 static int 1679 mlx_rebuild(struct mlx_softc *mlx, int channel, int target) 1680 { 1681 struct mlx_ccb *mc; 1682 int error; 1683 1684 error = 0x10000; 1685 if (mlx_ccb_alloc(mlx, &mc, 1) != 0) 1686 goto out; 1687 1688 /* Build a rebuildasync command, set the "fix it" flag. */ 1689 mlx_make_type2(mc, MLX_CMD_REBUILDASYNC, channel, target, 0, 0, 0, 0, 1690 0, 0); 1691 1692 /* Start the command and wait for it to be returned. */ 1693 if (mlx_ccb_wait(mlx, mc) != 0) 1694 goto out; 1695 1696 /* Command completed OK? */ 1697 printf("%s: ", mlx->mlx_dv.dv_xname); 1698 if (mc->mc_status != 0) 1699 printf("REBUILD ASYNC failed - %s\n", mlx_ccb_diagnose(mc)); 1700 else 1701 printf("rebuild started for %d:%d\n", channel, target); 1702 1703 error = mc->mc_status; 1704 1705 out: 1706 if (mc != NULL) 1707 mlx_ccb_free(mlx, mc); 1708 1709 return (error); 1710 } 1711 1712 /* 1713 * Take a command from user-space and try to run it. 1714 * 1715 * XXX Note that this can't perform very much in the way of error checking, 1716 * XXX and as such, applications _must_ be considered trustworthy. 1717 * 1718 * XXX Commands using S/G for data are not supported. 1719 */ 1720 static int 1721 mlx_user_command(struct mlx_softc *mlx, struct mlx_usercommand *mu) 1722 { 1723 struct mlx_ccb *mc; 1724 struct mlx_dcdb *dcdb; 1725 void *kbuf; 1726 int rv, mapped; 1727 1728 if ((mu->mu_bufdir & ~MU_XFER_MASK) != 0) 1729 return (EINVAL); 1730 1731 kbuf = NULL; 1732 dcdb = NULL; 1733 mapped = 0; 1734 1735 /* Get ourselves a command and copy in from user space. */ 1736 if ((rv = mlx_ccb_alloc(mlx, &mc, 1)) != 0) { 1737 DPRINTF(("mlx_user_command: mlx_ccb_alloc = %d\n", rv)); 1738 goto out; 1739 } 1740 1741 memcpy(mc->mc_mbox, mu->mu_command, sizeof(mc->mc_mbox)); 1742 1743 /* 1744 * If we need a buffer for data transfer, allocate one and copy in 1745 * its initial contents. 1746 */ 1747 if (mu->mu_datasize > 0) { 1748 if (mu->mu_datasize > MAXPHYS) 1749 return (EINVAL); 1750 1751 kbuf = malloc(mu->mu_datasize, M_DEVBUF, M_WAITOK); 1752 if (kbuf == NULL) { 1753 DPRINTF(("mlx_user_command: malloc = NULL\n")); 1754 rv = ENOMEM; 1755 goto out; 1756 } 1757 1758 if ((mu->mu_bufdir & MU_XFER_OUT) != 0) { 1759 rv = copyin(mu->mu_buf, kbuf, mu->mu_datasize); 1760 if (rv != 0) { 1761 DPRINTF(("mlx_user_command: copyin = %d\n", 1762 rv)); 1763 goto out; 1764 } 1765 } 1766 1767 /* Map the buffer so the controller can see it. */ 1768 rv = mlx_ccb_map(mlx, mc, kbuf, mu->mu_datasize, mu->mu_bufdir); 1769 if (rv != 0) { 1770 DPRINTF(("mlx_user_command: mlx_ccb_map = %d\n", rv)); 1771 goto out; 1772 } 1773 if (mc->mc_nsgent > 1) { 1774 DPRINTF(("mlx_user_command: too many s/g entries\n")); 1775 rv = EFBIG; 1776 goto out; 1777 } 1778 mapped = 1; 1779 } 1780 1781 /* 1782 * If this is a passthrough SCSI command, the DCDB is packed at the 1783 * beginning of the data area. Fix up the DCDB to point to the correct physical 1784 * address and override any bufptr supplied by the caller since we know 1785 * what it's meant to be. 1786 */ 1787 if (mc->mc_mbox[0] == MLX_CMD_DIRECT_CDB) { 1788 dcdb = (struct mlx_dcdb *)kbuf; 1789 dcdb->dcdb_physaddr = mc->mc_xfer_phys + sizeof(*dcdb); 1790 mu->mu_bufptr = 8; 1791 } 1792 1793 /* 1794 * If there's a data buffer, fix up the command's buffer pointer. 1795 */ 1796 if (mu->mu_datasize > 0) { 1797 /* Range check the pointer to physical buffer address. */ 1798 if (mu->mu_bufptr < 0 || 1799 mu->mu_bufptr > sizeof(mu->mu_command) - 4) { 1800 DPRINTF(("mlx_user_command: bufptr botch\n")); 1801 rv = EINVAL; 1802 goto out; 1803 } 1804 1805 mc->mc_mbox[mu->mu_bufptr] = mc->mc_xfer_phys; 1806 mc->mc_mbox[mu->mu_bufptr+1] = mc->mc_xfer_phys >> 8; 1807 mc->mc_mbox[mu->mu_bufptr+2] = mc->mc_xfer_phys >> 16; 1808 mc->mc_mbox[mu->mu_bufptr+3] = mc->mc_xfer_phys >> 24; 1809 } 1810 1811 /* Submit the command and wait. */ 1812 if ((rv = mlx_ccb_wait(mlx, mc)) != 0) { 1813 #ifdef DEBUG 1814 printf("mlx_user_command: mlx_ccb_wait = %d\n", rv); 1815 #endif 1816 } 1817 1818 out: 1819 if (mc != NULL) { 1820 if (mapped) 1821 mlx_ccb_unmap(mlx, mc); 1822 mlx_ccb_free(mlx, mc); 1823 } 1824 1825 /* Copy out status and data */ 1826 mu->mu_status = mc->mc_status; 1827 1828 if (kbuf != NULL) { 1829 if (mu->mu_datasize > 0 && (mu->mu_bufdir & MU_XFER_IN) != 0) { 1830 rv = copyout(kbuf, mu->mu_buf, mu->mu_datasize); 1831 #ifdef DIAGNOSTIC 1832 if (rv != 0) 1833 printf("mlx_user_command: copyout = %d\n", rv); 1834 #endif 1835 } 1836 } 1837 if (kbuf != NULL) 1838 free(kbuf, M_DEVBUF); 1839 1840 return (rv); 1841 } 1842 1843 /* 1844 * Allocate and initialise a CCB. 1845 */ 1846 int 1847 mlx_ccb_alloc(struct mlx_softc *mlx, struct mlx_ccb **mcp, int special) 1848 { 1849 struct mlx_ccb *mc; 1850 int s; 1851 1852 s = splbio(); 1853 if ((!special && mlx->mlx_nccbs_free < MLX_NCCBS_RESERVE) || 1854 SLIST_FIRST(&mlx->mlx_ccb_freelist) == NULL) { 1855 splx(s); 1856 *mcp = NULL; 1857 return (EAGAIN); 1858 } 1859 mc = SLIST_FIRST(&mlx->mlx_ccb_freelist); 1860 SLIST_REMOVE_HEAD(&mlx->mlx_ccb_freelist, mc_chain.slist); 1861 mlx->mlx_nccbs_free--; 1862 splx(s); 1863 1864 *mcp = mc; 1865 return (0); 1866 } 1867 1868 /* 1869 * Free a CCB. 1870 */ 1871 void 1872 mlx_ccb_free(struct mlx_softc *mlx, struct mlx_ccb *mc) 1873 { 1874 int s; 1875 1876 s = splbio(); 1877 mc->mc_flags = 0; 1878 SLIST_INSERT_HEAD(&mlx->mlx_ccb_freelist, mc, mc_chain.slist); 1879 mlx->mlx_nccbs_free++; 1880 splx(s); 1881 } 1882 1883 /* 1884 * If a CCB is specified, enqueue it. Pull CCBs off the software queue in 1885 * the order that they were enqueued and try to submit their mailboxes to 1886 * the controller for execution. 1887 */ 1888 void 1889 mlx_ccb_enqueue(struct mlx_softc *mlx, struct mlx_ccb *mc) 1890 { 1891 int s; 1892 1893 s = splbio(); 1894 1895 if (mc != NULL) 1896 SIMPLEQ_INSERT_TAIL(&mlx->mlx_ccb_queue, mc, mc_chain.simpleq); 1897 1898 while ((mc = SIMPLEQ_FIRST(&mlx->mlx_ccb_queue)) != NULL) { 1899 if (mlx_ccb_submit(mlx, mc) != 0) 1900 break; 1901 SIMPLEQ_REMOVE_HEAD(&mlx->mlx_ccb_queue, mc, mc_chain.simpleq); 1902 TAILQ_INSERT_TAIL(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq); 1903 } 1904 1905 splx(s); 1906 } 1907 1908 /* 1909 * Map the specified CCB's data buffer onto the bus, and fill the 1910 * scatter-gather list. 1911 */ 1912 int 1913 mlx_ccb_map(struct mlx_softc *mlx, struct mlx_ccb *mc, void *data, int size, 1914 int dir) 1915 { 1916 struct mlx_sgentry *sge; 1917 int nsegs, i, rv, sgloff; 1918 bus_dmamap_t xfer; 1919 1920 xfer = mc->mc_xfer_map; 1921 1922 rv = bus_dmamap_load(mlx->mlx_dmat, xfer, data, size, NULL, 1923 BUS_DMA_NOWAIT | BUS_DMA_STREAMING | 1924 ((dir & MC_XFER_IN) ? BUS_DMA_READ : BUS_DMA_WRITE)); 1925 if (rv != 0) 1926 return (rv); 1927 1928 nsegs = xfer->dm_nsegs; 1929 mc->mc_xfer_size = size; 1930 mc->mc_flags |= dir; 1931 mc->mc_nsgent = nsegs; 1932 mc->mc_xfer_phys = xfer->dm_segs[0].ds_addr; 1933 1934 sgloff = MLX_SGL_SIZE * mc->mc_ident; 1935 sge = (struct mlx_sgentry *)((caddr_t)mlx->mlx_sgls + sgloff); 1936 1937 for (i = 0; i < nsegs; i++, sge++) { 1938 sge->sge_addr = htole32(xfer->dm_segs[i].ds_addr); 1939 sge->sge_count = htole32(xfer->dm_segs[i].ds_len); 1940 } 1941 1942 if ((dir & MC_XFER_OUT) != 0) 1943 i = BUS_DMASYNC_PREWRITE; 1944 else 1945 i = 0; 1946 if ((dir & MC_XFER_IN) != 0) 1947 i |= BUS_DMASYNC_PREREAD; 1948 1949 bus_dmamap_sync(mlx->mlx_dmat, xfer, 0, mc->mc_xfer_size, i); 1950 bus_dmamap_sync(mlx->mlx_dmat, mlx->mlx_dmamap, sgloff, 1951 MLX_SGL_SIZE, BUS_DMASYNC_PREWRITE); 1952 1953 return (0); 1954 } 1955 1956 /* 1957 * Unmap the specified CCB's data buffer. 1958 */ 1959 void 1960 mlx_ccb_unmap(struct mlx_softc *mlx, struct mlx_ccb *mc) 1961 { 1962 int i; 1963 1964 bus_dmamap_sync(mlx->mlx_dmat, mlx->mlx_dmamap, 1965 MLX_SGL_SIZE * mc->mc_ident, MLX_SGL_SIZE, 1966 BUS_DMASYNC_POSTWRITE); 1967 1968 if ((mc->mc_flags & MC_XFER_OUT) != 0) 1969 i = BUS_DMASYNC_POSTWRITE; 1970 else 1971 i = 0; 1972 if ((mc->mc_flags & MC_XFER_IN) != 0) 1973 i |= BUS_DMASYNC_POSTREAD; 1974 1975 bus_dmamap_sync(mlx->mlx_dmat, mc->mc_xfer_map, 0, mc->mc_xfer_size, i); 1976 bus_dmamap_unload(mlx->mlx_dmat, mc->mc_xfer_map); 1977 } 1978 1979 /* 1980 * Submit the CCB, and busy-wait for it to complete. Return non-zero on 1981 * timeout or submission error. Must be called with interrupts blocked. 1982 */ 1983 int 1984 mlx_ccb_poll(struct mlx_softc *mlx, struct mlx_ccb *mc, int timo) 1985 { 1986 int rv; 1987 1988 mc->mc_mx.mx_handler = NULL; 1989 1990 if ((rv = mlx_ccb_submit(mlx, mc)) != 0) 1991 return (rv); 1992 TAILQ_INSERT_TAIL(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq); 1993 1994 for (timo *= 10; timo != 0; timo--) { 1995 mlx_intr(mlx); 1996 if (mc->mc_status != MLX_STATUS_BUSY) 1997 break; 1998 DELAY(100); 1999 } 2000 2001 if (timo != 0) { 2002 if (mc->mc_status != 0) { 2003 printf("%s: command failed - %s\n", 2004 mlx->mlx_dv.dv_xname, mlx_ccb_diagnose(mc)); 2005 rv = EIO; 2006 } else 2007 rv = 0; 2008 } else { 2009 printf("%s: command timed out\n", mlx->mlx_dv.dv_xname); 2010 rv = EIO; 2011 } 2012 2013 return (rv); 2014 } 2015 2016 /* 2017 * Enqueue the CCB, and sleep until it completes. Return non-zero on 2018 * timeout or error. 2019 */ 2020 int 2021 mlx_ccb_wait(struct mlx_softc *mlx, struct mlx_ccb *mc) 2022 { 2023 int s; 2024 2025 mc->mc_flags |= MC_WAITING; 2026 mc->mc_mx.mx_handler = NULL; 2027 2028 s = splbio(); 2029 mlx_ccb_enqueue(mlx, mc); 2030 tsleep(mc, PRIBIO, "mlxwccb", 0); 2031 splx(s); 2032 2033 if (mc->mc_status != 0) { 2034 printf("%s: command failed - %s\n", mlx->mlx_dv.dv_xname, 2035 mlx_ccb_diagnose(mc)); 2036 return (EIO); 2037 } 2038 2039 return (0); 2040 } 2041 2042 /* 2043 * Try to submit a CCB's mailbox to the controller for execution. Return 2044 * non-zero on timeout or error. Must be called with interrupts blocked. 2045 */ 2046 static int 2047 mlx_ccb_submit(struct mlx_softc *mlx, struct mlx_ccb *mc) 2048 { 2049 int i, s, r; 2050 2051 /* Save the ident so we can handle this command when complete. */ 2052 mc->mc_mbox[1] = (u_int8_t)mc->mc_ident; 2053 2054 /* Mark the command as currently being processed. */ 2055 mc->mc_status = MLX_STATUS_BUSY; 2056 mc->mc_expiry = mlx_curtime() + MLX_TIMEOUT; 2057 2058 /* Spin waiting for the mailbox. */ 2059 for (i = 100; i != 0; i--) { 2060 s = splbio(); 2061 r = (*mlx->mlx_submit)(mlx, mc); 2062 splx(s); 2063 if (r != 0) 2064 break; 2065 DELAY(100); 2066 } 2067 if (i != 0) 2068 return (0); 2069 2070 DPRINTF(("mlx_ccb_submit: rejected; queueing\n")); 2071 mc->mc_status = MLX_STATUS_WEDGED; 2072 return (EIO); 2073 } 2074 2075 /* 2076 * Return a string that describes why a command has failed. 2077 */ 2078 const char * 2079 mlx_ccb_diagnose(struct mlx_ccb *mc) 2080 { 2081 static char buf[80]; 2082 int i; 2083 2084 for (i = 0; i < sizeof(mlx_msgs) / sizeof(mlx_msgs[0]); i++) 2085 if ((mc->mc_mbox[0] == mlx_msgs[i].command || 2086 mlx_msgs[i].command == 0) && 2087 mc->mc_status == mlx_msgs[i].status) { 2088 sprintf(buf, "%s (0x%x)", 2089 mlx_status_msgs[mlx_msgs[i].msg], mc->mc_status); 2090 return (buf); 2091 } 2092 2093 sprintf(buf, "unknown response 0x%x for command 0x%x", 2094 (int)mc->mc_status, (int)mc->mc_mbox[0]); 2095 2096 return (buf); 2097 } 2098 2099 /* 2100 * Poll the controller for completed commands. Returns non-zero if one or 2101 * more commands were completed. Must be called with interrupts blocked. 2102 */ 2103 int 2104 mlx_intr(void *cookie) 2105 { 2106 struct mlx_softc *mlx; 2107 struct mlx_ccb *mc; 2108 int result; 2109 u_int ident, status; 2110 2111 mlx = cookie; 2112 result = 0; 2113 2114 while ((*mlx->mlx_findcomplete)(mlx, &ident, &status) != 0) { 2115 result = 1; 2116 2117 if (ident >= MLX_MAX_QUEUECNT) { 2118 printf("%s: bad completion returned\n", 2119 mlx->mlx_dv.dv_xname); 2120 continue; 2121 } 2122 2123 mc = mlx->mlx_ccbs + ident; 2124 2125 if (mc->mc_status != MLX_STATUS_BUSY) { 2126 printf("%s: bad completion returned\n", 2127 mlx->mlx_dv.dv_xname); 2128 continue; 2129 } 2130 2131 TAILQ_REMOVE(&mlx->mlx_ccb_worklist, mc, mc_chain.tailq); 2132 2133 /* Record status and notify the initiator, if requested. */ 2134 mc->mc_status = status; 2135 if (mc->mc_mx.mx_handler != NULL) 2136 (*mc->mc_mx.mx_handler)(mc); 2137 else if ((mc->mc_flags & MC_WAITING) != 0) 2138 wakeup(mc); 2139 } 2140 2141 /* If we've completed any commands, try posting some more. */ 2142 if (result) 2143 mlx_ccb_enqueue(mlx, NULL); 2144 2145 return (result); 2146 } 2147 2148 /* 2149 * Emit a string describing the firmware handshake status code, and return a 2150 * flag indicating whether the code represents a fatal error. 2151 * 2152 * Error code interpretations are from the Linux driver, and don't directly 2153 * match the messages printed by Mylex's BIOS. This may change if 2154 * documentation on the codes is forthcoming. 2155 */ 2156 static int 2157 mlx_fw_message(struct mlx_softc *mlx, int error, int param1, int param2) 2158 { 2159 const char *fmt; 2160 2161 switch (error) { 2162 case 0x00: 2163 fmt = "physical drive %d:%d not responding"; 2164 break; 2165 2166 case 0x08: 2167 /* 2168 * We could be neater about this and give some indication 2169 * when we receive more of them. 2170 */ 2171 if ((mlx->mlx_flags & MLXF_SPINUP_REPORTED) == 0) { 2172 printf("%s: spinning up drives...\n", 2173 mlx->mlx_dv.dv_xname); 2174 mlx->mlx_flags |= MLXF_SPINUP_REPORTED; 2175 } 2176 break; 2177 2178 case 0x30: 2179 fmt = "configuration checksum error"; 2180 break; 2181 2182 case 0x60: 2183 fmt = "mirror race recovery failed"; 2184 break; 2185 2186 case 0x70: 2187 fmt = "mirror race recovery in progress"; 2188 break; 2189 2190 case 0x90: 2191 fmt = "physical drive %d:%d COD mismatch"; 2192 break; 2193 2194 case 0xa0: 2195 fmt = "logical drive installation aborted"; 2196 break; 2197 2198 case 0xb0: 2199 fmt = "mirror race on a critical system drive"; 2200 break; 2201 2202 case 0xd0: 2203 fmt = "new controller configuration found"; 2204 break; 2205 2206 case 0xf0: 2207 fmt = "FATAL MEMORY PARITY ERROR"; 2208 return (1); 2209 2210 default: 2211 printf("%s: unknown firmware init error %02x:%02x:%02x\n", 2212 mlx->mlx_dv.dv_xname, error, param1, param2); 2213 return (0); 2214 } 2215 2216 printf("%s: ", mlx->mlx_dv.dv_xname); 2217 printf(fmt, param2, param1); 2218 printf("\n"); 2219 2220 return (0); 2221 } 2222