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