mpt.c revision 134123
12061Sjkh/* 218434Sache * Generic routines for LSI '909 FC adapters. 32061Sjkh * FreeBSD Version. 42061Sjkh * 515603Smarkm * Copyright (c) 2000, 2001 by Greg Ansley 62061Sjkh * 72061Sjkh * Redistribution and use in source and binary forms, with or without 83197Scsgr * modification, are permitted provided that the following conditions 93197Scsgr * are met: 102061Sjkh * 1. Redistributions of source code must retain the above copyright 1112483Speter * notice immediately at the beginning of the file, without modification, 122160Scsgr * this list of conditions, and the following disclaimer. 132834Swollman * 2. The name of the author may not be used to endorse or promote products 142061Sjkh * derived from this software without specific prior written permission. 152061Sjkh * 162160Scsgr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1717308Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 181594Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1917308Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2017308Speter * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2117308Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2217308Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2317308Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2417308Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2517308Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2617308Speter * SUCH DAMAGE. 2717308Speter */ 2817308Speter/* 2917308Speter * Additional Copyright (c) 2002 by Matthew Jacob under same license. 302061Sjkh */ 312061Sjkh 321594Srgrimes#include <sys/cdefs.h> 337407Srgrimes__FBSDID("$FreeBSD: head/sys/dev/mpt/mpt.c 134123 2004-08-21 17:44:57Z obrien $"); 347407Srgrimes 357108Sphk#include <dev/mpt/mpt_freebsd.h> 367108Sphk 377108Sphk#define MPT_MAX_TRYS 3 387407Srgrimes#define MPT_MAX_WAIT 300000 397407Srgrimes 407407Srgrimesstatic int maxwait_ack = 0; 417108Sphkstatic int maxwait_int = 0; 422061Sjkhstatic int maxwait_state = 0; 432061Sjkh 442061Sjkhstatic INLINE u_int32_t mpt_rd_db(mpt_softc_t *mpt); 4517308Speterstatic INLINE u_int32_t mpt_rd_intr(mpt_softc_t *mpt); 462061Sjkh 472061Sjkhstatic INLINE u_int32_t 482061Sjkhmpt_rd_db(mpt_softc_t *mpt) 492061Sjkh{ 502061Sjkh return mpt_read(mpt, MPT_OFFSET_DOORBELL); 513197Scsgr} 522626Scsgr 532626Scsgrstatic INLINE u_int32_t 542061Sjkhmpt_rd_intr(mpt_softc_t *mpt) 552061Sjkh{ 562061Sjkh return mpt_read(mpt, MPT_OFFSET_INTR_STATUS); 572061Sjkh} 582061Sjkh 592061Sjkh/* Busy wait for a door bell to be read by IOC */ 602061Sjkhstatic int 612061Sjkhmpt_wait_db_ack(mpt_softc_t *mpt) 622061Sjkh{ 632061Sjkh int i; 642061Sjkh for (i=0; i < MPT_MAX_WAIT; i++) { 652061Sjkh if (!MPT_DB_IS_BUSY(mpt_rd_intr(mpt))) { 662061Sjkh maxwait_ack = i > maxwait_ack ? i : maxwait_ack; 672061Sjkh return MPT_OK; 682061Sjkh } 692061Sjkh 702061Sjkh DELAY(100); 712061Sjkh } 722834Swollman return MPT_FAIL; 732834Swollman} 742834Swollman 752834Swollman/* Busy wait for a door bell interrupt */ 762834Swollmanstatic int 772834Swollmanmpt_wait_db_int(mpt_softc_t *mpt) 781594Srgrimes{ 794486Sphk int i; 804486Sphk for (i=0; i < MPT_MAX_WAIT; i++) { 814486Sphk if (MPT_DB_INTR(mpt_rd_intr(mpt))) { 824486Sphk maxwait_int = i > maxwait_int ? i : maxwait_int; 834486Sphk return MPT_OK; 842061Sjkh } 852061Sjkh DELAY(100); 862061Sjkh } 872061Sjkh return MPT_FAIL; 882061Sjkh} 892061Sjkh 902061Sjkh/* Wait for IOC to transition to a give state */ 912061Sjkhvoid 922061Sjkhmpt_check_doorbell(mpt_softc_t *mpt) 9317308Speter{ 942061Sjkh u_int32_t db = mpt_rd_db(mpt); 952061Sjkh if (MPT_STATE(db) != MPT_DB_STATE_RUNNING) { 962061Sjkh mpt_prt(mpt, "Device not running"); 972061Sjkh mpt_print_db(db); 982061Sjkh } 9912483Speter} 10012483Speter 10112483Speter/* Wait for IOC to transition to a give state */ 10212483Speterstatic int 1032061Sjkhmpt_wait_state(mpt_softc_t *mpt, enum DB_STATE_BITS state) 1042061Sjkh{ 1058854Srgrimes int i; 1062061Sjkh 1072061Sjkh for (i = 0; i < MPT_MAX_WAIT; i++) { 10812483Speter u_int32_t db = mpt_rd_db(mpt); 1092061Sjkh if (MPT_STATE(db) == state) { 11017308Speter maxwait_state = i > maxwait_state ? i : maxwait_state; 11117308Speter return (MPT_OK); 11217308Speter } 11317308Speter DELAY(100); 11415603Smarkm } 11515603Smarkm return (MPT_FAIL); 11617308Speter} 11717308Speter 11817308Speter 11917308Speter/* Issue the reset COMMAND to the IOC */ 12017308Speterint 12117308Spetermpt_soft_reset(mpt_softc_t *mpt) 12217308Speter{ 12317308Speter if (mpt->verbose) { 12417308Speter mpt_prt(mpt, "soft reset"); 12518362Sjkh } 12618434Sache 12718362Sjkh /* Have to use hard reset if we are not in Running state */ 12817308Speter if (MPT_STATE(mpt_rd_db(mpt)) != MPT_DB_STATE_RUNNING) { 12917308Speter mpt_prt(mpt, "soft reset failed: device not running"); 13017308Speter return MPT_FAIL; 13117308Speter } 13217308Speter 13317308Speter /* If door bell is in use we don't have a chance of getting 13416550Sjkh * a word in since the IOC probably crashed in message 1352061Sjkh * processing. So don't waste our time. 13617308Speter */ 1372061Sjkh if (MPT_DB_IS_IN_USE(mpt_rd_db(mpt))) { 13817308Speter mpt_prt(mpt, "soft reset failed: doorbell wedged"); 1392061Sjkh return MPT_FAIL; 14017308Speter } 14117308Speter 14217308Speter /* Send the reset request to the IOC */ 14317308Speter mpt_write(mpt, MPT_OFFSET_DOORBELL, 14417308Speter MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET << MPI_DOORBELL_FUNCTION_SHIFT); 14517308Speter if (mpt_wait_db_ack(mpt) != MPT_OK) { 14617308Speter mpt_prt(mpt, "soft reset failed: ack timeout"); 14717308Speter return MPT_FAIL; 14817308Speter } 14917308Speter 15017308Speter /* Wait for the IOC to reload and come out of reset state */ 15117466Speter if (mpt_wait_state(mpt, MPT_DB_STATE_READY) != MPT_OK) { 15217308Speter mpt_prt(mpt, "soft reset failed: device did not start running"); 15317308Speter return MPT_FAIL; 15417466Speter } 15517308Speter 15617308Speter return MPT_OK; 15717308Speter} 15817308Speter 15917466Speter/* This is a magic diagnostic reset that resets all the ARM 16017308Speter * processors in the chip. 16117308Speter */ 16217308Spetervoid 16317308Spetermpt_hard_reset(mpt_softc_t *mpt) 16417308Speter{ 16517308Speter /* This extra read comes for the Linux source 16617308Speter * released by LSI. It's function is undocumented! 16717308Speter */ 16817308Speter if (mpt->verbose) { 16917308Speter mpt_prt(mpt, "hard reset"); 17017308Speter } 17117308Speter mpt_read(mpt, MPT_OFFSET_FUBAR); 17217308Speter 17317308Speter /* Enable diagnostic registers */ 17417308Speter mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_1); 17517308Speter mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_2); 17617308Speter mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_3); 17717308Speter mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_4); 17817308Speter mpt_write(mpt, MPT_OFFSET_SEQUENCE, MPT_DIAG_SEQUENCE_5); 17917308Speter 18017308Speter /* Diag. port is now active so we can now hit the reset bit */ 18117308Speter mpt_write(mpt, MPT_OFFSET_DIAGNOSTIC, MPT_DIAG_RESET_IOC); 18217308Speter 18317308Speter DELAY(10000); 18417308Speter 18517308Speter /* Disable Diagnostic Register */ 18617308Speter mpt_write(mpt, MPT_OFFSET_SEQUENCE, 0xFF); 18718392Speter 18817308Speter /* Restore the config register values */ 18917308Speter /* Hard resets are known to screw up the BAR for diagnostic 19017308Speter memory accesses (Mem1). */ 19117308Speter mpt_set_config_regs(mpt); 19217962Speter if (mpt->mpt2 != NULL) { 19317308Speter mpt_set_config_regs(mpt->mpt2); 19417962Speter } 19517962Speter 19617962Speter /* Note that if there is no valid firmware to run, the doorbell will 19717962Speter remain in the reset state (0x00000000) */ 19817962Speter} 19917962Speter 20017962Speter/* 20117962Speter * Reset the IOC when needed. Try software command first then if needed 20217962Speter * poke at the magic diagnostic reset. Note that a hard reset resets 20317962Speter * *both* IOCs on dual function chips (FC929 && LSI1030) as well as 20417962Speter * fouls up the PCI configuration registers. 20517962Speter */ 20617962Speterint 20717962Spetermpt_reset(mpt_softc_t *mpt) 20817962Speter{ 20917308Speter int ret; 21016550Sjkh 21117308Speter /* Try a soft reset */ 21217308Speter if ((ret = mpt_soft_reset(mpt)) != MPT_OK) { 21317308Speter /* Failed; do a hard reset */ 21417308Speter mpt_hard_reset(mpt); 21516550Sjkh 21616550Sjkh /* Wait for the IOC to reload and come out of reset state */ 21717308Speter ret = mpt_wait_state(mpt, MPT_DB_STATE_READY); 21817308Speter if (ret != MPT_OK) { 21918434Sache mpt_prt(mpt, "failed to reset device"); 22017962Speter } 2212061Sjkh } 22217308Speter 22317308Speter return ret; 22417308Speter} 22517308Speter 22617308Speter/* Return a command buffer to the free queue */ 22717308Spetervoid 22817308Spetermpt_free_request(mpt_softc_t *mpt, request_t *req) 22917308Speter{ 23012483Speter if (req == NULL || req != &mpt->request_pool[req->index]) { 23117308Speter panic("mpt_free_request bad req ptr\n"); 23212483Speter return; 23317308Speter } 23412483Speter req->sequence = 0; 2352061Sjkh req->ccb = NULL; 23617308Speter req->debug = REQ_FREE; 2372061Sjkh SLIST_INSERT_HEAD(&mpt->request_free_list, req, link); 23817308Speter} 23917308Speter 24017308Speter/* Get a command buffer from the free queue */ 24117308Speterrequest_t * 24217308Spetermpt_get_request(mpt_softc_t *mpt) 24317308Speter{ 24417308Speter request_t *req; 24517308Speter req = SLIST_FIRST(&mpt->request_free_list); 24617962Speter if (req != NULL) { 24717308Speter if (req != &mpt->request_pool[req->index]) { 24817962Speter panic("mpt_get_request: corrupted request free list\n"); 24917308Speter } 25017962Speter if (req->ccb != NULL) { 25117962Speter panic("mpt_get_request: corrupted request free list (ccb)\n"); 25217962Speter } 25317962Speter SLIST_REMOVE_HEAD(&mpt->request_free_list, link); 25417962Speter req->debug = REQ_IN_PROGRESS; 25517962Speter } 25617962Speter return req; 25717962Speter} 25817308Speter 25917962Speter/* Pass the command to the IOC */ 26017962Spetervoid 26117962Spetermpt_send_cmd(mpt_softc_t *mpt, request_t *req) 26217962Speter{ 26317308Speter req->sequence = mpt->sequence++; 2642061Sjkh if (mpt->verbose > 1) { 26517308Speter u_int32_t *pReq; 26617308Speter pReq = req->req_vbuf; 26717308Speter mpt_prt(mpt, "Send Request %d (0x%x):", 26817308Speter req->index, req->req_pbuf); 26917308Speter mpt_prt(mpt, "%08x %08x %08x %08x", 27017308Speter pReq[0], pReq[1], pReq[2], pReq[3]); 27117308Speter mpt_prt(mpt, "%08x %08x %08x %08x", 2722302Spaul pReq[4], pReq[5], pReq[6], pReq[7]); 2732302Spaul mpt_prt(mpt, "%08x %08x %08x %08x", 2742302Spaul pReq[8], pReq[9], pReq[10], pReq[11]); 2752302Spaul mpt_prt(mpt, "%08x %08x %08x %08x", 2762302Spaul pReq[12], pReq[13], pReq[14], pReq[15]); 2772302Spaul } 27810760Sache bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap, 27910760Sache BUS_DMASYNC_PREWRITE); 2802302Spaul req->debug = REQ_ON_CHIP; 28110760Sache mpt_write(mpt, MPT_OFFSET_REQUEST_Q, (u_int32_t) req->req_pbuf); 28210760Sache} 28310760Sache 28410760Sache/* 2852302Spaul * Give the reply buffer back to the IOC after we have 2862302Spaul * finished processing it. 2872302Spaul */ 2882302Spaulvoid 28916591Spstmpt_free_reply(mpt_softc_t *mpt, u_int32_t ptr) 2902302Spaul{ 2912302Spaul mpt_write(mpt, MPT_OFFSET_REPLY_Q, ptr); 29217308Speter} 29317308Speter 29417308Speter/* Get a reply from the IOC */ 29517308Speteru_int32_t 29617308Spetermpt_pop_reply_queue(mpt_softc_t *mpt) 29717308Speter{ 29817308Speter return mpt_read(mpt, MPT_OFFSET_REPLY_Q); 2992061Sjkh} 30017308Speter 3012061Sjkh/* 30217308Speter * Send a command to the IOC via the handshake register. 30317308Speter * 30417308Speter * Only done at initialization time and for certain unusual 30517308Speter * commands such as device/bus reset as specified by LSI. 30617308Speter */ 30717308Speterint 30817308Spetermpt_send_handshake_cmd(mpt_softc_t *mpt, size_t len, void *cmd) 30917308Speter{ 31017308Speter int i; 31117308Speter u_int32_t data, *data32; 31217308Speter 31317308Speter /* Check condition of the IOC */ 31417308Speter data = mpt_rd_db(mpt); 31517308Speter if (((MPT_STATE(data) != MPT_DB_STATE_READY) && 3162061Sjkh (MPT_STATE(data) != MPT_DB_STATE_RUNNING) && 31717308Speter (MPT_STATE(data) != MPT_DB_STATE_FAULT)) || 31817308Speter ( MPT_DB_IS_IN_USE(data) )) { 31917308Speter mpt_prt(mpt, "handshake aborted due to invalid doorbell state"); 32017308Speter mpt_print_db(data); 32117308Speter return(EBUSY); 32217308Speter } 3233626Swollman 3243626Swollman /* We move things in 32 bit chunks */ 3253626Swollman len = (len + 3) >> 2; 3263626Swollman data32 = cmd; 3273626Swollman 3283626Swollman /* Clear any left over pending doorbell interupts */ 3293626Swollman if (MPT_DB_INTR(mpt_rd_intr(mpt))) 3303626Swollman mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 3313626Swollman 3323626Swollman /* 3333626Swollman * Tell the handshake reg. we are going to send a command 3347059Sroberto * and how long it is going to be. 3353626Swollman */ 3363626Swollman data = (MPI_FUNCTION_HANDSHAKE << MPI_DOORBELL_FUNCTION_SHIFT) | 3373626Swollman (len << MPI_DOORBELL_ADD_DWORDS_SHIFT); 3383626Swollman mpt_write(mpt, MPT_OFFSET_DOORBELL, data); 3393626Swollman 3403626Swollman /* Wait for the chip to notice */ 3413626Swollman if (mpt_wait_db_int(mpt) != MPT_OK) { 34217308Speter mpt_prt(mpt, "mpt_send_handshake_cmd timeout1"); 34317308Speter return ETIMEDOUT; 34417308Speter } 34517308Speter 34617308Speter /* Clear the interrupt */ 34717308Speter mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 34817308Speter 34917308Speter if (mpt_wait_db_ack(mpt) != MPT_OK) { 35017308Speter mpt_prt(mpt, "mpt_send_handshake_cmd timeout2"); 35117308Speter return ETIMEDOUT; 3523626Swollman } 35317308Speter 35417308Speter /* Send the command */ 35517308Speter for (i = 0; i < len; i++) { 35617308Speter mpt_write(mpt, MPT_OFFSET_DOORBELL, *data32++); 35717308Speter if (mpt_wait_db_ack(mpt) != MPT_OK) { 35817308Speter mpt_prt(mpt, 35917308Speter "mpt_send_handshake_cmd timeout! index = %d", i); 36017308Speter return ETIMEDOUT; 36117308Speter } 3622061Sjkh } 36316663Sjkh return MPT_OK; 3642061Sjkh} 36517308Speter 36617308Speter/* Get the response from the handshake register */ 36717308Speterint 36817308Spetermpt_recv_handshake_reply(mpt_softc_t *mpt, size_t reply_len, void *reply) 36917308Speter{ 37017308Speter int left, reply_left; 37117820Sjkh u_int16_t *data16; 37217308Speter MSG_DEFAULT_REPLY *hdr; 37317820Sjkh 37417308Speter /* We move things out in 16 bit chunks */ 37517820Sjkh reply_len >>= 1; 37617467Speter data16 = (u_int16_t *)reply; 37717308Speter 37817308Speter hdr = (MSG_DEFAULT_REPLY *)reply; 37917308Speter 38017308Speter /* Get first word */ 38117308Speter if (mpt_wait_db_int(mpt) != MPT_OK) { 38217308Speter mpt_prt(mpt, "mpt_recv_handshake_cmd timeout1"); 38317308Speter return ETIMEDOUT; 38417308Speter } 38517820Sjkh *data16++ = mpt_read(mpt, MPT_OFFSET_DOORBELL) & MPT_DB_DATA_MASK; 38617820Sjkh mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 38717308Speter 38817308Speter /* Get Second Word */ 38917308Speter if (mpt_wait_db_int(mpt) != MPT_OK) { 39017308Speter mpt_prt(mpt, "mpt_recv_handshake_cmd timeout2"); 39114119Speter return ETIMEDOUT; 3922061Sjkh } 3937130Srgrimes *data16++ = mpt_read(mpt, MPT_OFFSET_DOORBELL) & MPT_DB_DATA_MASK; 3947130Srgrimes mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 3957130Srgrimes 3962061Sjkh /* With the second word, we can now look at the length */ 39717962Speter if (mpt->verbose > 1 && ((reply_len >> 1) != hdr->MsgLength)) { 3982061Sjkh mpt_prt(mpt, "reply length does not match message length: " 39917308Speter "got 0x%02x, expected 0x%02x", 4002685Srgrimes hdr->MsgLength << 2, reply_len << 1); 4016927Snate } 4022685Srgrimes 4033518Sache /* Get rest of the reply; but don't overflow the provided buffer */ 4043197Scsgr left = (hdr->MsgLength << 1) - 2; 4053197Scsgr reply_left = reply_len - 2; 40612166Sjkh while (left--) { 40712485Sjkh u_int16_t datum; 4083197Scsgr 4092061Sjkh if (mpt_wait_db_int(mpt) != MPT_OK) { 4102061Sjkh mpt_prt(mpt, "mpt_recv_handshake_cmd timeout3"); 4112061Sjkh return ETIMEDOUT; 41216786Snate } 4132883Sphk datum = mpt_read(mpt, MPT_OFFSET_DOORBELL); 41417308Speter 41517308Speter if (reply_left-- > 0) 4167281Srgrimes *data16++ = datum & MPT_DB_DATA_MASK; 4173242Spaul 4183242Spaul mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 4197171Sats } 4202061Sjkh 4213213Spst /* One more wait & clear at the end */ 42217308Speter if (mpt_wait_db_int(mpt) != MPT_OK) { 42317308Speter mpt_prt(mpt, "mpt_recv_handshake_cmd timeout4"); 4245749Swollman return ETIMEDOUT; 4255772Swollman } 42617308Speter mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); 42717308Speter 4282061Sjkh if ((hdr->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 42917308Speter if (mpt->verbose > 1) 43017308Speter mpt_print_reply(hdr); 43117308Speter return (MPT_FAIL | hdr->IOCStatus); 4325366Snate } 43317820Sjkh 43417467Speter return (0); 43517820Sjkh} 43617308Speter 43717820Sjkhstatic int 43817308Spetermpt_get_iocfacts(mpt_softc_t *mpt, MSG_IOC_FACTS_REPLY *freplp) 43917820Sjkh{ 44017308Speter MSG_IOC_FACTS f_req; 44117820Sjkh int error; 44217308Speter 44317820Sjkh bzero(&f_req, sizeof f_req); 44417308Speter f_req.Function = MPI_FUNCTION_IOC_FACTS; 44517820Sjkh f_req.MsgContext = 0x12071942; 44617308Speter error = mpt_send_handshake_cmd(mpt, sizeof f_req, &f_req); 4475728Swollman if (error) 44817820Sjkh return(error); 44917308Speter error = mpt_recv_handshake_reply(mpt, sizeof (*freplp), freplp); 45018392Speter return (error); 45118392Speter} 45218392Speter 45318392Speterstatic int 45418392Spetermpt_get_portfacts(mpt_softc_t *mpt, MSG_PORT_FACTS_REPLY *freplp) 45518392Speter{ 4565366Snate MSG_PORT_FACTS f_req; 45717308Speter int error; 45817308Speter 45917308Speter /* XXX: Only getting PORT FACTS for Port 0 */ 4602061Sjkh bzero(&f_req, sizeof f_req); 4618295Srgrimes f_req.Function = MPI_FUNCTION_PORT_FACTS; 46217820Sjkh f_req.MsgContext = 0x12071943; 46317308Speter error = mpt_send_handshake_cmd(mpt, sizeof f_req, &f_req); 4648295Srgrimes if (error) 4658489Srgrimes return(error); 46617820Sjkh error = mpt_recv_handshake_reply(mpt, sizeof (*freplp), freplp); 46717308Speter return (error); 4688489Srgrimes} 4698489Srgrimes 47017820Sjkh/* 47117308Speter * Send the initialization request. This is where we specify how many 4728489Srgrimes * SCSI busses and how many devices per bus we wish to emulate. 47317308Speter * This is also the command that specifies the max size of the reply 47417820Sjkh * frames from the IOC that we will be allocating. 47517308Speter */ 47617308Speterstatic int 4778295Srgrimesmpt_send_ioc_init(mpt_softc_t *mpt, u_int32_t who) 47817820Sjkh{ 47917308Speter int error = 0; 4808295Srgrimes MSG_IOC_INIT init; 4812160Scsgr MSG_IOC_INIT_REPLY reply; 48217820Sjkh 48317308Speter bzero(&init, sizeof init); 4842160Scsgr init.WhoInit = who; 4852279Spaul init.Function = MPI_FUNCTION_IOC_INIT; 48617820Sjkh if (mpt->is_fc) { 48717308Speter init.MaxDevices = 255; 4882279Spaul } else { 48917234Sjraynard init.MaxDevices = 16; 49017820Sjkh } 49117308Speter init.MaxBuses = 1; 49211772Snate init.ReplyFrameSize = MPT_REPLY_SIZE; 4933197Scsgr init.MsgContext = 0x12071941; 49417820Sjkh 49517308Speter if ((error = mpt_send_handshake_cmd(mpt, sizeof init, &init)) != 0) { 4962626Scsgr return(error); 4978304Srgrimes } 49817820Sjkh 49917308Speter error = mpt_recv_handshake_reply(mpt, sizeof reply, &reply); 5008304Srgrimes return (error); 5012061Sjkh} 50217308Speter 50317308Speter 50417308Speter/* 50517308Speter * Utiltity routine to read configuration headers and pages 50611806Sphk */ 50717820Sjkh 50817308Speterstatic int 50918204Sjfiebermpt_read_cfg_header(mpt_softc_t *, int, int, int, CONFIG_PAGE_HEADER *); 51018204Sjfieber 51117820Sjkhstatic int 51217308Spetermpt_read_cfg_header(mpt_softc_t *mpt, int PageType, int PageNumber, 51317820Sjkh int PageAddress, CONFIG_PAGE_HEADER *rslt) 51417308Speter{ 51517820Sjkh int count; 51617308Speter request_t *req; 51718362Sjkh MSG_CONFIG *cfgp; 51818362Sjkh MSG_CONFIG_REPLY *reply; 5192061Sjkh 5201594Srgrimes req = mpt_get_request(mpt); 521 522 cfgp = req->req_vbuf; 523 bzero(cfgp, sizeof *cfgp); 524 525 cfgp->Action = MPI_CONFIG_ACTION_PAGE_HEADER; 526 cfgp->Function = MPI_FUNCTION_CONFIG; 527 cfgp->Header.PageNumber = (U8) PageNumber; 528 cfgp->Header.PageType = (U8) PageType; 529 cfgp->PageAddress = PageAddress; 530 MPI_pSGE_SET_FLAGS(((SGE_SIMPLE32 *) &cfgp->PageBufferSGE), 531 (MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | 532 MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_LIST)); 533 cfgp->MsgContext = req->index | 0x80000000; 534 535 mpt_check_doorbell(mpt); 536 mpt_send_cmd(mpt, req); 537 count = 0; 538 do { 539 DELAY(500); 540 mpt_intr(mpt); 541 if (++count == 1000) { 542 mpt_prt(mpt, "read_cfg_header timed out"); 543 return (-1); 544 } 545 } while (req->debug == REQ_ON_CHIP); 546 547 reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence); 548 if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 549 mpt_prt(mpt, "mpt_read_cfg_header: Config Info Status %x", 550 reply->IOCStatus); 551 mpt_free_reply(mpt, (req->sequence << 1)); 552 return (-1); 553 } 554 bcopy(&reply->Header, rslt, sizeof (CONFIG_PAGE_HEADER)); 555 mpt_free_reply(mpt, (req->sequence << 1)); 556 mpt_free_request(mpt, req); 557 return (0); 558} 559 560#define CFG_DATA_OFF 128 561 562int 563mpt_read_cfg_page(mpt_softc_t *mpt, int PageAddress, CONFIG_PAGE_HEADER *hdr) 564{ 565 int count; 566 request_t *req; 567 SGE_SIMPLE32 *se; 568 MSG_CONFIG *cfgp; 569 size_t amt; 570 MSG_CONFIG_REPLY *reply; 571 572 req = mpt_get_request(mpt); 573 574 cfgp = req->req_vbuf; 575 bzero(cfgp, MPT_REQUEST_AREA); 576 cfgp->Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 577 cfgp->Function = MPI_FUNCTION_CONFIG; 578 cfgp->Header = *hdr; 579 amt = (cfgp->Header.PageLength * sizeof (u_int32_t)); 580 cfgp->Header.PageType &= MPI_CONFIG_PAGETYPE_MASK; 581 cfgp->PageAddress = PageAddress; 582 se = (SGE_SIMPLE32 *) &cfgp->PageBufferSGE; 583 se->Address = req->req_pbuf + CFG_DATA_OFF; 584 MPI_pSGE_SET_LENGTH(se, amt); 585 MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT | 586 MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | 587 MPI_SGE_FLAGS_END_OF_LIST)); 588 589 cfgp->MsgContext = req->index | 0x80000000; 590 591 mpt_check_doorbell(mpt); 592 mpt_send_cmd(mpt, req); 593 count = 0; 594 do { 595 DELAY(500); 596 mpt_intr(mpt); 597 if (++count == 1000) { 598 mpt_prt(mpt, "read_cfg_page timed out"); 599 return (-1); 600 } 601 } while (req->debug == REQ_ON_CHIP); 602 603 reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence); 604 if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 605 mpt_prt(mpt, "mpt_read_cfg_page: Config Info Status %x", 606 reply->IOCStatus); 607 mpt_free_reply(mpt, (req->sequence << 1)); 608 return (-1); 609 } 610 mpt_free_reply(mpt, (req->sequence << 1)); 611 bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap, 612 BUS_DMASYNC_POSTREAD); 613 if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 614 cfgp->Header.PageNumber == 0) { 615 amt = sizeof (CONFIG_PAGE_SCSI_PORT_0); 616 } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 617 cfgp->Header.PageNumber == 1) { 618 amt = sizeof (CONFIG_PAGE_SCSI_PORT_1); 619 } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 620 cfgp->Header.PageNumber == 2) { 621 amt = sizeof (CONFIG_PAGE_SCSI_PORT_2); 622 } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && 623 cfgp->Header.PageNumber == 0) { 624 amt = sizeof (CONFIG_PAGE_SCSI_DEVICE_0); 625 } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && 626 cfgp->Header.PageNumber == 1) { 627 amt = sizeof (CONFIG_PAGE_SCSI_DEVICE_1); 628 } 629 bcopy(((caddr_t)req->req_vbuf)+CFG_DATA_OFF, hdr, amt); 630 mpt_free_request(mpt, req); 631 return (0); 632} 633 634int 635mpt_write_cfg_page(mpt_softc_t *mpt, int PageAddress, CONFIG_PAGE_HEADER *hdr) 636{ 637 int count, hdr_attr; 638 request_t *req; 639 SGE_SIMPLE32 *se; 640 MSG_CONFIG *cfgp; 641 size_t amt; 642 MSG_CONFIG_REPLY *reply; 643 644 req = mpt_get_request(mpt); 645 646 cfgp = req->req_vbuf; 647 bzero(cfgp, sizeof *cfgp); 648 649 hdr_attr = hdr->PageType & MPI_CONFIG_PAGEATTR_MASK; 650 if (hdr_attr != MPI_CONFIG_PAGEATTR_CHANGEABLE && 651 hdr_attr != MPI_CONFIG_PAGEATTR_PERSISTENT) { 652 mpt_prt(mpt, "page type 0x%x not changeable", 653 hdr->PageType & MPI_CONFIG_PAGETYPE_MASK); 654 return (-1); 655 } 656 hdr->PageType &= MPI_CONFIG_PAGETYPE_MASK; 657 658 cfgp->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; 659 cfgp->Function = MPI_FUNCTION_CONFIG; 660 cfgp->Header = *hdr; 661 amt = (cfgp->Header.PageLength * sizeof (u_int32_t)); 662 cfgp->PageAddress = PageAddress; 663 664 se = (SGE_SIMPLE32 *) &cfgp->PageBufferSGE; 665 se->Address = req->req_pbuf + CFG_DATA_OFF; 666 MPI_pSGE_SET_LENGTH(se, amt); 667 MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT | 668 MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | 669 MPI_SGE_FLAGS_END_OF_LIST | MPI_SGE_FLAGS_HOST_TO_IOC)); 670 671 cfgp->MsgContext = req->index | 0x80000000; 672 673 if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 674 cfgp->Header.PageNumber == 0) { 675 amt = sizeof (CONFIG_PAGE_SCSI_PORT_0); 676 } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 677 cfgp->Header.PageNumber == 1) { 678 amt = sizeof (CONFIG_PAGE_SCSI_PORT_1); 679 } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_PORT && 680 cfgp->Header.PageNumber == 2) { 681 amt = sizeof (CONFIG_PAGE_SCSI_PORT_2); 682 } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && 683 cfgp->Header.PageNumber == 0) { 684 amt = sizeof (CONFIG_PAGE_SCSI_DEVICE_0); 685 } else if (cfgp->Header.PageType == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && 686 cfgp->Header.PageNumber == 1) { 687 amt = sizeof (CONFIG_PAGE_SCSI_DEVICE_1); 688 } 689 bcopy(hdr, ((caddr_t)req->req_vbuf)+CFG_DATA_OFF, amt); 690 /* Restore stripped out attributes */ 691 hdr->PageType |= hdr_attr; 692 693 mpt_check_doorbell(mpt); 694 mpt_send_cmd(mpt, req); 695 count = 0; 696 do { 697 DELAY(500); 698 mpt_intr(mpt); 699 if (++count == 1000) { 700 hdr->PageType |= hdr_attr; 701 mpt_prt(mpt, "mpt_write_cfg_page timed out"); 702 return (-1); 703 } 704 } while (req->debug == REQ_ON_CHIP); 705 706 reply = (MSG_CONFIG_REPLY *) MPT_REPLY_PTOV(mpt, req->sequence); 707 if ((reply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 708 mpt_prt(mpt, "mpt_write_cfg_page: Config Info Status %x", 709 reply->IOCStatus); 710 mpt_free_reply(mpt, (req->sequence << 1)); 711 return (-1); 712 } 713 mpt_free_reply(mpt, (req->sequence << 1)); 714 715 mpt_free_request(mpt, req); 716 return (0); 717} 718 719/* 720 * Read SCSI configuration information 721 */ 722static int 723mpt_read_config_info_spi(mpt_softc_t *mpt) 724{ 725 int rv, i; 726 727 rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 0, 728 0, &mpt->mpt_port_page0.Header); 729 if (rv) { 730 return (-1); 731 } 732 if (mpt->verbose > 1) { 733 mpt_prt(mpt, "SPI Port Page 0 Header: %x %x %x %x", 734 mpt->mpt_port_page0.Header.PageVersion, 735 mpt->mpt_port_page0.Header.PageLength, 736 mpt->mpt_port_page0.Header.PageNumber, 737 mpt->mpt_port_page0.Header.PageType); 738 } 739 740 rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 1, 741 0, &mpt->mpt_port_page1.Header); 742 if (rv) { 743 return (-1); 744 } 745 if (mpt->verbose > 1) { 746 mpt_prt(mpt, "SPI Port Page 1 Header: %x %x %x %x", 747 mpt->mpt_port_page1.Header.PageVersion, 748 mpt->mpt_port_page1.Header.PageLength, 749 mpt->mpt_port_page1.Header.PageNumber, 750 mpt->mpt_port_page1.Header.PageType); 751 } 752 753 rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 2, 754 0, &mpt->mpt_port_page2.Header); 755 if (rv) { 756 return (-1); 757 } 758 759 if (mpt->verbose > 1) { 760 mpt_prt(mpt, "SPI Port Page 2 Header: %x %x %x %x", 761 mpt->mpt_port_page1.Header.PageVersion, 762 mpt->mpt_port_page1.Header.PageLength, 763 mpt->mpt_port_page1.Header.PageNumber, 764 mpt->mpt_port_page1.Header.PageType); 765 } 766 767 for (i = 0; i < 16; i++) { 768 rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE, 769 0, i, &mpt->mpt_dev_page0[i].Header); 770 if (rv) { 771 return (-1); 772 } 773 if (mpt->verbose > 1) { 774 mpt_prt(mpt, 775 "SPI Target %d Device Page 0 Header: %x %x %x %x", 776 i, mpt->mpt_dev_page0[i].Header.PageVersion, 777 mpt->mpt_dev_page0[i].Header.PageLength, 778 mpt->mpt_dev_page0[i].Header.PageNumber, 779 mpt->mpt_dev_page0[i].Header.PageType); 780 } 781 782 rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE, 783 1, i, &mpt->mpt_dev_page1[i].Header); 784 if (rv) { 785 return (-1); 786 } 787 if (mpt->verbose > 1) { 788 mpt_prt(mpt, 789 "SPI Target %d Device Page 1 Header: %x %x %x %x", 790 i, mpt->mpt_dev_page1[i].Header.PageVersion, 791 mpt->mpt_dev_page1[i].Header.PageLength, 792 mpt->mpt_dev_page1[i].Header.PageNumber, 793 mpt->mpt_dev_page1[i].Header.PageType); 794 } 795 } 796 797 /* 798 * At this point, we don't *have* to fail. As long as we have 799 * valid config header information, we can (barely) lurch 800 * along. 801 */ 802 803 rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page0.Header); 804 if (rv) { 805 mpt_prt(mpt, "failed to read SPI Port Page 0"); 806 } else if (mpt->verbose > 1) { 807 mpt_prt(mpt, 808 "SPI Port Page 0: Capabilities %x PhysicalInterface %x", 809 mpt->mpt_port_page0.Capabilities, 810 mpt->mpt_port_page0.PhysicalInterface); 811 } 812 813 rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page1.Header); 814 if (rv) { 815 mpt_prt(mpt, "failed to read SPI Port Page 1"); 816 } else if (mpt->verbose > 1) { 817 mpt_prt(mpt, 818 "SPI Port Page 1: Configuration %x OnBusTimerValue %x", 819 mpt->mpt_port_page1.Configuration, 820 mpt->mpt_port_page1.OnBusTimerValue); 821 } 822 823 rv = mpt_read_cfg_page(mpt, 0, &mpt->mpt_port_page2.Header); 824 if (rv) { 825 mpt_prt(mpt, "failed to read SPI Port Page 2"); 826 } else if (mpt->verbose > 1) { 827 mpt_prt(mpt, 828 "SPI Port Page 2: Flags %x Settings %x", 829 mpt->mpt_port_page2.PortFlags, 830 mpt->mpt_port_page2.PortSettings); 831 for (i = 0; i < 16; i++) { 832 mpt_prt(mpt, 833 "SPI Port Page 2 Tgt %d: timo %x SF %x Flags %x", 834 i, mpt->mpt_port_page2.DeviceSettings[i].Timeout, 835 mpt->mpt_port_page2.DeviceSettings[i].SyncFactor, 836 mpt->mpt_port_page2.DeviceSettings[i].DeviceFlags); 837 } 838 } 839 840 for (i = 0; i < 16; i++) { 841 rv = mpt_read_cfg_page(mpt, i, &mpt->mpt_dev_page0[i].Header); 842 if (rv) { 843 mpt_prt(mpt, "cannot read SPI Tgt %d Device Page 0", i); 844 continue; 845 } 846 if (mpt->verbose > 1) { 847 mpt_prt(mpt, 848 "SPI Tgt %d Page 0: NParms %x Information %x", 849 i, mpt->mpt_dev_page0[i].NegotiatedParameters, 850 mpt->mpt_dev_page0[i].Information); 851 } 852 rv = mpt_read_cfg_page(mpt, i, &mpt->mpt_dev_page1[i].Header); 853 if (rv) { 854 mpt_prt(mpt, "cannot read SPI Tgt %d Device Page 1", i); 855 continue; 856 } 857 if (mpt->verbose > 1) { 858 mpt_prt(mpt, 859 "SPI Tgt %d Page 1: RParms %x Configuration %x", 860 i, mpt->mpt_dev_page1[i].RequestedParameters, 861 mpt->mpt_dev_page1[i].Configuration); 862 } 863 } 864 return (0); 865} 866 867/* 868 * Validate SPI configuration information. 869 * 870 * In particular, validate SPI Port Page 1. 871 */ 872static int 873mpt_set_initial_config_spi(mpt_softc_t *mpt) 874{ 875 int i, pp1val = ((1 << mpt->mpt_ini_id) << 16) | mpt->mpt_ini_id; 876 877 mpt->mpt_disc_enable = 0xff; 878 mpt->mpt_tag_enable = 0; 879 880 if (mpt->mpt_port_page1.Configuration != pp1val) { 881 CONFIG_PAGE_SCSI_PORT_1 tmp; 882 mpt_prt(mpt, 883 "SPI Port Page 1 Config value bad (%x)- should be %x", 884 mpt->mpt_port_page1.Configuration, pp1val); 885 tmp = mpt->mpt_port_page1; 886 tmp.Configuration = pp1val; 887 if (mpt_write_cfg_page(mpt, 0, &tmp.Header)) { 888 return (-1); 889 } 890 if (mpt_read_cfg_page(mpt, 0, &tmp.Header)) { 891 return (-1); 892 } 893 if (tmp.Configuration != pp1val) { 894 mpt_prt(mpt, 895 "failed to reset SPI Port Page 1 Config value"); 896 return (-1); 897 } 898 mpt->mpt_port_page1 = tmp; 899 } 900 901 for (i = 0; i < 16; i++) { 902 CONFIG_PAGE_SCSI_DEVICE_1 tmp; 903 tmp = mpt->mpt_dev_page1[i]; 904 tmp.RequestedParameters = 0; 905 tmp.Configuration = 0; 906 if (mpt->verbose > 1) { 907 mpt_prt(mpt, 908 "Set Tgt %d SPI DevicePage 1 values to %x 0 %x", 909 i, tmp.RequestedParameters, tmp.Configuration); 910 } 911 if (mpt_write_cfg_page(mpt, i, &tmp.Header)) { 912 return (-1); 913 } 914 if (mpt_read_cfg_page(mpt, i, &tmp.Header)) { 915 return (-1); 916 } 917 mpt->mpt_dev_page1[i] = tmp; 918 if (mpt->verbose > 1) { 919 mpt_prt(mpt, 920 "SPI Tgt %d Page 1: RParm %x Configuration %x", i, 921 mpt->mpt_dev_page1[i].RequestedParameters, 922 mpt->mpt_dev_page1[i].Configuration); 923 } 924 } 925 return (0); 926} 927 928/* 929 * Enable IOC port 930 */ 931static int 932mpt_send_port_enable(mpt_softc_t *mpt, int port) 933{ 934 int count; 935 request_t *req; 936 MSG_PORT_ENABLE *enable_req; 937 938 req = mpt_get_request(mpt); 939 940 enable_req = req->req_vbuf; 941 bzero(enable_req, sizeof *enable_req); 942 943 enable_req->Function = MPI_FUNCTION_PORT_ENABLE; 944 enable_req->MsgContext = req->index | 0x80000000; 945 enable_req->PortNumber = port; 946 947 mpt_check_doorbell(mpt); 948 if (mpt->verbose > 1) { 949 mpt_prt(mpt, "enabling port %d", port); 950 } 951 mpt_send_cmd(mpt, req); 952 953 count = 0; 954 do { 955 DELAY(500); 956 mpt_intr(mpt); 957 if (++count == 100000) { 958 mpt_prt(mpt, "port enable timed out"); 959 return (-1); 960 } 961 } while (req->debug == REQ_ON_CHIP); 962 mpt_free_request(mpt, req); 963 return (0); 964} 965 966/* 967 * Enable/Disable asynchronous event reporting. 968 * 969 * NB: this is the first command we send via shared memory 970 * instead of the handshake register. 971 */ 972static int 973mpt_send_event_request(mpt_softc_t *mpt, int onoff) 974{ 975 request_t *req; 976 MSG_EVENT_NOTIFY *enable_req; 977 978 req = mpt_get_request(mpt); 979 980 enable_req = req->req_vbuf; 981 bzero(enable_req, sizeof *enable_req); 982 983 enable_req->Function = MPI_FUNCTION_EVENT_NOTIFICATION; 984 enable_req->MsgContext = req->index | 0x80000000; 985 enable_req->Switch = onoff; 986 987 mpt_check_doorbell(mpt); 988 if (mpt->verbose > 1) { 989 mpt_prt(mpt, "%sabling async events", onoff? "en" : "dis"); 990 } 991 mpt_send_cmd(mpt, req); 992 993 return (0); 994} 995 996/* 997 * Un-mask the interupts on the chip. 998 */ 999void 1000mpt_enable_ints(mpt_softc_t *mpt) 1001{ 1002 /* Unmask every thing except door bell int */ 1003 mpt_write(mpt, MPT_OFFSET_INTR_MASK, MPT_INTR_DB_MASK); 1004} 1005 1006/* 1007 * Mask the interupts on the chip. 1008 */ 1009void 1010mpt_disable_ints(mpt_softc_t *mpt) 1011{ 1012 /* Mask all interrupts */ 1013 mpt_write(mpt, MPT_OFFSET_INTR_MASK, 1014 MPT_INTR_REPLY_MASK | MPT_INTR_DB_MASK); 1015} 1016 1017/* (Re)Initialize the chip for use */ 1018int 1019mpt_init(mpt_softc_t *mpt, u_int32_t who) 1020{ 1021 int try; 1022 MSG_IOC_FACTS_REPLY facts; 1023 MSG_PORT_FACTS_REPLY pfp; 1024 u_int32_t pptr; 1025 int val; 1026 1027 /* Put all request buffers (back) on the free list */ 1028 SLIST_INIT(&mpt->request_free_list); 1029 for (val = 0; val < MPT_MAX_REQUESTS(mpt); val++) { 1030 mpt_free_request(mpt, &mpt->request_pool[val]); 1031 } 1032 1033 if (mpt->verbose > 1) { 1034 mpt_prt(mpt, "doorbell req = %s", 1035 mpt_ioc_diag(mpt_read(mpt, MPT_OFFSET_DOORBELL))); 1036 } 1037 1038 /* 1039 * Start by making sure we're not at FAULT or RESET state 1040 */ 1041 switch (mpt_rd_db(mpt) & MPT_DB_STATE_MASK) { 1042 case MPT_DB_STATE_RESET: 1043 case MPT_DB_STATE_FAULT: 1044 if (mpt_reset(mpt) != MPT_OK) { 1045 return (EIO); 1046 } 1047 default: 1048 break; 1049 } 1050 1051 for (try = 0; try < MPT_MAX_TRYS; try++) { 1052 /* 1053 * No need to reset if the IOC is already in the READY state. 1054 * 1055 * Force reset if initialization failed previously. 1056 * Note that a hard_reset of the second channel of a '929 1057 * will stop operation of the first channel. Hopefully, if the 1058 * first channel is ok, the second will not require a hard 1059 * reset. 1060 */ 1061 if ((mpt_rd_db(mpt) & MPT_DB_STATE_MASK) != 1062 MPT_DB_STATE_READY) { 1063 if (mpt_reset(mpt) != MPT_OK) { 1064 DELAY(10000); 1065 continue; 1066 } 1067 } 1068 1069 if (mpt_get_iocfacts(mpt, &facts) != MPT_OK) { 1070 mpt_prt(mpt, "mpt_get_iocfacts failed"); 1071 continue; 1072 } 1073 1074 if (mpt->verbose > 1) { 1075 mpt_prt(mpt, 1076 "IOCFACTS: GlobalCredits=%d BlockSize=%u " 1077 "Request Frame Size %u\n", facts.GlobalCredits, 1078 facts.BlockSize, facts.RequestFrameSize); 1079 } 1080 mpt->mpt_global_credits = facts.GlobalCredits; 1081 mpt->request_frame_size = facts.RequestFrameSize; 1082 1083 if (mpt_get_portfacts(mpt, &pfp) != MPT_OK) { 1084 mpt_prt(mpt, "mpt_get_portfacts failed"); 1085 continue; 1086 } 1087 1088 if (mpt->verbose > 1) { 1089 mpt_prt(mpt, 1090 "PORTFACTS: Type %x PFlags %x IID %d MaxDev %d\n", 1091 pfp.PortType, pfp.ProtocolFlags, pfp.PortSCSIID, 1092 pfp.MaxDevices); 1093 } 1094 1095 if (pfp.PortType != MPI_PORTFACTS_PORTTYPE_SCSI && 1096 pfp.PortType != MPI_PORTFACTS_PORTTYPE_FC) { 1097 mpt_prt(mpt, "Unsupported Port Type (%x)", 1098 pfp.PortType); 1099 return (ENXIO); 1100 } 1101 if (!(pfp.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)) { 1102 mpt_prt(mpt, "initiator role unsupported"); 1103 return (ENXIO); 1104 } 1105 if (pfp.PortType == MPI_PORTFACTS_PORTTYPE_FC) { 1106 mpt->is_fc = 1; 1107 } else { 1108 mpt->is_fc = 0; 1109 } 1110 mpt->mpt_ini_id = pfp.PortSCSIID; 1111 1112 if (mpt_send_ioc_init(mpt, who) != MPT_OK) { 1113 mpt_prt(mpt, "mpt_send_ioc_init failed"); 1114 continue; 1115 } 1116 1117 if (mpt->verbose > 1) { 1118 mpt_prt(mpt, "mpt_send_ioc_init ok"); 1119 } 1120 1121 if (mpt_wait_state(mpt, MPT_DB_STATE_RUNNING) != MPT_OK) { 1122 mpt_prt(mpt, "IOC failed to go to run state"); 1123 continue; 1124 } 1125 if (mpt->verbose > 1) { 1126 mpt_prt(mpt, "IOC now at RUNSTATE"); 1127 } 1128 1129 /* 1130 * Give it reply buffers 1131 * 1132 * Do *not* except global credits. 1133 */ 1134 for (val = 0, pptr = mpt->reply_phys; 1135 (pptr + MPT_REPLY_SIZE) < (mpt->reply_phys + PAGE_SIZE); 1136 pptr += MPT_REPLY_SIZE) { 1137 mpt_free_reply(mpt, pptr); 1138 if (++val == mpt->mpt_global_credits - 1) 1139 break; 1140 } 1141 1142 /* 1143 * Enable asynchronous event reporting 1144 */ 1145 mpt_send_event_request(mpt, 1); 1146 1147 1148 /* 1149 * Read set up initial configuration information 1150 * (SPI only for now) 1151 */ 1152 1153 if (mpt->is_fc == 0) { 1154 if (mpt_read_config_info_spi(mpt)) { 1155 return (EIO); 1156 } 1157 if (mpt_set_initial_config_spi(mpt)) { 1158 return (EIO); 1159 } 1160 } 1161 1162 /* 1163 * Now enable the port 1164 */ 1165 if (mpt_send_port_enable(mpt, 0) != MPT_OK) { 1166 mpt_prt(mpt, "failed to enable port 0"); 1167 continue; 1168 } 1169 1170 if (mpt->verbose > 1) { 1171 mpt_prt(mpt, "enabled port 0"); 1172 } 1173 1174 /* Everything worked */ 1175 break; 1176 } 1177 1178 if (try >= MPT_MAX_TRYS) { 1179 mpt_prt(mpt, "failed to initialize IOC"); 1180 return (EIO); 1181 } 1182 1183 if (mpt->verbose > 1) { 1184 mpt_prt(mpt, "enabling interrupts"); 1185 } 1186 1187 mpt_enable_ints(mpt); 1188 return (0); 1189} 1190