1 /* $NetBSD: mpt.c,v 1.4 2003/11/02 11:07:45 wiz Exp $ */ 2 3 /* 4 * Copyright (c) 2000, 2001 by Greg Ansley 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice immediately at the beginning of the file, without modification, 11 * this list of conditions, and the following disclaimer. 12 * 2. The name of the author may not be used to endorse or promote products 13 * derived from this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 19 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 /* 28 * Additional Copyright (c) 2002 by Matthew Jacob under same license. 29 */ 30 31 /* 32 * mpt.c: 33 * 34 * Generic routines for LSI Fusion adapters. 35 * 36 * Adapted from the FreeBSD "mpt" driver by Jason R. Thorpe for 37 * Wasabi Systems, Inc. 38 */ 39 40 #include <sys/cdefs.h> 41 __KERNEL_RCSID(0, "$NetBSD: mpt.c,v 1.4 2003/11/02 11:07:45 wiz Exp $"); 42 43 #include <dev/ic/mpt.h> 44 45 #define MPT_MAX_TRYS 3 46 #define MPT_MAX_WAIT 300000 47 48 static int maxwait_ack = 0; 49 static int maxwait_int = 0; 50 static int maxwait_state = 0; 51 52 static __inline u_int32_t 53 mpt_rd_db(mpt_softc_t *mpt) 54 { 55 return mpt_read(mpt, MPT_OFFSET_DOORBELL); 56 } 57 58 static __inline u_int32_t 59 mpt_rd_intr(mpt_softc_t *mpt) 60 { 61 return mpt_read(mpt, MPT_OFFSET_INTR_STATUS); 62 } 63 64 /* Busy wait for a door bell to be read by IOC */ 65 static int 66 mpt_wait_db_ack(mpt_softc_t *mpt) 67 { 68 int i; 69 for (i=0; i < MPT_MAX_WAIT; i++) { 70 if (!MPT_DB_IS_BUSY(mpt_rd_intr(mpt))) { 71 maxwait_ack = i > maxwait_ack ? i : maxwait_ack; 72 return MPT_OK; 73 } 74 75 DELAY(100); 76 } 77 return MPT_FAIL; 78 } 79 80 /* Busy wait for a door bell interrupt */ 81 static int 82 mpt_wait_db_int(mpt_softc_t *mpt) 83 { 84 int i; 85 for (i=0; i < MPT_MAX_WAIT; i++) { 86 if (MPT_DB_INTR(mpt_rd_intr(mpt))) { 87 maxwait_int = i > maxwait_int ? i : maxwait_int; 88 return MPT_OK; 89 } 90 DELAY(100); 91 } 92 return MPT_FAIL; 93 } 94 95 /* Wait for IOC to transition to a give state */ 96 void 97 mpt_check_doorbell(mpt_softc_t *mpt) 98 { 99 u_int32_t db = mpt_rd_db(mpt); 100 if (MPT_STATE(db) != MPT_DB_STATE_RUNNING) { 101 mpt_prt(mpt, "Device not running"); 102 mpt_print_db(db); 103 } 104 } 105 106 /* Wait for IOC to transition to a give state */ 107 static int 108 mpt_wait_state(mpt_softc_t *mpt, enum DB_STATE_BITS state) 109 { 110 int i; 111 112 for (i = 0; i < MPT_MAX_WAIT; i++) { 113 u_int32_t db = mpt_rd_db(mpt); 114 if (MPT_STATE(db) == state) { 115 maxwait_state = i > maxwait_state ? i : maxwait_state; 116 return (MPT_OK); 117 } 118 DELAY(100); 119 } 120 return (MPT_FAIL); 121 } 122 123 124 /* Issue the reset COMMAND to the IOC */ 125 int 126 mpt_soft_reset(mpt_softc_t *mpt) 127 { 128 if (mpt->verbose) { 129 mpt_prt(mpt, "soft reset"); 130 } 131 132 /* Have to use hard reset if we are not in Running state */ 133 if (MPT_STATE(mpt_rd_db(mpt)) != MPT_DB_STATE_RUNNING) { 134 mpt_prt(mpt, "soft reset failed: device not running"); 135 return MPT_FAIL; 136 } 137 138 /* If door bell is in use we don't have a chance of getting 139 * a word in since the IOC probably crashed in message 140 * processing. So don't waste our time. 141 */ 142 if (MPT_DB_IS_IN_USE(mpt_rd_db(mpt))) { 143 mpt_prt(mpt, "soft reset failed: doorbell wedged"); 144 return MPT_FAIL; 145 } 146 147 /* Send the reset request to the IOC */ 148 mpt_write(mpt, MPT_OFFSET_DOORBELL, 149 MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET << MPI_DOORBELL_FUNCTION_SHIFT); 150 if (mpt_wait_db_ack(mpt) != MPT_OK) { 151 mpt_prt(mpt, "soft reset failed: ack timeout"); 152 return MPT_FAIL; 153 } 154 155 /* Wait for the IOC to reload and come out of reset state */ 156 if (mpt_wait_state(mpt, MPT_DB_STATE_READY) != MPT_OK) { 157 mpt_prt(mpt, "soft reset failed: device did not start running"); 158 return MPT_FAIL; 159 } 160 161 return MPT_OK; 162 } 163 164 /* This is a magic diagnostic reset that resets all the ARM 165 * processors in the chip. 166 */ 167 void 168 mpt_hard_reset(mpt_softc_t *mpt) 169 { 170 /* This extra read comes for the Linux source 171 * released by LSI. It's function is undocumented! 172 */ 173 if (mpt->verbose) { 174 mpt_prt(mpt, "hard reset"); 175 } 176 mpt_read(mpt, MPT_OFFSET_FUBAR); 177 178 /* Enable diagnostic registers */ 179 mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_1); 180 mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_2); 181 mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_3); 182 mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_4); 183 mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_5); 184 185 /* Diag. port is now active so we can now hit the reset bit */ 186 mpt_write(mpt, MPT_OFFSET_DIAGNOSTIC, MPT_DIAG_RESET_IOC); 187 188 DELAY(10000); 189 190 /* Disable Diagnostic Register */ 191 mpt_write(mpt, MPT_OFFSET_SEQUENCE, 0xFF); 192 193 /* Restore the config register values */ 194 /* Hard resets are known to screw up the BAR for diagnostic 195 memory accesses (Mem1). */ 196 mpt_set_config_regs(mpt); 197 if (mpt->mpt2 != NULL) { 198 mpt_set_config_regs(mpt->mpt2); 199 } 200 201 /* Note that if there is no valid firmware to run, the doorbell will 202 remain in the reset state (0x00000000) */ 203 } 204 205 /* 206 * Reset the IOC when needed. Try software command first then if needed 207 * poke at the magic diagnostic reset. Note that a hard reset resets 208 * *both* IOCs on dual function chips (FC929 && LSI1030) as well as 209 * fouls up the PCI configuration registers. 210 */ 211 int 212 mpt_reset(mpt_softc_t *mpt) 213 { 214 int ret; 215 216 /* Try a soft reset */ 217 if ((ret = mpt_soft_reset(mpt)) != MPT_OK) { 218 /* Failed; do a hard reset */ 219 mpt_hard_reset(mpt); 220 221 /* Wait for the IOC to reload and come out of reset state */ 222 ret = mpt_wait_state(mpt, MPT_DB_STATE_READY); 223 if (ret != MPT_OK) { 224 mpt_prt(mpt, "failed to reset device"); 225 } 226 } 227 228 return ret; 229 } 230 231 /* Return a command buffer to the free queue */ 232 void 233 mpt_free_request(mpt_softc_t *mpt, request_t *req) 234 { 235 if (req == NULL || req != &mpt->request_pool[req->index]) { 236 panic("mpt_free_request bad req ptr\n"); 237 return; 238 } 239 req->sequence = 0; 240 req->xfer = NULL; 241 req->debug = REQ_FREE; 242 SLIST_INSERT_HEAD(&mpt->request_free_list, req, link); 243 } 244 245 /* Get a command buffer from the free queue */ 246 request_t * 247 mpt_get_request(mpt_softc_t *mpt) 248 { 249 request_t *req; 250 req = SLIST_FIRST(&mpt->request_free_list); 251 if (req != NULL) { 252 if (req != &mpt->request_pool[req->index]) { 253 panic("mpt_get_request: corrupted request free list\n"); 254 } 255 if (req->xfer != NULL) { 256 panic("mpt_get_request: corrupted request free list (xfer)\n"); 257 } 258 SLIST_REMOVE_HEAD(&mpt->request_free_list, link); 259 req->debug = REQ_IN_PROGRESS; 260 } 261 return req; 262 } 263 264 /* Pass the command to the IOC */ 265 void 266 mpt_send_cmd(mpt_softc_t *mpt, request_t *req) 267 { 268 req->sequence = mpt->sequence++; 269 if (mpt->verbose > 1) { 270 u_int32_t *pReq; 271 pReq = req->req_vbuf; 272 mpt_prt(mpt, "Send Request %d (0x%x):", 273 req->index, req->req_pbuf); 274 mpt_prt(mpt, "%08x %08x %08x %08x", 275 pReq[0], pReq[1], pReq[2], pReq[3]); 276 mpt_prt(mpt, "%08x %08x %08x %08x", 277 pReq[4], pReq[5], pReq[6], pReq[7]); 278 mpt_prt(mpt, "%08x %08x %08x %08x", 279 pReq[8], pReq[9], pReq[10], pReq[11]); 280 mpt_prt(mpt, "%08x %08x %08x %08x", 281 pReq[12], pReq[13], pReq[14], pReq[15]); 282 } 283 MPT_SYNC_REQ(mpt, req, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 284 req->debug = REQ_ON_CHIP; 285 mpt_write(mpt, MPT_OFFSET_REQUEST_Q, (u_int32_t) req->req_pbuf); 286 } 287 288 /* 289 * Give the reply buffer back to the IOC after we have 290 * finished processing it. 291 */ 292 void 293 mpt_free_reply(mpt_softc_t *mpt, u_int32_t ptr) 294 { 295 mpt_write(mpt, MPT_OFFSET_REPLY_Q, ptr); 296 } 297 298 /* Get a reply from the IOC */ 299 u_int32_t 300 mpt_pop_reply_queue(mpt_softc_t *mpt) 301 { 302 return mpt_read(mpt, MPT_OFFSET_REPLY_Q); 303 } 304 305 /* 306 * Send a command to the IOC via the handshake register. 307 * 308 * Only done at initialization time and for certain unusual 309 * commands such as device/bus reset as specified by LSI. 310 */ 311 int 312 mpt_send_handshake_cmd(mpt_softc_t *mpt, size_t len, void *cmd) 313 { 314 int i; 315 u_int32_t data, *data32; 316 317 /* Check condition of the IOC */ 318 data = mpt_rd_db(mpt); 319 if (((MPT_STATE(data) != MPT_DB_STATE_READY) && 320 (MPT_STATE(data) != MPT_DB_STATE_RUNNING) && 321 (MPT_STATE(data) != MPT_DB_STATE_FAULT)) || 322 ( MPT_DB_IS_IN_USE(data) )) { 323 mpt_prt(mpt, "handshake aborted due to invalid doorbell state"); 324 mpt_print_db(data); 325 return(EBUSY); 326 } 327 328 /* We move things in 32 bit chunks */ 329 len = (len + 3) >> 2; 330 data32 = cmd; 331 332 /* Clear any left over pending doorbell interrupts */ 333 if (MPT_DB_INTR(mpt_rd_intr(mpt))) 334 mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 335 336 /* 337 * Tell the handshake reg. we are going to send a command 338 * and how long it is going to be. 339 */ 340 data = (MPI_FUNCTION_HANDSHAKE << MPI_DOORBELL_FUNCTION_SHIFT) | 341 (len << MPI_DOORBELL_ADD_DWORDS_SHIFT); 342 mpt_write(mpt, MPT_OFFSET_DOORBELL, data); 343 344 /* Wait for the chip to notice */ 345 if (mpt_wait_db_int(mpt) != MPT_OK) { 346 mpt_prt(mpt, "mpt_send_handshake_cmd timeout1"); 347 return ETIMEDOUT; 348 } 349 350 /* Clear the interrupt */ 351 mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 352 353 if (mpt_wait_db_ack(mpt) != MPT_OK) { 354 mpt_prt(mpt, "mpt_send_handshake_cmd timeout2"); 355 return ETIMEDOUT; 356 } 357 358 /* Send the command */ 359 for (i = 0; i < len; i++) { 360 mpt_write(mpt, MPT_OFFSET_DOORBELL, *data32++); 361 if (mpt_wait_db_ack(mpt) != MPT_OK) { 362 mpt_prt(mpt, 363 "mpt_send_handshake_cmd timeout! index = %d", i); 364 return ETIMEDOUT; 365 } 366 } 367 return MPT_OK; 368 } 369 370 /* Get the response from the handshake register */ 371 int 372 mpt_recv_handshake_reply(mpt_softc_t *mpt, size_t reply_len, void *reply) 373 { 374 int left, reply_left; 375 u_int16_t *data16; 376 MSG_DEFAULT_REPLY *hdr; 377 378 /* We move things out in 16 bit chunks */ 379 reply_len >>= 1; 380 data16 = (u_int16_t *)reply; 381 382 hdr = (MSG_DEFAULT_REPLY *)reply; 383 384 /* Get first word */ 385 if (mpt_wait_db_int(mpt) != MPT_OK) { 386 mpt_prt(mpt, "mpt_recv_handshake_cmd timeout1"); 387 return ETIMEDOUT; 388 } 389 *data16++ = mpt_read(mpt, MPT_OFFSET_DOORBELL) & MPT_DB_DATA_MASK; 390 mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 391 392 /* Get Second Word */ 393 if (mpt_wait_db_int(mpt) != MPT_OK) { 394 mpt_prt(mpt, "mpt_recv_handshake_cmd timeout2"); 395 return ETIMEDOUT; 396 } 397 *data16++ = mpt_read(mpt, MPT_OFFSET_DOORBELL) & MPT_DB_DATA_MASK; 398 mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 399 400 /* With the second word, we can now look at the length */ 401 if (mpt->verbose > 1 && ((reply_len >> 1) != hdr->MsgLength)) { 402 mpt_prt(mpt, "reply length does not match message length: " 403 "got 0x%02x, expected 0x%02x", 404 hdr->MsgLength << 2, reply_len << 1); 405 } 406 407 /* Get rest of the reply; but don't overflow the provided buffer */ 408 left = (hdr->MsgLength << 1) - 2; 409 reply_left = reply_len - 2; 410 while (left--) { 411 u_int16_t datum; 412 413 if (mpt_wait_db_int(mpt) != MPT_OK) { 414 mpt_prt(mpt, "mpt_recv_handshake_cmd timeout3"); 415 return ETIMEDOUT; 416 } 417 datum = mpt_read(mpt, MPT_OFFSET_DOORBELL); 418 419 if (reply_left-- > 0) 420 *data16++ = datum & MPT_DB_DATA_MASK; 421 422 mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 423 } 424 425 /* One more wait & clear at the end */ 426 if (mpt_wait_db_int(mpt) != MPT_OK) { 427 mpt_prt(mpt, "mpt_recv_handshake_cmd timeout4"); 428 return ETIMEDOUT; 429 } 430 mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 431 432 if ((hdr->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 433 if (mpt->verbose > 1) 434 mpt_print_reply(hdr); 435 return (MPT_FAIL | hdr->IOCStatus); 436 } 437 438 return (0); 439 } 440 441 static int 442 mpt_get_iocfacts(mpt_softc_t *mpt, MSG_IOC_FACTS_REPLY *freplp) 443 { 444 MSG_IOC_FACTS f_req; 445 int error; 446 447 bzero(&f_req, sizeof f_req); 448 f_req.Function = MPI_FUNCTION_IOC_FACTS; 449 f_req.MsgContext = 0x12071942; 450 error = mpt_send_handshake_cmd(mpt, sizeof f_req, &f_req); 451 if (error) 452 return(error); 453 error = mpt_recv_handshake_reply(mpt, sizeof (*freplp), freplp); 454 return (error); 455 } 456 457 static int 458 mpt_get_portfacts(mpt_softc_t *mpt, MSG_PORT_FACTS_REPLY *freplp) 459 { 460 MSG_PORT_FACTS f_req; 461 int error; 462 463 /* XXX: Only getting PORT FACTS for Port 0 */ 464 bzero(&f_req, sizeof f_req); 465 f_req.Function = MPI_FUNCTION_PORT_FACTS; 466 f_req.MsgContext = 0x12071943; 467 error = mpt_send_handshake_cmd(mpt, sizeof f_req, &f_req); 468 if (error) 469 return(error); 470 error = mpt_recv_handshake_reply(mpt, sizeof (*freplp), freplp); 471 return (error); 472 } 473 474 /* 475 * Send the initialization request. This is where we specify how many 476 * SCSI busses and how many devices per bus we wish to emulate. 477 * This is also the command that specifies the max size of the reply 478 * frames from the IOC that we will be allocating. 479 */ 480 static int 481 mpt_send_ioc_init(mpt_softc_t *mpt, u_int32_t who) 482 { 483 int error = 0; 484 MSG_IOC_INIT init; 485 MSG_IOC_INIT_REPLY reply; 486 487 bzero(&init, sizeof init); 488 init.WhoInit = who; 489 init.Function = MPI_FUNCTION_IOC_INIT; 490 if (mpt->is_fc) { 491 init.MaxDevices = 255; 492 } else { 493 init.MaxDevices = 16; 494 } 495 init.MaxBuses = 1; 496 init.ReplyFrameSize = MPT_REPLY_SIZE; 497 init.MsgContext = 0x12071941; 498 499 if ((error = mpt_send_handshake_cmd(mpt, sizeof init, &init)) != 0) { 500 return(error); 501 } 502 503 error = mpt_recv_handshake_reply(mpt, sizeof reply, &reply); 504 return (error); 505 } 506 507 508 /* 509 * Utiltity routine to read configuration headers and pages 510 */ 511 512 static int 513 mpt_read_cfg_header(mpt_softc_t *, int, int, int, fCONFIG_PAGE_HEADER *); 514 515 static int 516 mpt_read_cfg_header(mpt_softc_t *mpt, int PageType, int PageNumber, 517 int PageAddress, fCONFIG_PAGE_HEADER *rslt) 518 { 519 int count; 520 request_t *req; 521 MSG_CONFIG *cfgp; 522 MSG_CONFIG_REPLY *reply; 523 524 req = mpt_get_request(mpt); 525 526 cfgp = req->req_vbuf; 527 bzero(cfgp, sizeof *cfgp); 528 529 cfgp->Action = MPI_CONFIG_ACTION_PAGE_HEADER; 530 cfgp->Function = MPI_FUNCTION_CONFIG; 531 cfgp->Header.PageNumber = (U8) PageNumber; 532 cfgp->Header.PageType = (U8) PageType; 533 cfgp->PageAddress = PageAddress; 534 MPI_pSGE_SET_FLAGS(((SGE_SIMPLE32 *) &cfgp->PageBufferSGE), 535 (MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | 536 MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_LIST)); 537 cfgp->MsgContext = req->index | 0x80000000; 538 539 mpt_check_doorbell(mpt); 540 mpt_send_cmd(mpt, req); 541 count = 0; 542 do { 543 DELAY(500); 544 mpt_intr(mpt); 545 if (++count == 1000) { 546 mpt_prt(mpt, "read_cfg_header timed out"); 547 return (-1); 548 } 549 } while (req->debug == REQ_ON_CHIP); 550 551 reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence); 552 if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 553 mpt_prt(mpt, "mpt_read_cfg_header: Config Info Status %x", 554 reply->IOCStatus); 555 mpt_free_reply(mpt, (req->sequence << 1)); 556 return (-1); 557 } 558 bcopy(&reply->Header, rslt, sizeof (fCONFIG_PAGE_HEADER)); 559 mpt_free_reply(mpt, (req->sequence << 1)); 560 mpt_free_request(mpt, req); 561 return (0); 562 } 563 564 #define CFG_DATA_OFF 128 565 566 int 567 mpt_read_cfg_page(mpt_softc_t *mpt, int PageAddress, fCONFIG_PAGE_HEADER *hdr) 568 { 569 int count; 570 request_t *req; 571 SGE_SIMPLE32 *se; 572 MSG_CONFIG *cfgp; 573 size_t amt; 574 MSG_CONFIG_REPLY *reply; 575 576 req = mpt_get_request(mpt); 577 578 cfgp = req->req_vbuf; 579 bzero(cfgp, MPT_REQUEST_AREA); 580 cfgp->Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 581 cfgp->Function = MPI_FUNCTION_CONFIG; 582 cfgp->Header = *hdr; 583 amt = (cfgp->Header.PageLength * sizeof (u_int32_t)); 584 cfgp->Header.PageType &= MPI_CONFIG_PAGETYPE_MASK; 585 cfgp->PageAddress = PageAddress; 586 se = (SGE_SIMPLE32 *) &cfgp->PageBufferSGE; 587 se->Address = req->req_pbuf + CFG_DATA_OFF; 588 MPI_pSGE_SET_LENGTH(se, amt); 589 MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT | 590 MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | 591 MPI_SGE_FLAGS_END_OF_LIST)); 592 593 cfgp->MsgContext = req->index | 0x80000000; 594 595 mpt_check_doorbell(mpt); 596 mpt_send_cmd(mpt, req); 597 count = 0; 598 do { 599 DELAY(500); 600 mpt_intr(mpt); 601 if (++count == 1000) { 602 mpt_prt(mpt, "read_cfg_page timed out"); 603 return (-1); 604 } 605 } while (req->debug == REQ_ON_CHIP); 606 607 reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence); 608 if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 609 mpt_prt(mpt, "mpt_read_cfg_page: Config Info Status %x", 610 reply->IOCStatus); 611 mpt_free_reply(mpt, (req->sequence << 1)); 612 return (-1); 613 } 614 mpt_free_reply(mpt, (req->sequence << 1)); 615 #if 0 /* XXXJRT */ 616 bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap, 617 BUS_DMASYNC_POSTREAD); 618 #endif 619 if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 620 cfgp->Header.PageNumber == 0) { 621 amt = sizeof (fCONFIG_PAGE_SCSI_PORT_0); 622 } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 623 cfgp->Header.PageNumber == 1) { 624 amt = sizeof (fCONFIG_PAGE_SCSI_PORT_1); 625 } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 626 cfgp->Header.PageNumber == 2) { 627 amt = sizeof (fCONFIG_PAGE_SCSI_PORT_2); 628 } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && 629 cfgp->Header.PageNumber == 0) { 630 amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_0); 631 } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && 632 cfgp->Header.PageNumber == 1) { 633 amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_1); 634 } 635 bcopy(((caddr_t)req->req_vbuf)+CFG_DATA_OFF, hdr, amt); 636 mpt_free_request(mpt, req); 637 return (0); 638 } 639 640 int 641 mpt_write_cfg_page(mpt_softc_t *mpt, int PageAddress, fCONFIG_PAGE_HEADER *hdr) 642 { 643 int count, hdr_attr; 644 request_t *req; 645 SGE_SIMPLE32 *se; 646 MSG_CONFIG *cfgp; 647 size_t amt; 648 MSG_CONFIG_REPLY *reply; 649 650 req = mpt_get_request(mpt); 651 652 cfgp = req->req_vbuf; 653 bzero(cfgp, sizeof *cfgp); 654 655 hdr_attr = hdr->PageType & MPI_CONFIG_PAGEATTR_MASK; 656 if (hdr_attr != MPI_CONFIG_PAGEATTR_CHANGEABLE && 657 hdr_attr != MPI_CONFIG_PAGEATTR_PERSISTENT) { 658 mpt_prt(mpt, "page type 0x%x not changeable", 659 hdr->PageType & MPI_CONFIG_PAGETYPE_MASK); 660 return (-1); 661 } 662 hdr->PageType &= MPI_CONFIG_PAGETYPE_MASK; 663 664 cfgp->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; 665 cfgp->Function = MPI_FUNCTION_CONFIG; 666 cfgp->Header = *hdr; 667 amt = (cfgp->Header.PageLength * sizeof (u_int32_t)); 668 cfgp->PageAddress = PageAddress; 669 670 se = (SGE_SIMPLE32 *) &cfgp->PageBufferSGE; 671 se->Address = req->req_pbuf + CFG_DATA_OFF; 672 MPI_pSGE_SET_LENGTH(se, amt); 673 MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT | 674 MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | 675 MPI_SGE_FLAGS_END_OF_LIST | MPI_SGE_FLAGS_HOST_TO_IOC)); 676 677 cfgp->MsgContext = req->index | 0x80000000; 678 679 if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 680 cfgp->Header.PageNumber == 0) { 681 amt = sizeof (fCONFIG_PAGE_SCSI_PORT_0); 682 } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 683 cfgp->Header.PageNumber == 1) { 684 amt = sizeof (fCONFIG_PAGE_SCSI_PORT_1); 685 } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 686 cfgp->Header.PageNumber == 2) { 687 amt = sizeof (fCONFIG_PAGE_SCSI_PORT_2); 688 } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && 689 cfgp->Header.PageNumber == 0) { 690 amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_0); 691 } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && 692 cfgp->Header.PageNumber == 1) { 693 amt = sizeof (fCONFIG_PAGE_SCSI_DEVICE_1); 694 } 695 bcopy(hdr, ((caddr_t)req->req_vbuf)+CFG_DATA_OFF, amt); 696 /* Restore stripped out attributes */ 697 hdr->PageType |= hdr_attr; 698 699 mpt_check_doorbell(mpt); 700 mpt_send_cmd(mpt, req); 701 count = 0; 702 do { 703 DELAY(500); 704 mpt_intr(mpt); 705 if (++count == 1000) { 706 hdr->PageType |= hdr_attr; 707 mpt_prt(mpt, "mpt_write_cfg_page timed out"); 708 return (-1); 709 } 710 } while (req->debug == REQ_ON_CHIP); 711 712 reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence); 713 if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 714 mpt_prt(mpt, "mpt_write_cfg_page: Config Info Status %x", 715 reply->IOCStatus); 716 mpt_free_reply(mpt, (req->sequence << 1)); 717 return (-1); 718 } 719 mpt_free_reply(mpt, (req->sequence << 1)); 720 721 mpt_free_request(mpt, req); 722 return (0); 723 } 724 725 /* 726 * Read SCSI configuration information 727 */ 728 static int 729 mpt_read_config_info_spi(mpt_softc_t *mpt) 730 { 731 int rv, i; 732 733 rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 0, 734 0, &mpt->mpt_port_page0.Header); 735 if (rv) { 736 return (-1); 737 } 738 if (mpt->verbose > 1) { 739 mpt_prt(mpt, "SPI Port Page 0 Header: %x %x %x %x", 740 mpt->mpt_port_page0.Header.PageVersion, 741 mpt->mpt_port_page0.Header.PageLength, 742 mpt->mpt_port_page0.Header.PageNumber, 743 mpt->mpt_port_page0.Header.PageType); 744 } 745 746 rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 1, 747 0, &mpt->mpt_port_page1.Header); 748 if (rv) { 749 return (-1); 750 } 751 if (mpt->verbose > 1) { 752 mpt_prt(mpt, "SPI Port Page 1 Header: %x %x %x %x", 753 mpt->mpt_port_page1.Header.PageVersion, 754 mpt->mpt_port_page1.Header.PageLength, 755 mpt->mpt_port_page1.Header.PageNumber, 756 mpt->mpt_port_page1.Header.PageType); 757 } 758 759 rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 2, 760 0, &mpt->mpt_port_page2.Header); 761 if (rv) { 762 return (-1); 763 } 764 765 if (mpt->verbose > 1) { 766 mpt_prt(mpt, "SPI Port Page 2 Header: %x %x %x %x", 767 mpt->mpt_port_page1.Header.PageVersion, 768 mpt->mpt_port_page1.Header.PageLength, 769 mpt->mpt_port_page1.Header.PageNumber, 770 mpt->mpt_port_page1.Header.PageType); 771 } 772 773 for (i = 0; i < 16; i++) { 774 rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE, 775 0, i, &mpt->mpt_dev_page0[i].Header); 776 if (rv) { 777 return (-1); 778 } 779 if (mpt->verbose > 1) { 780 mpt_prt(mpt, 781 "SPI Target %d Device Page 0 Header: %x %x %x %x", 782 i, mpt->mpt_dev_page0[i].Header.PageVersion, 783 mpt->mpt_dev_page0[i].Header.PageLength, 784 mpt->mpt_dev_page0[i].Header.PageNumber, 785 mpt->mpt_dev_page0[i].Header.PageType); 786 } 787 788 rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE, 789 1, i, &mpt->mpt_dev_page1[i].Header); 790 if (rv) { 791 return (-1); 792 } 793 if (mpt->verbose > 1) { 794 mpt_prt(mpt, 795 "SPI Target %d Device Page 1 Header: %x %x %x %x", 796 i, mpt->mpt_dev_page1[i].Header.PageVersion, 797 mpt->mpt_dev_page1[i].Header.PageLength, 798 mpt->mpt_dev_page1[i].Header.PageNumber, 799 mpt->mpt_dev_page1[i].Header.PageType); 800 } 801 } 802 803 /* 804 * At this point, we don't *have* to fail. As long as we have 805 * valid config header information, we can (barely) lurch 806 * along. 807 */ 808 809 rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page0.Header); 810 if (rv) { 811 mpt_prt(mpt, "failed to read SPI Port Page 0"); 812 } else if (mpt->verbose > 1) { 813 mpt_prt(mpt, 814 "SPI Port Page 0: Capabilities %x PhysicalInterface %x", 815 mpt->mpt_port_page0.Capabilities, 816 mpt->mpt_port_page0.PhysicalInterface); 817 } 818 819 rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page1.Header); 820 if (rv) { 821 mpt_prt(mpt, "failed to read SPI Port Page 1"); 822 } else if (mpt->verbose > 1) { 823 mpt_prt(mpt, 824 "SPI Port Page 1: Configuration %x OnBusTimerValue %x", 825 mpt->mpt_port_page1.Configuration, 826 mpt->mpt_port_page1.OnBusTimerValue); 827 } 828 829 rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page2.Header); 830 if (rv) { 831 mpt_prt(mpt, "failed to read SPI Port Page 2"); 832 } else if (mpt->verbose > 1) { 833 mpt_prt(mpt, 834 "SPI Port Page 2: Flags %x Settings %x", 835 mpt->mpt_port_page2.PortFlags, 836 mpt->mpt_port_page2.PortSettings); 837 for (i = 0; i < 16; i++) { 838 mpt_prt(mpt, 839 "SPI Port Page 2 Tgt %d: timo %x SF %x Flags %x", 840 i, mpt->mpt_port_page2.DeviceSettings[i].Timeout, 841 mpt->mpt_port_page2.DeviceSettings[i].SyncFactor, 842 mpt->mpt_port_page2.DeviceSettings[i].DeviceFlags); 843 } 844 } 845 846 for (i = 0; i < 16; i++) { 847 rv = mpt_read_cfg_page(mpt, i, &mpt->mpt_dev_page0[i].Header); 848 if (rv) { 849 mpt_prt(mpt, "cannot read SPI Tgt %d Device Page 0", i); 850 continue; 851 } 852 if (mpt->verbose > 1) { 853 mpt_prt(mpt, 854 "SPI Tgt %d Page 0: NParms %x Information %x", 855 i, mpt->mpt_dev_page0[i].NegotiatedParameters, 856 mpt->mpt_dev_page0[i].Information); 857 } 858 rv = mpt_read_cfg_page(mpt, i, &mpt->mpt_dev_page1[i].Header); 859 if (rv) { 860 mpt_prt(mpt, "cannot read SPI Tgt %d Device Page 1", i); 861 continue; 862 } 863 if (mpt->verbose > 1) { 864 mpt_prt(mpt, 865 "SPI Tgt %d Page 1: RParms %x Configuration %x", 866 i, mpt->mpt_dev_page1[i].RequestedParameters, 867 mpt->mpt_dev_page1[i].Configuration); 868 } 869 } 870 return (0); 871 } 872 873 /* 874 * Validate SPI configuration information. 875 * 876 * In particular, validate SPI Port Page 1. 877 */ 878 static int 879 mpt_set_initial_config_spi(mpt_softc_t *mpt) 880 { 881 int i, pp1val = ((1 << mpt->mpt_ini_id) << 16) | mpt->mpt_ini_id; 882 883 mpt->mpt_disc_enable = 0xff; 884 mpt->mpt_tag_enable = 0; 885 886 if (mpt->mpt_port_page1.Configuration != pp1val) { 887 fCONFIG_PAGE_SCSI_PORT_1 tmp; 888 mpt_prt(mpt, 889 "SPI Port Page 1 Config value bad (%x)- should be %x", 890 mpt->mpt_port_page1.Configuration, pp1val); 891 tmp = mpt->mpt_port_page1; 892 tmp.Configuration = pp1val; 893 if (mpt_write_cfg_page(mpt, 0, &tmp.Header)) { 894 return (-1); 895 } 896 if (mpt_read_cfg_page(mpt, 0, &tmp.Header)) { 897 return (-1); 898 } 899 if (tmp.Configuration != pp1val) { 900 mpt_prt(mpt, 901 "failed to reset SPI Port Page 1 Config value"); 902 return (-1); 903 } 904 mpt->mpt_port_page1 = tmp; 905 } 906 907 for (i = 0; i < 16; i++) { 908 fCONFIG_PAGE_SCSI_DEVICE_1 tmp; 909 tmp = mpt->mpt_dev_page1[i]; 910 tmp.RequestedParameters = 0; 911 tmp.Configuration = 0; 912 if (mpt->verbose > 1) { 913 mpt_prt(mpt, 914 "Set Tgt %d SPI DevicePage 1 values to %x 0 %x", 915 i, tmp.RequestedParameters, tmp.Configuration); 916 } 917 if (mpt_write_cfg_page(mpt, i, &tmp.Header)) { 918 return (-1); 919 } 920 if (mpt_read_cfg_page(mpt, i, &tmp.Header)) { 921 return (-1); 922 } 923 mpt->mpt_dev_page1[i] = tmp; 924 if (mpt->verbose > 1) { 925 mpt_prt(mpt, 926 "SPI Tgt %d Page 1: RParm %x Configuration %x", i, 927 mpt->mpt_dev_page1[i].RequestedParameters, 928 mpt->mpt_dev_page1[i].Configuration); 929 } 930 } 931 return (0); 932 } 933 934 /* 935 * Enable IOC port 936 */ 937 static int 938 mpt_send_port_enable(mpt_softc_t *mpt, int port) 939 { 940 int count; 941 request_t *req; 942 MSG_PORT_ENABLE *enable_req; 943 944 req = mpt_get_request(mpt); 945 946 enable_req = req->req_vbuf; 947 bzero(enable_req, sizeof *enable_req); 948 949 enable_req->Function = MPI_FUNCTION_PORT_ENABLE; 950 enable_req->MsgContext = req->index | 0x80000000; 951 enable_req->PortNumber = port; 952 953 mpt_check_doorbell(mpt); 954 if (mpt->verbose > 1) { 955 mpt_prt(mpt, "enabling port %d", port); 956 } 957 mpt_send_cmd(mpt, req); 958 959 count = 0; 960 do { 961 DELAY(500); 962 mpt_intr(mpt); 963 if (++count == 100000) { 964 mpt_prt(mpt, "port enable timed out"); 965 return (-1); 966 } 967 } while (req->debug == REQ_ON_CHIP); 968 mpt_free_request(mpt, req); 969 return (0); 970 } 971 972 /* 973 * Enable/Disable asynchronous event reporting. 974 * 975 * NB: this is the first command we send via shared memory 976 * instead of the handshake register. 977 */ 978 static int 979 mpt_send_event_request(mpt_softc_t *mpt, int onoff) 980 { 981 request_t *req; 982 MSG_EVENT_NOTIFY *enable_req; 983 984 req = mpt_get_request(mpt); 985 986 enable_req = req->req_vbuf; 987 bzero(enable_req, sizeof *enable_req); 988 989 enable_req->Function = MPI_FUNCTION_EVENT_NOTIFICATION; 990 enable_req->MsgContext = req->index | 0x80000000; 991 enable_req->Switch = onoff; 992 993 mpt_check_doorbell(mpt); 994 if (mpt->verbose > 1) { 995 mpt_prt(mpt, "%sabling async events", onoff? "en" : "dis"); 996 } 997 mpt_send_cmd(mpt, req); 998 999 return (0); 1000 } 1001 1002 /* 1003 * Un-mask the interrupts on the chip. 1004 */ 1005 void 1006 mpt_enable_ints(mpt_softc_t *mpt) 1007 { 1008 /* Unmask every thing except door bell int */ 1009 mpt_write(mpt, MPT_OFFSET_INTR_MASK, MPT_INTR_DB_MASK); 1010 } 1011 1012 /* 1013 * Mask the interrupts on the chip. 1014 */ 1015 void 1016 mpt_disable_ints(mpt_softc_t *mpt) 1017 { 1018 /* Mask all interrupts */ 1019 mpt_write(mpt, MPT_OFFSET_INTR_MASK, 1020 MPT_INTR_REPLY_MASK | MPT_INTR_DB_MASK); 1021 } 1022 1023 /* (Re)Initialize the chip for use */ 1024 int 1025 mpt_init(mpt_softc_t *mpt, u_int32_t who) 1026 { 1027 int try; 1028 MSG_IOC_FACTS_REPLY facts; 1029 MSG_PORT_FACTS_REPLY pfp; 1030 u_int32_t pptr; 1031 int val; 1032 1033 /* Put all request buffers (back) on the free list */ 1034 SLIST_INIT(&mpt->request_free_list); 1035 for (val = 0; val < MPT_MAX_REQUESTS(mpt); val++) { 1036 mpt_free_request(mpt, &mpt->request_pool[val]); 1037 } 1038 1039 if (mpt->verbose > 1) { 1040 mpt_prt(mpt, "doorbell req = %s", 1041 mpt_ioc_diag(mpt_read(mpt, MPT_OFFSET_DOORBELL))); 1042 } 1043 1044 /* 1045 * Start by making sure we're not at FAULT or RESET state 1046 */ 1047 switch (mpt_rd_db(mpt) & MPT_DB_STATE_MASK) { 1048 case MPT_DB_STATE_RESET: 1049 case MPT_DB_STATE_FAULT: 1050 if (mpt_reset(mpt) != MPT_OK) { 1051 return (EIO); 1052 } 1053 default: 1054 break; 1055 } 1056 1057 for (try = 0; try < MPT_MAX_TRYS; try++) { 1058 /* 1059 * No need to reset if the IOC is already in the READY state. 1060 * 1061 * Force reset if initialization failed previously. 1062 * Note that a hard_reset of the second channel of a '929 1063 * will stop operation of the first channel. Hopefully, if the 1064 * first channel is ok, the second will not require a hard 1065 * reset. 1066 */ 1067 if ((mpt_rd_db(mpt) & MPT_DB_STATE_MASK) != 1068 MPT_DB_STATE_READY) { 1069 if (mpt_reset(mpt) != MPT_OK) { 1070 DELAY(10000); 1071 continue; 1072 } 1073 } 1074 1075 if (mpt_get_iocfacts(mpt, &facts) != MPT_OK) { 1076 mpt_prt(mpt, "mpt_get_iocfacts failed"); 1077 continue; 1078 } 1079 1080 if (mpt->verbose > 1) { 1081 mpt_prt(mpt, 1082 "IOCFACTS: GlobalCredits=%d BlockSize=%u " 1083 "Request Frame Size %u\n", facts.GlobalCredits, 1084 facts.BlockSize, facts.RequestFrameSize); 1085 } 1086 mpt->mpt_global_credits = facts.GlobalCredits; 1087 mpt->request_frame_size = facts.RequestFrameSize; 1088 1089 if (mpt_get_portfacts(mpt, &pfp) != MPT_OK) { 1090 mpt_prt(mpt, "mpt_get_portfacts failed"); 1091 continue; 1092 } 1093 1094 if (mpt->verbose > 1) { 1095 mpt_prt(mpt, 1096 "PORTFACTS: Type %x PFlags %x IID %d MaxDev %d\n", 1097 pfp.PortType, pfp.ProtocolFlags, pfp.PortSCSIID, 1098 pfp.MaxDevices); 1099 } 1100 1101 if (pfp.PortType != MPI_PORTFACTS_PORTTYPE_SCSI && 1102 pfp.PortType != MPI_PORTFACTS_PORTTYPE_FC) { 1103 mpt_prt(mpt, "Unsupported Port Type (%x)", 1104 pfp.PortType); 1105 return (ENXIO); 1106 } 1107 if (!(pfp.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)) { 1108 mpt_prt(mpt, "initiator role unsupported"); 1109 return (ENXIO); 1110 } 1111 if (pfp.PortType == MPI_PORTFACTS_PORTTYPE_FC) { 1112 mpt->is_fc = 1; 1113 } else { 1114 mpt->is_fc = 0; 1115 } 1116 mpt->mpt_ini_id = pfp.PortSCSIID; 1117 1118 if (mpt_send_ioc_init(mpt, who) != MPT_OK) { 1119 mpt_prt(mpt, "mpt_send_ioc_init failed"); 1120 continue; 1121 } 1122 1123 if (mpt->verbose > 1) { 1124 mpt_prt(mpt, "mpt_send_ioc_init ok"); 1125 } 1126 1127 if (mpt_wait_state(mpt, MPT_DB_STATE_RUNNING) != MPT_OK) { 1128 mpt_prt(mpt, "IOC failed to go to run state"); 1129 continue; 1130 } 1131 if (mpt->verbose > 1) { 1132 mpt_prt(mpt, "IOC now at RUNSTATE"); 1133 } 1134 1135 /* 1136 * Give it reply buffers 1137 * 1138 * Do *not* except global credits. 1139 */ 1140 for (val = 0, pptr = mpt->reply_phys; 1141 (pptr + MPT_REPLY_SIZE) < (mpt->reply_phys + PAGE_SIZE); 1142 pptr += MPT_REPLY_SIZE) { 1143 mpt_free_reply(mpt, pptr); 1144 if (++val == mpt->mpt_global_credits - 1) 1145 break; 1146 } 1147 1148 /* 1149 * Enable asynchronous event reporting 1150 */ 1151 mpt_send_event_request(mpt, 1); 1152 1153 1154 /* 1155 * Read set up initial configuration information 1156 * (SPI only for now) 1157 */ 1158 1159 if (mpt->is_fc == 0) { 1160 if (mpt_read_config_info_spi(mpt)) { 1161 return (EIO); 1162 } 1163 if (mpt_set_initial_config_spi(mpt)) { 1164 return (EIO); 1165 } 1166 } 1167 1168 /* 1169 * Now enable the port 1170 */ 1171 if (mpt_send_port_enable(mpt, 0) != MPT_OK) { 1172 mpt_prt(mpt, "failed to enable port 0"); 1173 continue; 1174 } 1175 1176 if (mpt->verbose > 1) { 1177 mpt_prt(mpt, "enabled port 0"); 1178 } 1179 1180 /* Everything worked */ 1181 break; 1182 } 1183 1184 if (try >= MPT_MAX_TRYS) { 1185 mpt_prt(mpt, "failed to initialize IOC"); 1186 return (EIO); 1187 } 1188 1189 if (mpt->verbose > 1) { 1190 mpt_prt(mpt, "enabling interrupts"); 1191 } 1192 1193 mpt_enable_ints(mpt); 1194 return (0); 1195 } 1196