mpt.c revision 139749
1139749Simp/*- 2101704Smjacob * Generic routines for LSI '909 FC adapters. 3101704Smjacob * FreeBSD Version. 4101704Smjacob * 5101704Smjacob * Copyright (c) 2000, 2001 by Greg Ansley 6101704Smjacob * 7101704Smjacob * Redistribution and use in source and binary forms, with or without 8101704Smjacob * modification, are permitted provided that the following conditions 9101704Smjacob * are met: 10101704Smjacob * 1. Redistributions of source code must retain the above copyright 11101704Smjacob * notice immediately at the beginning of the file, without modification, 12101704Smjacob * this list of conditions, and the following disclaimer. 13101704Smjacob * 2. The name of the author may not be used to endorse or promote products 14101704Smjacob * derived from this software without specific prior written permission. 15101704Smjacob * 16101704Smjacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17101704Smjacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18101704Smjacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19101704Smjacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 20101704Smjacob * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21101704Smjacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22101704Smjacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23101704Smjacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24101704Smjacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25101704Smjacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26101704Smjacob * SUCH DAMAGE. 27101704Smjacob */ 28101704Smjacob/* 29101704Smjacob * Additional Copyright (c) 2002 by Matthew Jacob under same license. 30101704Smjacob */ 31101704Smjacob 32134123Sobrien#include <sys/cdefs.h> 33134123Sobrien__FBSDID("$FreeBSD: head/sys/dev/mpt/mpt.c 139749 2005-01-06 01:43:34Z imp $"); 34134123Sobrien 35101704Smjacob#include <dev/mpt/mpt_freebsd.h> 36102199Smjacob 37101704Smjacob#define MPT_MAX_TRYS 3 38101704Smjacob#define MPT_MAX_WAIT 300000 39101704Smjacob 40101704Smjacobstatic int maxwait_ack = 0; 41101704Smjacobstatic int maxwait_int = 0; 42101704Smjacobstatic int maxwait_state = 0; 43101704Smjacob 44103914Smjacobstatic INLINE u_int32_t mpt_rd_db(mpt_softc_t *mpt); 45103914Smjacobstatic INLINE u_int32_t mpt_rd_intr(mpt_softc_t *mpt); 46101704Smjacob 47103914Smjacobstatic INLINE u_int32_t 48102199Smjacobmpt_rd_db(mpt_softc_t *mpt) 49101704Smjacob{ 50101704Smjacob return mpt_read(mpt, MPT_OFFSET_DOORBELL); 51101704Smjacob} 52101704Smjacob 53103914Smjacobstatic INLINE u_int32_t 54102199Smjacobmpt_rd_intr(mpt_softc_t *mpt) 55101704Smjacob{ 56101704Smjacob return mpt_read(mpt, MPT_OFFSET_INTR_STATUS); 57101704Smjacob} 58101704Smjacob 59101704Smjacob/* Busy wait for a door bell to be read by IOC */ 60101704Smjacobstatic int 61102199Smjacobmpt_wait_db_ack(mpt_softc_t *mpt) 62101704Smjacob{ 63101704Smjacob int i; 64101704Smjacob for (i=0; i < MPT_MAX_WAIT; i++) { 65101704Smjacob if (!MPT_DB_IS_BUSY(mpt_rd_intr(mpt))) { 66101704Smjacob maxwait_ack = i > maxwait_ack ? i : maxwait_ack; 67101704Smjacob return MPT_OK; 68101704Smjacob } 69101704Smjacob 70101704Smjacob DELAY(100); 71101704Smjacob } 72101704Smjacob return MPT_FAIL; 73101704Smjacob} 74101704Smjacob 75101704Smjacob/* Busy wait for a door bell interrupt */ 76101704Smjacobstatic int 77102199Smjacobmpt_wait_db_int(mpt_softc_t *mpt) 78101704Smjacob{ 79101704Smjacob int i; 80101704Smjacob for (i=0; i < MPT_MAX_WAIT; i++) { 81101704Smjacob if (MPT_DB_INTR(mpt_rd_intr(mpt))) { 82101704Smjacob maxwait_int = i > maxwait_int ? i : maxwait_int; 83101704Smjacob return MPT_OK; 84101704Smjacob } 85101704Smjacob DELAY(100); 86101704Smjacob } 87101704Smjacob return MPT_FAIL; 88101704Smjacob} 89101704Smjacob 90101704Smjacob/* Wait for IOC to transition to a give state */ 91101704Smjacobvoid 92102199Smjacobmpt_check_doorbell(mpt_softc_t *mpt) 93101704Smjacob{ 94101704Smjacob u_int32_t db = mpt_rd_db(mpt); 95101704Smjacob if (MPT_STATE(db) != MPT_DB_STATE_RUNNING) { 96103914Smjacob mpt_prt(mpt, "Device not running"); 97101704Smjacob mpt_print_db(db); 98101704Smjacob } 99101704Smjacob} 100101704Smjacob 101101704Smjacob/* Wait for IOC to transition to a give state */ 102101704Smjacobstatic int 103102199Smjacobmpt_wait_state(mpt_softc_t *mpt, enum DB_STATE_BITS state) 104101704Smjacob{ 105101704Smjacob int i; 106101704Smjacob 107101704Smjacob for (i = 0; i < MPT_MAX_WAIT; i++) { 108101704Smjacob u_int32_t db = mpt_rd_db(mpt); 109101704Smjacob if (MPT_STATE(db) == state) { 110101704Smjacob maxwait_state = i > maxwait_state ? i : maxwait_state; 111101704Smjacob return (MPT_OK); 112101704Smjacob } 113101704Smjacob DELAY(100); 114101704Smjacob } 115101704Smjacob return (MPT_FAIL); 116101704Smjacob} 117101704Smjacob 118101704Smjacob 119101704Smjacob/* Issue the reset COMMAND to the IOC */ 120101704Smjacobint 121102199Smjacobmpt_soft_reset(mpt_softc_t *mpt) 122101704Smjacob{ 123101704Smjacob if (mpt->verbose) { 124103914Smjacob mpt_prt(mpt, "soft reset"); 125101704Smjacob } 126101704Smjacob 127101704Smjacob /* Have to use hard reset if we are not in Running state */ 128101704Smjacob if (MPT_STATE(mpt_rd_db(mpt)) != MPT_DB_STATE_RUNNING) { 129103914Smjacob mpt_prt(mpt, "soft reset failed: device not running"); 130101704Smjacob return MPT_FAIL; 131101704Smjacob } 132101704Smjacob 133101704Smjacob /* If door bell is in use we don't have a chance of getting 134101704Smjacob * a word in since the IOC probably crashed in message 135101704Smjacob * processing. So don't waste our time. 136101704Smjacob */ 137101704Smjacob if (MPT_DB_IS_IN_USE(mpt_rd_db(mpt))) { 138103914Smjacob mpt_prt(mpt, "soft reset failed: doorbell wedged"); 139101704Smjacob return MPT_FAIL; 140101704Smjacob } 141101704Smjacob 142101704Smjacob /* Send the reset request to the IOC */ 143101704Smjacob mpt_write(mpt, MPT_OFFSET_DOORBELL, 144101704Smjacob MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET << MPI_DOORBELL_FUNCTION_SHIFT); 145101704Smjacob if (mpt_wait_db_ack(mpt) != MPT_OK) { 146103914Smjacob mpt_prt(mpt, "soft reset failed: ack timeout"); 147101704Smjacob return MPT_FAIL; 148101704Smjacob } 149101704Smjacob 150101704Smjacob /* Wait for the IOC to reload and come out of reset state */ 151101704Smjacob if (mpt_wait_state(mpt, MPT_DB_STATE_READY) != MPT_OK) { 152103914Smjacob mpt_prt(mpt, "soft reset failed: device did not start running"); 153101704Smjacob return MPT_FAIL; 154101704Smjacob } 155101704Smjacob 156101704Smjacob return MPT_OK; 157101704Smjacob} 158101704Smjacob 159101704Smjacob/* This is a magic diagnostic reset that resets all the ARM 160101704Smjacob * processors in the chip. 161101704Smjacob */ 162101704Smjacobvoid 163102199Smjacobmpt_hard_reset(mpt_softc_t *mpt) 164101704Smjacob{ 165101704Smjacob /* This extra read comes for the Linux source 166101704Smjacob * released by LSI. It's function is undocumented! 167101704Smjacob */ 168101704Smjacob if (mpt->verbose) { 169103914Smjacob mpt_prt(mpt, "hard reset"); 170101704Smjacob } 171101704Smjacob mpt_read(mpt, MPT_OFFSET_FUBAR); 172101704Smjacob 173101704Smjacob /* Enable diagnostic registers */ 174101704Smjacob mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_1); 175101704Smjacob mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_2); 176101704Smjacob mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_3); 177101704Smjacob mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_4); 178101704Smjacob mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_5); 179101704Smjacob 180101704Smjacob /* Diag. port is now active so we can now hit the reset bit */ 181101704Smjacob mpt_write(mpt, MPT_OFFSET_DIAGNOSTIC, MPT_DIAG_RESET_IOC); 182101704Smjacob 183101704Smjacob DELAY(10000); 184101704Smjacob 185101704Smjacob /* Disable Diagnostic Register */ 186101704Smjacob mpt_write(mpt, MPT_OFFSET_SEQUENCE, 0xFF); 187101704Smjacob 188101704Smjacob /* Restore the config register values */ 189101704Smjacob /* Hard resets are known to screw up the BAR for diagnostic 190101704Smjacob memory accesses (Mem1). */ 191101704Smjacob mpt_set_config_regs(mpt); 192101704Smjacob if (mpt->mpt2 != NULL) { 193101704Smjacob mpt_set_config_regs(mpt->mpt2); 194101704Smjacob } 195101704Smjacob 196101704Smjacob /* Note that if there is no valid firmware to run, the doorbell will 197101704Smjacob remain in the reset state (0x00000000) */ 198101704Smjacob} 199101704Smjacob 200101704Smjacob/* 201101704Smjacob * Reset the IOC when needed. Try software command first then if needed 202101704Smjacob * poke at the magic diagnostic reset. Note that a hard reset resets 203101704Smjacob * *both* IOCs on dual function chips (FC929 && LSI1030) as well as 204101704Smjacob * fouls up the PCI configuration registers. 205101704Smjacob */ 206101704Smjacobint 207102199Smjacobmpt_reset(mpt_softc_t *mpt) 208101704Smjacob{ 209101704Smjacob int ret; 210101704Smjacob 211101704Smjacob /* Try a soft reset */ 212101704Smjacob if ((ret = mpt_soft_reset(mpt)) != MPT_OK) { 213101704Smjacob /* Failed; do a hard reset */ 214101704Smjacob mpt_hard_reset(mpt); 215101704Smjacob 216101704Smjacob /* Wait for the IOC to reload and come out of reset state */ 217101704Smjacob ret = mpt_wait_state(mpt, MPT_DB_STATE_READY); 218101704Smjacob if (ret != MPT_OK) { 219103914Smjacob mpt_prt(mpt, "failed to reset device"); 220101704Smjacob } 221101704Smjacob } 222101704Smjacob 223101704Smjacob return ret; 224101704Smjacob} 225101704Smjacob 226101704Smjacob/* Return a command buffer to the free queue */ 227101704Smjacobvoid 228102199Smjacobmpt_free_request(mpt_softc_t *mpt, request_t *req) 229101704Smjacob{ 230103871Smjacob if (req == NULL || req != &mpt->request_pool[req->index]) { 231101704Smjacob panic("mpt_free_request bad req ptr\n"); 232101704Smjacob return; 233101704Smjacob } 234103827Smjacob req->sequence = 0; 235101704Smjacob req->ccb = NULL; 236101704Smjacob req->debug = REQ_FREE; 237101704Smjacob SLIST_INSERT_HEAD(&mpt->request_free_list, req, link); 238101704Smjacob} 239101704Smjacob 240101704Smjacob/* Get a command buffer from the free queue */ 241101704Smjacobrequest_t * 242102199Smjacobmpt_get_request(mpt_softc_t *mpt) 243101704Smjacob{ 244101704Smjacob request_t *req; 245101704Smjacob req = SLIST_FIRST(&mpt->request_free_list); 246101704Smjacob if (req != NULL) { 247103871Smjacob if (req != &mpt->request_pool[req->index]) { 248101704Smjacob panic("mpt_get_request: corrupted request free list\n"); 249101704Smjacob } 250101704Smjacob if (req->ccb != NULL) { 251101704Smjacob panic("mpt_get_request: corrupted request free list (ccb)\n"); 252101704Smjacob } 253101704Smjacob SLIST_REMOVE_HEAD(&mpt->request_free_list, link); 254101704Smjacob req->debug = REQ_IN_PROGRESS; 255101704Smjacob } 256101704Smjacob return req; 257101704Smjacob} 258101704Smjacob 259101704Smjacob/* Pass the command to the IOC */ 260101704Smjacobvoid 261102199Smjacobmpt_send_cmd(mpt_softc_t *mpt, request_t *req) 262101704Smjacob{ 263101704Smjacob req->sequence = mpt->sequence++; 264101704Smjacob if (mpt->verbose > 1) { 265101704Smjacob u_int32_t *pReq; 266101704Smjacob pReq = req->req_vbuf; 267103914Smjacob mpt_prt(mpt, "Send Request %d (0x%x):", 268103914Smjacob req->index, req->req_pbuf); 269103914Smjacob mpt_prt(mpt, "%08x %08x %08x %08x", 270101704Smjacob pReq[0], pReq[1], pReq[2], pReq[3]); 271103914Smjacob mpt_prt(mpt, "%08x %08x %08x %08x", 272101704Smjacob pReq[4], pReq[5], pReq[6], pReq[7]); 273103914Smjacob mpt_prt(mpt, "%08x %08x %08x %08x", 274101704Smjacob pReq[8], pReq[9], pReq[10], pReq[11]); 275103914Smjacob mpt_prt(mpt, "%08x %08x %08x %08x", 276101704Smjacob pReq[12], pReq[13], pReq[14], pReq[15]); 277101704Smjacob } 278101704Smjacob bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap, 279103914Smjacob BUS_DMASYNC_PREWRITE); 280101704Smjacob req->debug = REQ_ON_CHIP; 281101704Smjacob mpt_write(mpt, MPT_OFFSET_REQUEST_Q, (u_int32_t) req->req_pbuf); 282101704Smjacob} 283101704Smjacob 284101704Smjacob/* 285101704Smjacob * Give the reply buffer back to the IOC after we have 286101704Smjacob * finished processing it. 287101704Smjacob */ 288101704Smjacobvoid 289102199Smjacobmpt_free_reply(mpt_softc_t *mpt, u_int32_t ptr) 290101704Smjacob{ 291101704Smjacob mpt_write(mpt, MPT_OFFSET_REPLY_Q, ptr); 292101704Smjacob} 293101704Smjacob 294101704Smjacob/* Get a reply from the IOC */ 295101704Smjacobu_int32_t 296102199Smjacobmpt_pop_reply_queue(mpt_softc_t *mpt) 297101704Smjacob{ 298101704Smjacob return mpt_read(mpt, MPT_OFFSET_REPLY_Q); 299101704Smjacob} 300101704Smjacob 301101704Smjacob/* 302101704Smjacob * Send a command to the IOC via the handshake register. 303101704Smjacob * 304101704Smjacob * Only done at initialization time and for certain unusual 305101704Smjacob * commands such as device/bus reset as specified by LSI. 306101704Smjacob */ 307101704Smjacobint 308102199Smjacobmpt_send_handshake_cmd(mpt_softc_t *mpt, size_t len, void *cmd) 309101704Smjacob{ 310101704Smjacob int i; 311101704Smjacob u_int32_t data, *data32; 312101704Smjacob 313101704Smjacob /* Check condition of the IOC */ 314101704Smjacob data = mpt_rd_db(mpt); 315101704Smjacob if (((MPT_STATE(data) != MPT_DB_STATE_READY) && 316101704Smjacob (MPT_STATE(data) != MPT_DB_STATE_RUNNING) && 317101704Smjacob (MPT_STATE(data) != MPT_DB_STATE_FAULT)) || 318101704Smjacob ( MPT_DB_IS_IN_USE(data) )) { 319103914Smjacob mpt_prt(mpt, "handshake aborted due to invalid doorbell state"); 320101704Smjacob mpt_print_db(data); 321101704Smjacob return(EBUSY); 322101704Smjacob } 323101704Smjacob 324101704Smjacob /* We move things in 32 bit chunks */ 325101704Smjacob len = (len + 3) >> 2; 326101704Smjacob data32 = cmd; 327101704Smjacob 328101704Smjacob /* Clear any left over pending doorbell interupts */ 329101704Smjacob if (MPT_DB_INTR(mpt_rd_intr(mpt))) 330101704Smjacob mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 331101704Smjacob 332101704Smjacob /* 333101704Smjacob * Tell the handshake reg. we are going to send a command 334101704Smjacob * and how long it is going to be. 335101704Smjacob */ 336101704Smjacob data = (MPI_FUNCTION_HANDSHAKE << MPI_DOORBELL_FUNCTION_SHIFT) | 337101704Smjacob (len << MPI_DOORBELL_ADD_DWORDS_SHIFT); 338101704Smjacob mpt_write(mpt, MPT_OFFSET_DOORBELL, data); 339101704Smjacob 340101704Smjacob /* Wait for the chip to notice */ 341101704Smjacob if (mpt_wait_db_int(mpt) != MPT_OK) { 342103914Smjacob mpt_prt(mpt, "mpt_send_handshake_cmd timeout1"); 343101704Smjacob return ETIMEDOUT; 344101704Smjacob } 345101704Smjacob 346101704Smjacob /* Clear the interrupt */ 347101704Smjacob mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 348101704Smjacob 349101704Smjacob if (mpt_wait_db_ack(mpt) != MPT_OK) { 350103914Smjacob mpt_prt(mpt, "mpt_send_handshake_cmd timeout2"); 351101704Smjacob return ETIMEDOUT; 352101704Smjacob } 353101704Smjacob 354101704Smjacob /* Send the command */ 355101704Smjacob for (i = 0; i < len; i++) { 356101704Smjacob mpt_write(mpt, MPT_OFFSET_DOORBELL, *data32++); 357101704Smjacob if (mpt_wait_db_ack(mpt) != MPT_OK) { 358103914Smjacob mpt_prt(mpt, 359103914Smjacob "mpt_send_handshake_cmd timeout! index = %d", i); 360101704Smjacob return ETIMEDOUT; 361101704Smjacob } 362101704Smjacob } 363101704Smjacob return MPT_OK; 364101704Smjacob} 365101704Smjacob 366101704Smjacob/* Get the response from the handshake register */ 367101704Smjacobint 368102199Smjacobmpt_recv_handshake_reply(mpt_softc_t *mpt, size_t reply_len, void *reply) 369101704Smjacob{ 370101704Smjacob int left, reply_left; 371101704Smjacob u_int16_t *data16; 372101704Smjacob MSG_DEFAULT_REPLY *hdr; 373101704Smjacob 374101704Smjacob /* We move things out in 16 bit chunks */ 375101704Smjacob reply_len >>= 1; 376101704Smjacob data16 = (u_int16_t *)reply; 377101704Smjacob 378101704Smjacob hdr = (MSG_DEFAULT_REPLY *)reply; 379101704Smjacob 380101704Smjacob /* Get first word */ 381101704Smjacob if (mpt_wait_db_int(mpt) != MPT_OK) { 382103914Smjacob mpt_prt(mpt, "mpt_recv_handshake_cmd timeout1"); 383101704Smjacob return ETIMEDOUT; 384101704Smjacob } 385101704Smjacob *data16++ = mpt_read(mpt, MPT_OFFSET_DOORBELL) & MPT_DB_DATA_MASK; 386101704Smjacob mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 387101704Smjacob 388101704Smjacob /* Get Second Word */ 389101704Smjacob if (mpt_wait_db_int(mpt) != MPT_OK) { 390103914Smjacob mpt_prt(mpt, "mpt_recv_handshake_cmd timeout2"); 391101704Smjacob return ETIMEDOUT; 392101704Smjacob } 393101704Smjacob *data16++ = mpt_read(mpt, MPT_OFFSET_DOORBELL) & MPT_DB_DATA_MASK; 394101704Smjacob mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 395101704Smjacob 396101704Smjacob /* With the second word, we can now look at the length */ 397101704Smjacob if (mpt->verbose > 1 && ((reply_len >> 1) != hdr->MsgLength)) { 398103914Smjacob mpt_prt(mpt, "reply length does not match message length: " 399103914Smjacob "got 0x%02x, expected 0x%02x", 400103914Smjacob hdr->MsgLength << 2, reply_len << 1); 401101704Smjacob } 402101704Smjacob 403101704Smjacob /* Get rest of the reply; but don't overflow the provided buffer */ 404101704Smjacob left = (hdr->MsgLength << 1) - 2; 405101704Smjacob reply_left = reply_len - 2; 406101704Smjacob while (left--) { 407101704Smjacob u_int16_t datum; 408101704Smjacob 409101704Smjacob if (mpt_wait_db_int(mpt) != MPT_OK) { 410103914Smjacob mpt_prt(mpt, "mpt_recv_handshake_cmd timeout3"); 411101704Smjacob return ETIMEDOUT; 412101704Smjacob } 413101704Smjacob datum = mpt_read(mpt, MPT_OFFSET_DOORBELL); 414101704Smjacob 415101704Smjacob if (reply_left-- > 0) 416101704Smjacob *data16++ = datum & MPT_DB_DATA_MASK; 417101704Smjacob 418101704Smjacob mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 419101704Smjacob } 420101704Smjacob 421101704Smjacob /* One more wait & clear at the end */ 422101704Smjacob if (mpt_wait_db_int(mpt) != MPT_OK) { 423103914Smjacob mpt_prt(mpt, "mpt_recv_handshake_cmd timeout4"); 424101704Smjacob return ETIMEDOUT; 425101704Smjacob } 426101704Smjacob mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 427101704Smjacob 428101704Smjacob if ((hdr->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 429101704Smjacob if (mpt->verbose > 1) 430101704Smjacob mpt_print_reply(hdr); 431101704Smjacob return (MPT_FAIL | hdr->IOCStatus); 432101704Smjacob } 433101704Smjacob 434101704Smjacob return (0); 435101704Smjacob} 436101704Smjacob 437101704Smjacobstatic int 438102199Smjacobmpt_get_iocfacts(mpt_softc_t *mpt, MSG_IOC_FACTS_REPLY *freplp) 439101704Smjacob{ 440101704Smjacob MSG_IOC_FACTS f_req; 441101704Smjacob int error; 442101704Smjacob 443101704Smjacob bzero(&f_req, sizeof f_req); 444101704Smjacob f_req.Function = MPI_FUNCTION_IOC_FACTS; 445101704Smjacob f_req.MsgContext = 0x12071942; 446101704Smjacob error = mpt_send_handshake_cmd(mpt, sizeof f_req, &f_req); 447101704Smjacob if (error) 448101704Smjacob return(error); 449101704Smjacob error = mpt_recv_handshake_reply(mpt, sizeof (*freplp), freplp); 450101704Smjacob return (error); 451101704Smjacob} 452101704Smjacob 453102199Smjacobstatic int 454102199Smjacobmpt_get_portfacts(mpt_softc_t *mpt, MSG_PORT_FACTS_REPLY *freplp) 455102199Smjacob{ 456102199Smjacob MSG_PORT_FACTS f_req; 457102199Smjacob int error; 458102199Smjacob 459102199Smjacob /* XXX: Only getting PORT FACTS for Port 0 */ 460102199Smjacob bzero(&f_req, sizeof f_req); 461102199Smjacob f_req.Function = MPI_FUNCTION_PORT_FACTS; 462102199Smjacob f_req.MsgContext = 0x12071943; 463102199Smjacob error = mpt_send_handshake_cmd(mpt, sizeof f_req, &f_req); 464102199Smjacob if (error) 465102199Smjacob return(error); 466102199Smjacob error = mpt_recv_handshake_reply(mpt, sizeof (*freplp), freplp); 467102199Smjacob return (error); 468102199Smjacob} 469102199Smjacob 470101704Smjacob/* 471101704Smjacob * Send the initialization request. This is where we specify how many 472101704Smjacob * SCSI busses and how many devices per bus we wish to emulate. 473101704Smjacob * This is also the command that specifies the max size of the reply 474101704Smjacob * frames from the IOC that we will be allocating. 475101704Smjacob */ 476101704Smjacobstatic int 477102199Smjacobmpt_send_ioc_init(mpt_softc_t *mpt, u_int32_t who) 478101704Smjacob{ 479101704Smjacob int error = 0; 480101704Smjacob MSG_IOC_INIT init; 481101704Smjacob MSG_IOC_INIT_REPLY reply; 482101704Smjacob 483101704Smjacob bzero(&init, sizeof init); 484101704Smjacob init.WhoInit = who; 485101704Smjacob init.Function = MPI_FUNCTION_IOC_INIT; 486101704Smjacob if (mpt->is_fc) { 487101704Smjacob init.MaxDevices = 255; 488101704Smjacob } else { 489101704Smjacob init.MaxDevices = 16; 490101704Smjacob } 491101704Smjacob init.MaxBuses = 1; 492101704Smjacob init.ReplyFrameSize = MPT_REPLY_SIZE; 493101704Smjacob init.MsgContext = 0x12071941; 494101704Smjacob 495101704Smjacob if ((error = mpt_send_handshake_cmd(mpt, sizeof init, &init)) != 0) { 496101704Smjacob return(error); 497101704Smjacob } 498101704Smjacob 499101704Smjacob error = mpt_recv_handshake_reply(mpt, sizeof reply, &reply); 500101704Smjacob return (error); 501101704Smjacob} 502101704Smjacob 503102199Smjacob 504102199Smjacob/* 505102199Smjacob * Utiltity routine to read configuration headers and pages 506102199Smjacob */ 507102199Smjacob 508101704Smjacobstatic int 509115778Smjacobmpt_read_cfg_header(mpt_softc_t *, int, int, int, CONFIG_PAGE_HEADER *); 510102199Smjacob 511102199Smjacobstatic int 512102199Smjacobmpt_read_cfg_header(mpt_softc_t *mpt, int PageType, int PageNumber, 513115778Smjacob int PageAddress, CONFIG_PAGE_HEADER *rslt) 514101704Smjacob{ 515101704Smjacob int count; 516101704Smjacob request_t *req; 517102199Smjacob MSG_CONFIG *cfgp; 518102199Smjacob MSG_CONFIG_REPLY *reply; 519102199Smjacob 520102199Smjacob req = mpt_get_request(mpt); 521102199Smjacob 522102199Smjacob cfgp = req->req_vbuf; 523102199Smjacob bzero(cfgp, sizeof *cfgp); 524102199Smjacob 525102199Smjacob cfgp->Action = MPI_CONFIG_ACTION_PAGE_HEADER; 526102199Smjacob cfgp->Function = MPI_FUNCTION_CONFIG; 527102199Smjacob cfgp->Header.PageNumber = (U8) PageNumber; 528102199Smjacob cfgp->Header.PageType = (U8) PageType; 529102199Smjacob cfgp->PageAddress = PageAddress; 530102199Smjacob MPI_pSGE_SET_FLAGS(((SGE_SIMPLE32 *) &cfgp->PageBufferSGE), 531102199Smjacob (MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | 532102199Smjacob MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_LIST)); 533102199Smjacob cfgp->MsgContext = req->index | 0x80000000; 534102199Smjacob 535102199Smjacob mpt_check_doorbell(mpt); 536102199Smjacob mpt_send_cmd(mpt, req); 537102199Smjacob count = 0; 538102199Smjacob do { 539102199Smjacob DELAY(500); 540102199Smjacob mpt_intr(mpt); 541102199Smjacob if (++count == 1000) { 542103914Smjacob mpt_prt(mpt, "read_cfg_header timed out"); 543102199Smjacob return (-1); 544102199Smjacob } 545102199Smjacob } while (req->debug == REQ_ON_CHIP); 546102199Smjacob 547102199Smjacob reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence); 548102199Smjacob if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 549103914Smjacob mpt_prt(mpt, "mpt_read_cfg_header: Config Info Status %x", 550102199Smjacob reply->IOCStatus); 551103914Smjacob mpt_free_reply(mpt, (req->sequence << 1)); 552102199Smjacob return (-1); 553102199Smjacob } 554115778Smjacob bcopy(&reply->Header, rslt, sizeof (CONFIG_PAGE_HEADER)); 555102199Smjacob mpt_free_reply(mpt, (req->sequence << 1)); 556102199Smjacob mpt_free_request(mpt, req); 557102199Smjacob return (0); 558102199Smjacob} 559102199Smjacob 560103827Smjacob#define CFG_DATA_OFF 128 561102199Smjacob 562102822Smjacobint 563115778Smjacobmpt_read_cfg_page(mpt_softc_t *mpt, int PageAddress, CONFIG_PAGE_HEADER *hdr) 564102199Smjacob{ 565102199Smjacob int count; 566102199Smjacob request_t *req; 567102199Smjacob SGE_SIMPLE32 *se; 568102199Smjacob MSG_CONFIG *cfgp; 569102199Smjacob size_t amt; 570102199Smjacob MSG_CONFIG_REPLY *reply; 571102199Smjacob 572102199Smjacob req = mpt_get_request(mpt); 573102199Smjacob 574102199Smjacob cfgp = req->req_vbuf; 575103827Smjacob bzero(cfgp, MPT_REQUEST_AREA); 576102199Smjacob cfgp->Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 577102199Smjacob cfgp->Function = MPI_FUNCTION_CONFIG; 578102199Smjacob cfgp->Header = *hdr; 579103914Smjacob amt = (cfgp->Header.PageLength * sizeof (u_int32_t)); 580102199Smjacob cfgp->Header.PageType &= MPI_CONFIG_PAGETYPE_MASK; 581102199Smjacob cfgp->PageAddress = PageAddress; 582102199Smjacob se = (SGE_SIMPLE32 *) &cfgp->PageBufferSGE; 583102199Smjacob se->Address = req->req_pbuf + CFG_DATA_OFF; 584102199Smjacob MPI_pSGE_SET_LENGTH(se, amt); 585102199Smjacob MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT | 586102199Smjacob MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | 587102199Smjacob MPI_SGE_FLAGS_END_OF_LIST)); 588102199Smjacob 589102199Smjacob cfgp->MsgContext = req->index | 0x80000000; 590102199Smjacob 591102199Smjacob mpt_check_doorbell(mpt); 592102199Smjacob mpt_send_cmd(mpt, req); 593102199Smjacob count = 0; 594102199Smjacob do { 595102199Smjacob DELAY(500); 596102199Smjacob mpt_intr(mpt); 597102199Smjacob if (++count == 1000) { 598103914Smjacob mpt_prt(mpt, "read_cfg_page timed out"); 599102199Smjacob return (-1); 600102199Smjacob } 601102199Smjacob } while (req->debug == REQ_ON_CHIP); 602102199Smjacob 603102199Smjacob reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence); 604102199Smjacob if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 605103914Smjacob mpt_prt(mpt, "mpt_read_cfg_page: Config Info Status %x", 606102199Smjacob reply->IOCStatus); 607103914Smjacob mpt_free_reply(mpt, (req->sequence << 1)); 608102199Smjacob return (-1); 609102199Smjacob } 610102199Smjacob mpt_free_reply(mpt, (req->sequence << 1)); 611102199Smjacob bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap, 612102199Smjacob BUS_DMASYNC_POSTREAD); 613102199Smjacob if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 614102199Smjacob cfgp->Header.PageNumber == 0) { 615115778Smjacob amt = sizeof (CONFIG_PAGE_SCSI_PORT_0); 616102199Smjacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 617102199Smjacob cfgp->Header.PageNumber == 1) { 618115778Smjacob amt = sizeof (CONFIG_PAGE_SCSI_PORT_1); 619102199Smjacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 620102199Smjacob cfgp->Header.PageNumber == 2) { 621115778Smjacob amt = sizeof (CONFIG_PAGE_SCSI_PORT_2); 622102199Smjacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && 623102199Smjacob cfgp->Header.PageNumber == 0) { 624115778Smjacob amt = sizeof (CONFIG_PAGE_SCSI_DEVICE_0); 625102199Smjacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && 626102199Smjacob cfgp->Header.PageNumber == 1) { 627115778Smjacob amt = sizeof (CONFIG_PAGE_SCSI_DEVICE_1); 628102199Smjacob } 629102199Smjacob bcopy(((caddr_t)req->req_vbuf)+CFG_DATA_OFF, hdr, amt); 630102199Smjacob mpt_free_request(mpt, req); 631102199Smjacob return (0); 632102199Smjacob} 633102199Smjacob 634102822Smjacobint 635115778Smjacobmpt_write_cfg_page(mpt_softc_t *mpt, int PageAddress, CONFIG_PAGE_HEADER *hdr) 636102199Smjacob{ 637102199Smjacob int count, hdr_attr; 638102199Smjacob request_t *req; 639102199Smjacob SGE_SIMPLE32 *se; 640102199Smjacob MSG_CONFIG *cfgp; 641102199Smjacob size_t amt; 642102199Smjacob MSG_CONFIG_REPLY *reply; 643102199Smjacob 644102199Smjacob req = mpt_get_request(mpt); 645102199Smjacob 646102199Smjacob cfgp = req->req_vbuf; 647102199Smjacob bzero(cfgp, sizeof *cfgp); 648102199Smjacob 649102199Smjacob hdr_attr = hdr->PageType & MPI_CONFIG_PAGEATTR_MASK; 650102199Smjacob if (hdr_attr != MPI_CONFIG_PAGEATTR_CHANGEABLE && 651102199Smjacob hdr_attr != MPI_CONFIG_PAGEATTR_PERSISTENT) { 652103914Smjacob mpt_prt(mpt, "page type 0x%x not changeable", 653102199Smjacob hdr->PageType & MPI_CONFIG_PAGETYPE_MASK); 654102199Smjacob return (-1); 655102199Smjacob } 656102199Smjacob hdr->PageType &= MPI_CONFIG_PAGETYPE_MASK; 657102199Smjacob 658102199Smjacob cfgp->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; 659102199Smjacob cfgp->Function = MPI_FUNCTION_CONFIG; 660102199Smjacob cfgp->Header = *hdr; 661103914Smjacob amt = (cfgp->Header.PageLength * sizeof (u_int32_t)); 662102199Smjacob cfgp->PageAddress = PageAddress; 663102199Smjacob 664102199Smjacob se = (SGE_SIMPLE32 *) &cfgp->PageBufferSGE; 665102199Smjacob se->Address = req->req_pbuf + CFG_DATA_OFF; 666102199Smjacob MPI_pSGE_SET_LENGTH(se, amt); 667102199Smjacob MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT | 668102199Smjacob MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | 669102199Smjacob MPI_SGE_FLAGS_END_OF_LIST | MPI_SGE_FLAGS_HOST_TO_IOC)); 670102199Smjacob 671102199Smjacob cfgp->MsgContext = req->index | 0x80000000; 672102199Smjacob 673102199Smjacob if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 674102199Smjacob cfgp->Header.PageNumber == 0) { 675115778Smjacob amt = sizeof (CONFIG_PAGE_SCSI_PORT_0); 676102199Smjacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 677102199Smjacob cfgp->Header.PageNumber == 1) { 678115778Smjacob amt = sizeof (CONFIG_PAGE_SCSI_PORT_1); 679102199Smjacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 680102199Smjacob cfgp->Header.PageNumber == 2) { 681115778Smjacob amt = sizeof (CONFIG_PAGE_SCSI_PORT_2); 682102199Smjacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && 683102199Smjacob cfgp->Header.PageNumber == 0) { 684115778Smjacob amt = sizeof (CONFIG_PAGE_SCSI_DEVICE_0); 685102199Smjacob } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && 686102199Smjacob cfgp->Header.PageNumber == 1) { 687115778Smjacob amt = sizeof (CONFIG_PAGE_SCSI_DEVICE_1); 688102199Smjacob } 689102199Smjacob bcopy(hdr, ((caddr_t)req->req_vbuf)+CFG_DATA_OFF, amt); 690103914Smjacob /* Restore stripped out attributes */ 691103914Smjacob hdr->PageType |= hdr_attr; 692102199Smjacob 693102199Smjacob mpt_check_doorbell(mpt); 694102199Smjacob mpt_send_cmd(mpt, req); 695102199Smjacob count = 0; 696102199Smjacob do { 697102199Smjacob DELAY(500); 698102199Smjacob mpt_intr(mpt); 699102199Smjacob if (++count == 1000) { 700102199Smjacob hdr->PageType |= hdr_attr; 701103914Smjacob mpt_prt(mpt, "mpt_write_cfg_page timed out"); 702102199Smjacob return (-1); 703102199Smjacob } 704102199Smjacob } while (req->debug == REQ_ON_CHIP); 705102199Smjacob 706102199Smjacob reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence); 707102199Smjacob if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 708103914Smjacob mpt_prt(mpt, "mpt_write_cfg_page: Config Info Status %x", 709102199Smjacob reply->IOCStatus); 710103914Smjacob mpt_free_reply(mpt, (req->sequence << 1)); 711102199Smjacob return (-1); 712102199Smjacob } 713102199Smjacob mpt_free_reply(mpt, (req->sequence << 1)); 714102199Smjacob 715102199Smjacob mpt_free_request(mpt, req); 716102199Smjacob return (0); 717102199Smjacob} 718102199Smjacob 719102199Smjacob/* 720102199Smjacob * Read SCSI configuration information 721102199Smjacob */ 722102199Smjacobstatic int 723102199Smjacobmpt_read_config_info_spi(mpt_softc_t *mpt) 724102199Smjacob{ 725102199Smjacob int rv, i; 726102199Smjacob 727102199Smjacob rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 0, 728102199Smjacob 0, &mpt->mpt_port_page0.Header); 729102199Smjacob if (rv) { 730102199Smjacob return (-1); 731102199Smjacob } 732102199Smjacob if (mpt->verbose > 1) { 733103914Smjacob mpt_prt(mpt, "SPI Port Page 0 Header: %x %x %x %x", 734102199Smjacob mpt->mpt_port_page0.Header.PageVersion, 735102199Smjacob mpt->mpt_port_page0.Header.PageLength, 736102199Smjacob mpt->mpt_port_page0.Header.PageNumber, 737102199Smjacob mpt->mpt_port_page0.Header.PageType); 738102199Smjacob } 739102199Smjacob 740102199Smjacob rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 1, 741102199Smjacob 0, &mpt->mpt_port_page1.Header); 742102199Smjacob if (rv) { 743102199Smjacob return (-1); 744102199Smjacob } 745102199Smjacob if (mpt->verbose > 1) { 746103914Smjacob mpt_prt(mpt, "SPI Port Page 1 Header: %x %x %x %x", 747102199Smjacob mpt->mpt_port_page1.Header.PageVersion, 748102199Smjacob mpt->mpt_port_page1.Header.PageLength, 749102199Smjacob mpt->mpt_port_page1.Header.PageNumber, 750102199Smjacob mpt->mpt_port_page1.Header.PageType); 751102199Smjacob } 752102199Smjacob 753102199Smjacob rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 2, 754102199Smjacob 0, &mpt->mpt_port_page2.Header); 755102199Smjacob if (rv) { 756102199Smjacob return (-1); 757102199Smjacob } 758102199Smjacob 759102199Smjacob if (mpt->verbose > 1) { 760103914Smjacob mpt_prt(mpt, "SPI Port Page 2 Header: %x %x %x %x", 761102199Smjacob mpt->mpt_port_page1.Header.PageVersion, 762102199Smjacob mpt->mpt_port_page1.Header.PageLength, 763102199Smjacob mpt->mpt_port_page1.Header.PageNumber, 764102199Smjacob mpt->mpt_port_page1.Header.PageType); 765102199Smjacob } 766102199Smjacob 767102199Smjacob for (i = 0; i < 16; i++) { 768102199Smjacob rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE, 769102199Smjacob 0, i, &mpt->mpt_dev_page0[i].Header); 770102199Smjacob if (rv) { 771102199Smjacob return (-1); 772102199Smjacob } 773102199Smjacob if (mpt->verbose > 1) { 774103914Smjacob mpt_prt(mpt, 775103914Smjacob "SPI Target %d Device Page 0 Header: %x %x %x %x", 776102199Smjacob i, mpt->mpt_dev_page0[i].Header.PageVersion, 777102199Smjacob mpt->mpt_dev_page0[i].Header.PageLength, 778102199Smjacob mpt->mpt_dev_page0[i].Header.PageNumber, 779102199Smjacob mpt->mpt_dev_page0[i].Header.PageType); 780102199Smjacob } 781102199Smjacob 782102199Smjacob rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE, 783102199Smjacob 1, i, &mpt->mpt_dev_page1[i].Header); 784102199Smjacob if (rv) { 785102199Smjacob return (-1); 786102199Smjacob } 787102199Smjacob if (mpt->verbose > 1) { 788103914Smjacob mpt_prt(mpt, 789103914Smjacob "SPI Target %d Device Page 1 Header: %x %x %x %x", 790102199Smjacob i, mpt->mpt_dev_page1[i].Header.PageVersion, 791102199Smjacob mpt->mpt_dev_page1[i].Header.PageLength, 792102199Smjacob mpt->mpt_dev_page1[i].Header.PageNumber, 793102199Smjacob mpt->mpt_dev_page1[i].Header.PageType); 794102199Smjacob } 795102199Smjacob } 796102199Smjacob 797102199Smjacob /* 798102199Smjacob * At this point, we don't *have* to fail. As long as we have 799102199Smjacob * valid config header information, we can (barely) lurch 800102199Smjacob * along. 801102199Smjacob */ 802102199Smjacob 803102199Smjacob rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page0.Header); 804102199Smjacob if (rv) { 805103914Smjacob mpt_prt(mpt, "failed to read SPI Port Page 0"); 806102199Smjacob } else if (mpt->verbose > 1) { 807103914Smjacob mpt_prt(mpt, 808103914Smjacob "SPI Port Page 0: Capabilities %x PhysicalInterface %x", 809102199Smjacob mpt->mpt_port_page0.Capabilities, 810102199Smjacob mpt->mpt_port_page0.PhysicalInterface); 811102199Smjacob } 812102199Smjacob 813102199Smjacob rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page1.Header); 814102199Smjacob if (rv) { 815103914Smjacob mpt_prt(mpt, "failed to read SPI Port Page 1"); 816102199Smjacob } else if (mpt->verbose > 1) { 817103914Smjacob mpt_prt(mpt, 818103914Smjacob "SPI Port Page 1: Configuration %x OnBusTimerValue %x", 819102199Smjacob mpt->mpt_port_page1.Configuration, 820102199Smjacob mpt->mpt_port_page1.OnBusTimerValue); 821102199Smjacob } 822102199Smjacob 823102199Smjacob rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page2.Header); 824102199Smjacob if (rv) { 825103914Smjacob mpt_prt(mpt, "failed to read SPI Port Page 2"); 826102199Smjacob } else if (mpt->verbose > 1) { 827103914Smjacob mpt_prt(mpt, 828103914Smjacob "SPI Port Page 2: Flags %x Settings %x", 829102199Smjacob mpt->mpt_port_page2.PortFlags, 830102199Smjacob mpt->mpt_port_page2.PortSettings); 831102199Smjacob for (i = 0; i < 16; i++) { 832103914Smjacob mpt_prt(mpt, 833103914Smjacob "SPI Port Page 2 Tgt %d: timo %x SF %x Flags %x", 834102199Smjacob i, mpt->mpt_port_page2.DeviceSettings[i].Timeout, 835102199Smjacob mpt->mpt_port_page2.DeviceSettings[i].SyncFactor, 836102199Smjacob mpt->mpt_port_page2.DeviceSettings[i].DeviceFlags); 837102199Smjacob } 838102199Smjacob } 839102199Smjacob 840102199Smjacob for (i = 0; i < 16; i++) { 841102199Smjacob rv = mpt_read_cfg_page(mpt, i, &mpt->mpt_dev_page0[i].Header); 842102199Smjacob if (rv) { 843103914Smjacob mpt_prt(mpt, "cannot read SPI Tgt %d Device Page 0", i); 844102199Smjacob continue; 845102199Smjacob } 846102199Smjacob if (mpt->verbose > 1) { 847103914Smjacob mpt_prt(mpt, 848103914Smjacob "SPI Tgt %d Page 0: NParms %x Information %x", 849102199Smjacob i, mpt->mpt_dev_page0[i].NegotiatedParameters, 850102199Smjacob mpt->mpt_dev_page0[i].Information); 851102199Smjacob } 852102199Smjacob rv = mpt_read_cfg_page(mpt, i, &mpt->mpt_dev_page1[i].Header); 853102199Smjacob if (rv) { 854103914Smjacob mpt_prt(mpt, "cannot read SPI Tgt %d Device Page 1", i); 855102199Smjacob continue; 856102199Smjacob } 857102199Smjacob if (mpt->verbose > 1) { 858103914Smjacob mpt_prt(mpt, 859103914Smjacob "SPI Tgt %d Page 1: RParms %x Configuration %x", 860102199Smjacob i, mpt->mpt_dev_page1[i].RequestedParameters, 861102199Smjacob mpt->mpt_dev_page1[i].Configuration); 862102199Smjacob } 863102199Smjacob } 864102199Smjacob return (0); 865102199Smjacob} 866102199Smjacob 867102199Smjacob/* 868102199Smjacob * Validate SPI configuration information. 869102199Smjacob * 870102199Smjacob * In particular, validate SPI Port Page 1. 871102199Smjacob */ 872102199Smjacobstatic int 873102199Smjacobmpt_set_initial_config_spi(mpt_softc_t *mpt) 874102199Smjacob{ 875102199Smjacob int i, pp1val = ((1 << mpt->mpt_ini_id) << 16) | mpt->mpt_ini_id; 876102199Smjacob 877102822Smjacob mpt->mpt_disc_enable = 0xff; 878102822Smjacob mpt->mpt_tag_enable = 0; 879102822Smjacob 880102199Smjacob if (mpt->mpt_port_page1.Configuration != pp1val) { 881115778Smjacob CONFIG_PAGE_SCSI_PORT_1 tmp; 882103914Smjacob mpt_prt(mpt, 883103914Smjacob "SPI Port Page 1 Config value bad (%x)- should be %x", 884102199Smjacob mpt->mpt_port_page1.Configuration, pp1val); 885102199Smjacob tmp = mpt->mpt_port_page1; 886102199Smjacob tmp.Configuration = pp1val; 887102199Smjacob if (mpt_write_cfg_page(mpt, 0, &tmp.Header)) { 888102199Smjacob return (-1); 889102199Smjacob } 890102199Smjacob if (mpt_read_cfg_page(mpt, 0, &tmp.Header)) { 891102199Smjacob return (-1); 892102199Smjacob } 893102199Smjacob if (tmp.Configuration != pp1val) { 894103914Smjacob mpt_prt(mpt, 895103914Smjacob "failed to reset SPI Port Page 1 Config value"); 896102199Smjacob return (-1); 897102199Smjacob } 898102199Smjacob mpt->mpt_port_page1 = tmp; 899102199Smjacob } 900102199Smjacob 901102199Smjacob for (i = 0; i < 16; i++) { 902115778Smjacob CONFIG_PAGE_SCSI_DEVICE_1 tmp; 903102199Smjacob tmp = mpt->mpt_dev_page1[i]; 904102199Smjacob tmp.RequestedParameters = 0; 905102199Smjacob tmp.Configuration = 0; 906102199Smjacob if (mpt->verbose > 1) { 907103914Smjacob mpt_prt(mpt, 908103914Smjacob "Set Tgt %d SPI DevicePage 1 values to %x 0 %x", 909102199Smjacob i, tmp.RequestedParameters, tmp.Configuration); 910102199Smjacob } 911102199Smjacob if (mpt_write_cfg_page(mpt, i, &tmp.Header)) { 912102199Smjacob return (-1); 913102199Smjacob } 914102199Smjacob if (mpt_read_cfg_page(mpt, i, &tmp.Header)) { 915102199Smjacob return (-1); 916102199Smjacob } 917102199Smjacob mpt->mpt_dev_page1[i] = tmp; 918102199Smjacob if (mpt->verbose > 1) { 919103914Smjacob mpt_prt(mpt, 920103914Smjacob "SPI Tgt %d Page 1: RParm %x Configuration %x", i, 921102199Smjacob mpt->mpt_dev_page1[i].RequestedParameters, 922102199Smjacob mpt->mpt_dev_page1[i].Configuration); 923102199Smjacob } 924102199Smjacob } 925102199Smjacob return (0); 926102199Smjacob} 927102199Smjacob 928102199Smjacob/* 929102199Smjacob * Enable IOC port 930102199Smjacob */ 931102199Smjacobstatic int 932102199Smjacobmpt_send_port_enable(mpt_softc_t *mpt, int port) 933102199Smjacob{ 934102199Smjacob int count; 935102199Smjacob request_t *req; 936101704Smjacob MSG_PORT_ENABLE *enable_req; 937101704Smjacob 938101704Smjacob req = mpt_get_request(mpt); 939101704Smjacob 940101704Smjacob enable_req = req->req_vbuf; 941101704Smjacob bzero(enable_req, sizeof *enable_req); 942101704Smjacob 943101704Smjacob enable_req->Function = MPI_FUNCTION_PORT_ENABLE; 944101704Smjacob enable_req->MsgContext = req->index | 0x80000000; 945101704Smjacob enable_req->PortNumber = port; 946101704Smjacob 947101704Smjacob mpt_check_doorbell(mpt); 948101704Smjacob if (mpt->verbose > 1) { 949103914Smjacob mpt_prt(mpt, "enabling port %d", port); 950101704Smjacob } 951101704Smjacob mpt_send_cmd(mpt, req); 952101704Smjacob 953101704Smjacob count = 0; 954101704Smjacob do { 955101704Smjacob DELAY(500); 956101704Smjacob mpt_intr(mpt); 957103871Smjacob if (++count == 100000) { 958103914Smjacob mpt_prt(mpt, "port enable timed out"); 959101704Smjacob return (-1); 960101704Smjacob } 961101704Smjacob } while (req->debug == REQ_ON_CHIP); 962101704Smjacob mpt_free_request(mpt, req); 963101704Smjacob return (0); 964101704Smjacob} 965101704Smjacob 966101704Smjacob/* 967101704Smjacob * Enable/Disable asynchronous event reporting. 968101704Smjacob * 969101704Smjacob * NB: this is the first command we send via shared memory 970101704Smjacob * instead of the handshake register. 971101704Smjacob */ 972101704Smjacobstatic int 973102199Smjacobmpt_send_event_request(mpt_softc_t *mpt, int onoff) 974101704Smjacob{ 975101704Smjacob request_t *req; 976101704Smjacob MSG_EVENT_NOTIFY *enable_req; 977101704Smjacob 978101704Smjacob req = mpt_get_request(mpt); 979101704Smjacob 980101704Smjacob enable_req = req->req_vbuf; 981101704Smjacob bzero(enable_req, sizeof *enable_req); 982101704Smjacob 983101704Smjacob enable_req->Function = MPI_FUNCTION_EVENT_NOTIFICATION; 984101704Smjacob enable_req->MsgContext = req->index | 0x80000000; 985101704Smjacob enable_req->Switch = onoff; 986101704Smjacob 987101704Smjacob mpt_check_doorbell(mpt); 988101704Smjacob if (mpt->verbose > 1) { 989103914Smjacob mpt_prt(mpt, "%sabling async events", onoff? "en" : "dis"); 990101704Smjacob } 991101704Smjacob mpt_send_cmd(mpt, req); 992101704Smjacob 993101704Smjacob return (0); 994101704Smjacob} 995101704Smjacob 996101704Smjacob/* 997101704Smjacob * Un-mask the interupts on the chip. 998101704Smjacob */ 999101704Smjacobvoid 1000102199Smjacobmpt_enable_ints(mpt_softc_t *mpt) 1001101704Smjacob{ 1002101704Smjacob /* Unmask every thing except door bell int */ 1003101704Smjacob mpt_write(mpt, MPT_OFFSET_INTR_MASK, MPT_INTR_DB_MASK); 1004101704Smjacob} 1005101704Smjacob 1006101704Smjacob/* 1007101704Smjacob * Mask the interupts on the chip. 1008101704Smjacob */ 1009101704Smjacobvoid 1010102199Smjacobmpt_disable_ints(mpt_softc_t *mpt) 1011101704Smjacob{ 1012101704Smjacob /* Mask all interrupts */ 1013101704Smjacob mpt_write(mpt, MPT_OFFSET_INTR_MASK, 1014101704Smjacob MPT_INTR_REPLY_MASK | MPT_INTR_DB_MASK); 1015101704Smjacob} 1016101704Smjacob 1017101704Smjacob/* (Re)Initialize the chip for use */ 1018101704Smjacobint 1019102199Smjacobmpt_init(mpt_softc_t *mpt, u_int32_t who) 1020101704Smjacob{ 1021101704Smjacob int try; 1022101704Smjacob MSG_IOC_FACTS_REPLY facts; 1023102199Smjacob MSG_PORT_FACTS_REPLY pfp; 1024101704Smjacob u_int32_t pptr; 1025101704Smjacob int val; 1026101704Smjacob 1027101704Smjacob /* Put all request buffers (back) on the free list */ 1028101704Smjacob SLIST_INIT(&mpt->request_free_list); 1029103871Smjacob for (val = 0; val < MPT_MAX_REQUESTS(mpt); val++) { 1030103871Smjacob mpt_free_request(mpt, &mpt->request_pool[val]); 1031101704Smjacob } 1032101704Smjacob 1033101704Smjacob if (mpt->verbose > 1) { 1034103914Smjacob mpt_prt(mpt, "doorbell req = %s", 1035101704Smjacob mpt_ioc_diag(mpt_read(mpt, MPT_OFFSET_DOORBELL))); 1036101704Smjacob } 1037101704Smjacob 1038101704Smjacob /* 1039101704Smjacob * Start by making sure we're not at FAULT or RESET state 1040101704Smjacob */ 1041101704Smjacob switch (mpt_rd_db(mpt) & MPT_DB_STATE_MASK) { 1042101704Smjacob case MPT_DB_STATE_RESET: 1043101704Smjacob case MPT_DB_STATE_FAULT: 1044101704Smjacob if (mpt_reset(mpt) != MPT_OK) { 1045101704Smjacob return (EIO); 1046101704Smjacob } 1047101704Smjacob default: 1048101704Smjacob break; 1049101704Smjacob } 1050101704Smjacob 1051101704Smjacob for (try = 0; try < MPT_MAX_TRYS; try++) { 1052101704Smjacob /* 1053101704Smjacob * No need to reset if the IOC is already in the READY state. 1054101704Smjacob * 1055101704Smjacob * Force reset if initialization failed previously. 1056101704Smjacob * Note that a hard_reset of the second channel of a '929 1057101704Smjacob * will stop operation of the first channel. Hopefully, if the 1058101704Smjacob * first channel is ok, the second will not require a hard 1059101704Smjacob * reset. 1060101704Smjacob */ 1061101704Smjacob if ((mpt_rd_db(mpt) & MPT_DB_STATE_MASK) != 1062101704Smjacob MPT_DB_STATE_READY) { 1063101704Smjacob if (mpt_reset(mpt) != MPT_OK) { 1064101704Smjacob DELAY(10000); 1065101704Smjacob continue; 1066101704Smjacob } 1067101704Smjacob } 1068101704Smjacob 1069101704Smjacob if (mpt_get_iocfacts(mpt, &facts) != MPT_OK) { 1070103914Smjacob mpt_prt(mpt, "mpt_get_iocfacts failed"); 1071101704Smjacob continue; 1072102199Smjacob } 1073102199Smjacob 1074102199Smjacob if (mpt->verbose > 1) { 1075103914Smjacob mpt_prt(mpt, 1076103871Smjacob "IOCFACTS: GlobalCredits=%d BlockSize=%u " 1077101704Smjacob "Request Frame Size %u\n", facts.GlobalCredits, 1078101704Smjacob facts.BlockSize, facts.RequestFrameSize); 1079101704Smjacob } 1080101704Smjacob mpt->mpt_global_credits = facts.GlobalCredits; 1081101704Smjacob mpt->request_frame_size = facts.RequestFrameSize; 1082101704Smjacob 1083102199Smjacob if (mpt_get_portfacts(mpt, &pfp) != MPT_OK) { 1084103914Smjacob mpt_prt(mpt, "mpt_get_portfacts failed"); 1085102199Smjacob continue; 1086102199Smjacob } 1087102199Smjacob 1088102199Smjacob if (mpt->verbose > 1) { 1089103914Smjacob mpt_prt(mpt, 1090103871Smjacob "PORTFACTS: Type %x PFlags %x IID %d MaxDev %d\n", 1091103871Smjacob pfp.PortType, pfp.ProtocolFlags, pfp.PortSCSIID, 1092103871Smjacob pfp.MaxDevices); 1093102199Smjacob } 1094102199Smjacob 1095102199Smjacob if (pfp.PortType != MPI_PORTFACTS_PORTTYPE_SCSI && 1096102199Smjacob pfp.PortType != MPI_PORTFACTS_PORTTYPE_FC) { 1097103914Smjacob mpt_prt(mpt, "Unsupported Port Type (%x)", 1098102199Smjacob pfp.PortType); 1099102199Smjacob return (ENXIO); 1100102199Smjacob } 1101102199Smjacob if (!(pfp.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)) { 1102103914Smjacob mpt_prt(mpt, "initiator role unsupported"); 1103102199Smjacob return (ENXIO); 1104102199Smjacob } 1105102199Smjacob if (pfp.PortType == MPI_PORTFACTS_PORTTYPE_FC) { 1106102199Smjacob mpt->is_fc = 1; 1107102199Smjacob } else { 1108102199Smjacob mpt->is_fc = 0; 1109102199Smjacob } 1110102199Smjacob mpt->mpt_ini_id = pfp.PortSCSIID; 1111102199Smjacob 1112101704Smjacob if (mpt_send_ioc_init(mpt, who) != MPT_OK) { 1113103914Smjacob mpt_prt(mpt, "mpt_send_ioc_init failed"); 1114101704Smjacob continue; 1115102199Smjacob } 1116102199Smjacob 1117102199Smjacob if (mpt->verbose > 1) { 1118103914Smjacob mpt_prt(mpt, "mpt_send_ioc_init ok"); 1119101704Smjacob } 1120101704Smjacob 1121101704Smjacob if (mpt_wait_state(mpt, MPT_DB_STATE_RUNNING) != MPT_OK) { 1122103914Smjacob mpt_prt(mpt, "IOC failed to go to run state"); 1123101704Smjacob continue; 1124102199Smjacob } 1125102199Smjacob if (mpt->verbose > 1) { 1126103914Smjacob mpt_prt(mpt, "IOC now at RUNSTATE"); 1127101704Smjacob } 1128101704Smjacob 1129101704Smjacob /* 1130101704Smjacob * Give it reply buffers 1131101704Smjacob * 1132101704Smjacob * Do *not* except global credits. 1133101704Smjacob */ 1134101704Smjacob for (val = 0, pptr = mpt->reply_phys; 1135101704Smjacob (pptr + MPT_REPLY_SIZE) < (mpt->reply_phys + PAGE_SIZE); 1136101704Smjacob pptr += MPT_REPLY_SIZE) { 1137101704Smjacob mpt_free_reply(mpt, pptr); 1138101704Smjacob if (++val == mpt->mpt_global_credits - 1) 1139101704Smjacob break; 1140101704Smjacob } 1141101704Smjacob 1142102199Smjacob /* 1143102199Smjacob * Enable asynchronous event reporting 1144102199Smjacob */ 1145101704Smjacob mpt_send_event_request(mpt, 1); 1146101704Smjacob 1147102199Smjacob 1148102199Smjacob /* 1149102199Smjacob * Read set up initial configuration information 1150102199Smjacob * (SPI only for now) 1151102199Smjacob */ 1152102199Smjacob 1153102199Smjacob if (mpt->is_fc == 0) { 1154102199Smjacob if (mpt_read_config_info_spi(mpt)) { 1155102199Smjacob return (EIO); 1156102199Smjacob } 1157102199Smjacob if (mpt_set_initial_config_spi(mpt)) { 1158102199Smjacob return (EIO); 1159102199Smjacob } 1160102199Smjacob } 1161102199Smjacob 1162102199Smjacob /* 1163102199Smjacob * Now enable the port 1164102199Smjacob */ 1165101704Smjacob if (mpt_send_port_enable(mpt, 0) != MPT_OK) { 1166103914Smjacob mpt_prt(mpt, "failed to enable port 0"); 1167101704Smjacob continue; 1168102199Smjacob } 1169102199Smjacob 1170102199Smjacob if (mpt->verbose > 1) { 1171103914Smjacob mpt_prt(mpt, "enabled port 0"); 1172101704Smjacob } 1173101704Smjacob 1174101704Smjacob /* Everything worked */ 1175101704Smjacob break; 1176101704Smjacob } 1177101704Smjacob 1178101704Smjacob if (try >= MPT_MAX_TRYS) { 1179103914Smjacob mpt_prt(mpt, "failed to initialize IOC"); 1180101704Smjacob return (EIO); 1181101704Smjacob } 1182101704Smjacob 1183101704Smjacob if (mpt->verbose > 1) { 1184103914Smjacob mpt_prt(mpt, "enabling interrupts"); 1185101704Smjacob } 1186101704Smjacob 1187101704Smjacob mpt_enable_ints(mpt); 1188101704Smjacob return (0); 1189101704Smjacob} 1190