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