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