mpr.c revision 303029
1265236Sken/*- 2265236Sken * Copyright (c) 2009 Yahoo! Inc. 3283661Sslm * Copyright (c) 2011-2015 LSI Corp. 4299265Sslm * Copyright (c) 2013-2016 Avago Technologies 5265236Sken * All rights reserved. 6265236Sken * 7265236Sken * Redistribution and use in source and binary forms, with or without 8265236Sken * modification, are permitted provided that the following conditions 9265236Sken * are met: 10265236Sken * 1. Redistributions of source code must retain the above copyright 11265236Sken * notice, this list of conditions and the following disclaimer. 12265236Sken * 2. Redistributions in binary form must reproduce the above copyright 13265236Sken * notice, this list of conditions and the following disclaimer in the 14265236Sken * documentation and/or other materials provided with the distribution. 15265236Sken * 16265236Sken * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17265236Sken * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18265236Sken * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19265236Sken * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20265236Sken * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21265236Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22265236Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23265236Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24265236Sken * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25265236Sken * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26265236Sken * SUCH DAMAGE. 27265236Sken * 28283661Sslm * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD 29283661Sslm * 30265236Sken */ 31265236Sken 32265236Sken#include <sys/cdefs.h> 33265236Sken__FBSDID("$FreeBSD: stable/11/sys/dev/mpr/mpr.c 303029 2016-07-19 16:46:27Z slm $"); 34265236Sken 35283661Sslm/* Communications core for Avago Technologies (LSI) MPT3 */ 36265236Sken 37265236Sken/* TODO Move headers to mprvar */ 38265236Sken#include <sys/types.h> 39265236Sken#include <sys/param.h> 40265236Sken#include <sys/systm.h> 41265236Sken#include <sys/kernel.h> 42265236Sken#include <sys/selinfo.h> 43265236Sken#include <sys/lock.h> 44265236Sken#include <sys/mutex.h> 45265236Sken#include <sys/module.h> 46265236Sken#include <sys/bus.h> 47265236Sken#include <sys/conf.h> 48265236Sken#include <sys/bio.h> 49265236Sken#include <sys/malloc.h> 50265236Sken#include <sys/uio.h> 51265236Sken#include <sys/sysctl.h> 52265236Sken#include <sys/queue.h> 53265236Sken#include <sys/kthread.h> 54265236Sken#include <sys/taskqueue.h> 55265236Sken#include <sys/endian.h> 56265236Sken#include <sys/eventhandler.h> 57265236Sken 58265236Sken#include <machine/bus.h> 59265236Sken#include <machine/resource.h> 60265236Sken#include <sys/rman.h> 61265236Sken#include <sys/proc.h> 62265236Sken 63265236Sken#include <dev/pci/pcivar.h> 64265236Sken 65265236Sken#include <cam/cam.h> 66265236Sken#include <cam/scsi/scsi_all.h> 67265236Sken 68265236Sken#include <dev/mpr/mpi/mpi2_type.h> 69265236Sken#include <dev/mpr/mpi/mpi2.h> 70265236Sken#include <dev/mpr/mpi/mpi2_ioc.h> 71265236Sken#include <dev/mpr/mpi/mpi2_sas.h> 72265236Sken#include <dev/mpr/mpi/mpi2_cnfg.h> 73265236Sken#include <dev/mpr/mpi/mpi2_init.h> 74265236Sken#include <dev/mpr/mpi/mpi2_tool.h> 75265236Sken#include <dev/mpr/mpr_ioctl.h> 76265236Sken#include <dev/mpr/mprvar.h> 77265236Sken#include <dev/mpr/mpr_table.h> 78265236Sken 79265236Skenstatic int mpr_diag_reset(struct mpr_softc *sc, int sleep_flag); 80265236Skenstatic int mpr_init_queues(struct mpr_softc *sc); 81265236Skenstatic int mpr_message_unit_reset(struct mpr_softc *sc, int sleep_flag); 82265236Skenstatic int mpr_transition_operational(struct mpr_softc *sc); 83265236Skenstatic int mpr_iocfacts_allocate(struct mpr_softc *sc, uint8_t attaching); 84265236Skenstatic void mpr_iocfacts_free(struct mpr_softc *sc); 85265236Skenstatic void mpr_startup(void *arg); 86265236Skenstatic int mpr_send_iocinit(struct mpr_softc *sc); 87265236Skenstatic int mpr_alloc_queues(struct mpr_softc *sc); 88265236Skenstatic int mpr_alloc_replies(struct mpr_softc *sc); 89265236Skenstatic int mpr_alloc_requests(struct mpr_softc *sc); 90265236Skenstatic int mpr_attach_log(struct mpr_softc *sc); 91265236Skenstatic __inline void mpr_complete_command(struct mpr_softc *sc, 92265236Sken struct mpr_command *cm); 93265236Skenstatic void mpr_dispatch_event(struct mpr_softc *sc, uintptr_t data, 94265236Sken MPI2_EVENT_NOTIFICATION_REPLY *reply); 95299265Sslmstatic void mpr_config_complete(struct mpr_softc *sc, struct mpr_command *cm); 96265236Skenstatic void mpr_periodic(void *); 97265236Skenstatic int mpr_reregister_events(struct mpr_softc *sc); 98299265Sslmstatic void mpr_enqueue_request(struct mpr_softc *sc, struct mpr_command *cm); 99299265Sslmstatic int mpr_get_iocfacts(struct mpr_softc *sc, MPI2_IOC_FACTS_REPLY *facts); 100265236Skenstatic int mpr_wait_db_ack(struct mpr_softc *sc, int timeout, int sleep_flag); 101265236SkenSYSCTL_NODE(_hw, OID_AUTO, mpr, CTLFLAG_RD, 0, "MPR Driver Parameters"); 102265236Sken 103265236SkenMALLOC_DEFINE(M_MPR, "mpr", "mpr driver memory"); 104265236Sken 105265236Sken/* 106265236Sken * Do a "Diagnostic Reset" aka a hard reset. This should get the chip out of 107265236Sken * any state and back to its initialization state machine. 108265236Sken */ 109265236Skenstatic char mpt2_reset_magic[] = { 0x00, 0x0f, 0x04, 0x0b, 0x02, 0x07, 0x0d }; 110265236Sken 111265236Sken/* 112265236Sken * Added this union to smoothly convert le64toh cm->cm_desc.Words. 113265236Sken * Compiler only supports unint64_t to be passed as an argument. 114265236Sken * Otherwise it will through this error: 115265236Sken * "aggregate value used where an integer was expected" 116265236Sken */ 117265236Skentypedef union _reply_descriptor { 118265236Sken u64 word; 119265236Sken struct { 120265236Sken u32 low; 121265236Sken u32 high; 122265236Sken } u; 123265236Sken}reply_descriptor,address_descriptor; 124265236Sken 125265236Sken/* Rate limit chain-fail messages to 1 per minute */ 126265236Skenstatic struct timeval mpr_chainfail_interval = { 60, 0 }; 127265236Sken 128265236Sken/* 129265236Sken * sleep_flag can be either CAN_SLEEP or NO_SLEEP. 130265236Sken * If this function is called from process context, it can sleep 131265236Sken * and there is no harm to sleep, in case if this fuction is called 132265236Sken * from Interrupt handler, we can not sleep and need NO_SLEEP flag set. 133265236Sken * based on sleep flags driver will call either msleep, pause or DELAY. 134265236Sken * msleep and pause are of same variant, but pause is used when mpr_mtx 135265236Sken * is not hold by driver. 136265236Sken */ 137265236Skenstatic int 138265236Skenmpr_diag_reset(struct mpr_softc *sc,int sleep_flag) 139265236Sken{ 140265236Sken uint32_t reg; 141265236Sken int i, error, tries = 0; 142265236Sken uint8_t first_wait_done = FALSE; 143265236Sken 144265236Sken mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); 145265236Sken 146265236Sken /* Clear any pending interrupts */ 147265236Sken mpr_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); 148265236Sken 149265236Sken /* 150265236Sken * Force NO_SLEEP for threads prohibited to sleep 151265236Sken * e.a Thread from interrupt handler are prohibited to sleep. 152265236Sken */ 153265236Sken#if __FreeBSD_version >= 1000029 154265236Sken if (curthread->td_no_sleeping) 155265236Sken#else //__FreeBSD_version < 1000029 156265236Sken if (curthread->td_pflags & TDP_NOSLEEPING) 157265236Sken#endif //__FreeBSD_version >= 1000029 158265236Sken sleep_flag = NO_SLEEP; 159265236Sken 160265236Sken /* Push the magic sequence */ 161265236Sken error = ETIMEDOUT; 162265236Sken while (tries++ < 20) { 163265236Sken for (i = 0; i < sizeof(mpt2_reset_magic); i++) 164265236Sken mpr_regwrite(sc, MPI2_WRITE_SEQUENCE_OFFSET, 165265236Sken mpt2_reset_magic[i]); 166265236Sken 167265236Sken /* wait 100 msec */ 168265236Sken if (mtx_owned(&sc->mpr_mtx) && sleep_flag == CAN_SLEEP) 169265236Sken msleep(&sc->msleep_fake_chan, &sc->mpr_mtx, 0, 170265236Sken "mprdiag", hz/10); 171265236Sken else if (sleep_flag == CAN_SLEEP) 172265236Sken pause("mprdiag", hz/10); 173265236Sken else 174265236Sken DELAY(100 * 1000); 175265236Sken 176265236Sken reg = mpr_regread(sc, MPI2_HOST_DIAGNOSTIC_OFFSET); 177265236Sken if (reg & MPI2_DIAG_DIAG_WRITE_ENABLE) { 178265236Sken error = 0; 179265236Sken break; 180265236Sken } 181265236Sken } 182265236Sken if (error) 183265236Sken return (error); 184265236Sken 185265236Sken /* Send the actual reset. XXX need to refresh the reg? */ 186265236Sken mpr_regwrite(sc, MPI2_HOST_DIAGNOSTIC_OFFSET, 187265236Sken reg | MPI2_DIAG_RESET_ADAPTER); 188265236Sken 189265236Sken /* Wait up to 300 seconds in 50ms intervals */ 190265236Sken error = ETIMEDOUT; 191265236Sken for (i = 0; i < 6000; i++) { 192265236Sken /* 193265236Sken * Wait 50 msec. If this is the first time through, wait 256 194265236Sken * msec to satisfy Diag Reset timing requirements. 195265236Sken */ 196265236Sken if (first_wait_done) { 197265236Sken if (mtx_owned(&sc->mpr_mtx) && sleep_flag == CAN_SLEEP) 198265236Sken msleep(&sc->msleep_fake_chan, &sc->mpr_mtx, 0, 199265236Sken "mprdiag", hz/20); 200265236Sken else if (sleep_flag == CAN_SLEEP) 201265236Sken pause("mprdiag", hz/20); 202265236Sken else 203265236Sken DELAY(50 * 1000); 204265236Sken } else { 205265236Sken DELAY(256 * 1000); 206265236Sken first_wait_done = TRUE; 207265236Sken } 208265236Sken /* 209265236Sken * Check for the RESET_ADAPTER bit to be cleared first, then 210265236Sken * wait for the RESET state to be cleared, which takes a little 211265236Sken * longer. 212265236Sken */ 213265236Sken reg = mpr_regread(sc, MPI2_HOST_DIAGNOSTIC_OFFSET); 214265236Sken if (reg & MPI2_DIAG_RESET_ADAPTER) { 215265236Sken continue; 216265236Sken } 217265236Sken reg = mpr_regread(sc, MPI2_DOORBELL_OFFSET); 218265236Sken if ((reg & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_RESET) { 219265236Sken error = 0; 220265236Sken break; 221265236Sken } 222265236Sken } 223265236Sken if (error) 224265236Sken return (error); 225265236Sken 226265236Sken mpr_regwrite(sc, MPI2_WRITE_SEQUENCE_OFFSET, 0x0); 227265236Sken 228265236Sken return (0); 229265236Sken} 230265236Sken 231265236Skenstatic int 232265236Skenmpr_message_unit_reset(struct mpr_softc *sc, int sleep_flag) 233265236Sken{ 234265236Sken 235265236Sken MPR_FUNCTRACE(sc); 236265236Sken 237265236Sken mpr_regwrite(sc, MPI2_DOORBELL_OFFSET, 238265236Sken MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET << 239265236Sken MPI2_DOORBELL_FUNCTION_SHIFT); 240265236Sken 241265236Sken if (mpr_wait_db_ack(sc, 5, sleep_flag) != 0) { 242265236Sken mpr_dprint(sc, MPR_FAULT, "Doorbell handshake failed : <%s>\n", 243265236Sken __func__); 244265236Sken return (ETIMEDOUT); 245265236Sken } 246265236Sken 247265236Sken return (0); 248265236Sken} 249265236Sken 250265236Skenstatic int 251265236Skenmpr_transition_ready(struct mpr_softc *sc) 252265236Sken{ 253265236Sken uint32_t reg, state; 254265236Sken int error, tries = 0; 255265236Sken int sleep_flags; 256265236Sken 257265236Sken MPR_FUNCTRACE(sc); 258265236Sken /* If we are in attach call, do not sleep */ 259265236Sken sleep_flags = (sc->mpr_flags & MPR_FLAGS_ATTACH_DONE) 260265236Sken ? CAN_SLEEP : NO_SLEEP; 261265236Sken 262265236Sken error = 0; 263265236Sken while (tries++ < 1200) { 264265236Sken reg = mpr_regread(sc, MPI2_DOORBELL_OFFSET); 265265236Sken mpr_dprint(sc, MPR_INIT, "Doorbell= 0x%x\n", reg); 266265236Sken 267265236Sken /* 268265236Sken * Ensure the IOC is ready to talk. If it's not, try 269265236Sken * resetting it. 270265236Sken */ 271265236Sken if (reg & MPI2_DOORBELL_USED) { 272265236Sken mpr_diag_reset(sc, sleep_flags); 273265236Sken DELAY(50000); 274265236Sken continue; 275265236Sken } 276265236Sken 277265236Sken /* Is the adapter owned by another peer? */ 278265236Sken if ((reg & MPI2_DOORBELL_WHO_INIT_MASK) == 279265236Sken (MPI2_WHOINIT_PCI_PEER << MPI2_DOORBELL_WHO_INIT_SHIFT)) { 280265236Sken device_printf(sc->mpr_dev, "IOC is under the control " 281265236Sken "of another peer host, aborting initialization.\n"); 282265236Sken return (ENXIO); 283265236Sken } 284265236Sken 285265236Sken state = reg & MPI2_IOC_STATE_MASK; 286265236Sken if (state == MPI2_IOC_STATE_READY) { 287265236Sken /* Ready to go! */ 288265236Sken error = 0; 289265236Sken break; 290265236Sken } else if (state == MPI2_IOC_STATE_FAULT) { 291265236Sken mpr_dprint(sc, MPR_FAULT, "IOC in fault state 0x%x\n", 292265236Sken state & MPI2_DOORBELL_FAULT_CODE_MASK); 293265236Sken mpr_diag_reset(sc, sleep_flags); 294265236Sken } else if (state == MPI2_IOC_STATE_OPERATIONAL) { 295265236Sken /* Need to take ownership */ 296265236Sken mpr_message_unit_reset(sc, sleep_flags); 297265236Sken } else if (state == MPI2_IOC_STATE_RESET) { 298265236Sken /* Wait a bit, IOC might be in transition */ 299265236Sken mpr_dprint(sc, MPR_FAULT, 300265236Sken "IOC in unexpected reset state\n"); 301265236Sken } else { 302265236Sken mpr_dprint(sc, MPR_FAULT, 303265236Sken "IOC in unknown state 0x%x\n", state); 304265236Sken error = EINVAL; 305265236Sken break; 306265236Sken } 307265236Sken 308265236Sken /* Wait 50ms for things to settle down. */ 309265236Sken DELAY(50000); 310265236Sken } 311265236Sken 312265236Sken if (error) 313265236Sken device_printf(sc->mpr_dev, "Cannot transition IOC to ready\n"); 314265236Sken 315265236Sken return (error); 316265236Sken} 317265236Sken 318265236Skenstatic int 319265236Skenmpr_transition_operational(struct mpr_softc *sc) 320265236Sken{ 321265236Sken uint32_t reg, state; 322265236Sken int error; 323265236Sken 324265236Sken MPR_FUNCTRACE(sc); 325265236Sken 326265236Sken error = 0; 327265236Sken reg = mpr_regread(sc, MPI2_DOORBELL_OFFSET); 328265236Sken mpr_dprint(sc, MPR_INIT, "Doorbell= 0x%x\n", reg); 329265236Sken 330265236Sken state = reg & MPI2_IOC_STATE_MASK; 331265236Sken if (state != MPI2_IOC_STATE_READY) { 332265236Sken if ((error = mpr_transition_ready(sc)) != 0) { 333265236Sken mpr_dprint(sc, MPR_FAULT, 334265236Sken "%s failed to transition ready\n", __func__); 335265236Sken return (error); 336265236Sken } 337265236Sken } 338265236Sken 339265236Sken error = mpr_send_iocinit(sc); 340265236Sken return (error); 341265236Sken} 342265236Sken 343265236Sken/* 344265236Sken * This is called during attach and when re-initializing due to a Diag Reset. 345265236Sken * IOC Facts is used to allocate many of the structures needed by the driver. 346265236Sken * If called from attach, de-allocation is not required because the driver has 347265236Sken * not allocated any structures yet, but if called from a Diag Reset, previously 348265236Sken * allocated structures based on IOC Facts will need to be freed and re- 349265236Sken * allocated bases on the latest IOC Facts. 350265236Sken */ 351265236Skenstatic int 352265236Skenmpr_iocfacts_allocate(struct mpr_softc *sc, uint8_t attaching) 353265236Sken{ 354283661Sslm int error; 355265236Sken Mpi2IOCFactsReply_t saved_facts; 356265236Sken uint8_t saved_mode, reallocating; 357265236Sken 358265236Sken mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); 359265236Sken 360265236Sken /* Save old IOC Facts and then only reallocate if Facts have changed */ 361265236Sken if (!attaching) { 362265236Sken bcopy(sc->facts, &saved_facts, sizeof(MPI2_IOC_FACTS_REPLY)); 363265236Sken } 364265236Sken 365265236Sken /* 366265236Sken * Get IOC Facts. In all cases throughout this function, panic if doing 367265236Sken * a re-initialization and only return the error if attaching so the OS 368265236Sken * can handle it. 369265236Sken */ 370265236Sken if ((error = mpr_get_iocfacts(sc, sc->facts)) != 0) { 371265236Sken if (attaching) { 372265236Sken mpr_dprint(sc, MPR_FAULT, "%s failed to get IOC Facts " 373265236Sken "with error %d\n", __func__, error); 374265236Sken return (error); 375265236Sken } else { 376265236Sken panic("%s failed to get IOC Facts with error %d\n", 377265236Sken __func__, error); 378265236Sken } 379265236Sken } 380265236Sken 381265236Sken mpr_print_iocfacts(sc, sc->facts); 382265236Sken 383265236Sken snprintf(sc->fw_version, sizeof(sc->fw_version), 384265236Sken "%02d.%02d.%02d.%02d", 385265236Sken sc->facts->FWVersion.Struct.Major, 386265236Sken sc->facts->FWVersion.Struct.Minor, 387265236Sken sc->facts->FWVersion.Struct.Unit, 388265236Sken sc->facts->FWVersion.Struct.Dev); 389265236Sken 390265236Sken mpr_printf(sc, "Firmware: %s, Driver: %s\n", sc->fw_version, 391265236Sken MPR_DRIVER_VERSION); 392265236Sken mpr_printf(sc, "IOCCapabilities: %b\n", sc->facts->IOCCapabilities, 393265236Sken "\20" "\3ScsiTaskFull" "\4DiagTrace" "\5SnapBuf" "\6ExtBuf" 394265236Sken "\7EEDP" "\10BiDirTarg" "\11Multicast" "\14TransRetry" "\15IR" 395265236Sken "\16EventReplay" "\17RaidAccel" "\20MSIXIndex" "\21HostDisc"); 396265236Sken 397265236Sken /* 398265236Sken * If the chip doesn't support event replay then a hard reset will be 399265236Sken * required to trigger a full discovery. Do the reset here then 400265236Sken * retransition to Ready. A hard reset might have already been done, 401265236Sken * but it doesn't hurt to do it again. Only do this if attaching, not 402265236Sken * for a Diag Reset. 403265236Sken */ 404265236Sken if (attaching) { 405265236Sken if ((sc->facts->IOCCapabilities & 406265236Sken MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY) == 0) { 407265236Sken mpr_diag_reset(sc, NO_SLEEP); 408265236Sken if ((error = mpr_transition_ready(sc)) != 0) { 409265236Sken mpr_dprint(sc, MPR_FAULT, "%s failed to " 410265236Sken "transition to ready with error %d\n", 411265236Sken __func__, error); 412265236Sken return (error); 413265236Sken } 414265236Sken } 415265236Sken } 416265236Sken 417265236Sken /* 418265236Sken * Set flag if IR Firmware is loaded. If the RAID Capability has 419265236Sken * changed from the previous IOC Facts, log a warning, but only if 420265236Sken * checking this after a Diag Reset and not during attach. 421265236Sken */ 422265236Sken saved_mode = sc->ir_firmware; 423265236Sken if (sc->facts->IOCCapabilities & 424265236Sken MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) 425265236Sken sc->ir_firmware = 1; 426265236Sken if (!attaching) { 427265236Sken if (sc->ir_firmware != saved_mode) { 428265236Sken mpr_dprint(sc, MPR_FAULT, "%s new IR/IT mode in IOC " 429265236Sken "Facts does not match previous mode\n", __func__); 430265236Sken } 431265236Sken } 432265236Sken 433265236Sken /* Only deallocate and reallocate if relevant IOC Facts have changed */ 434265236Sken reallocating = FALSE; 435265236Sken if ((!attaching) && 436265236Sken ((saved_facts.MsgVersion != sc->facts->MsgVersion) || 437265236Sken (saved_facts.HeaderVersion != sc->facts->HeaderVersion) || 438265236Sken (saved_facts.MaxChainDepth != sc->facts->MaxChainDepth) || 439265236Sken (saved_facts.RequestCredit != sc->facts->RequestCredit) || 440265236Sken (saved_facts.ProductID != sc->facts->ProductID) || 441265236Sken (saved_facts.IOCCapabilities != sc->facts->IOCCapabilities) || 442265236Sken (saved_facts.IOCRequestFrameSize != 443265236Sken sc->facts->IOCRequestFrameSize) || 444299266Sslm (saved_facts.IOCMaxChainSegmentSize != 445299266Sslm sc->facts->IOCMaxChainSegmentSize) || 446265236Sken (saved_facts.MaxTargets != sc->facts->MaxTargets) || 447265236Sken (saved_facts.MaxSasExpanders != sc->facts->MaxSasExpanders) || 448265236Sken (saved_facts.MaxEnclosures != sc->facts->MaxEnclosures) || 449265236Sken (saved_facts.HighPriorityCredit != sc->facts->HighPriorityCredit) || 450265236Sken (saved_facts.MaxReplyDescriptorPostQueueDepth != 451265236Sken sc->facts->MaxReplyDescriptorPostQueueDepth) || 452265236Sken (saved_facts.ReplyFrameSize != sc->facts->ReplyFrameSize) || 453265236Sken (saved_facts.MaxVolumes != sc->facts->MaxVolumes) || 454265236Sken (saved_facts.MaxPersistentEntries != 455265236Sken sc->facts->MaxPersistentEntries))) { 456265236Sken reallocating = TRUE; 457265236Sken } 458265236Sken 459265236Sken /* 460265236Sken * Some things should be done if attaching or re-allocating after a Diag 461265236Sken * Reset, but are not needed after a Diag Reset if the FW has not 462265236Sken * changed. 463265236Sken */ 464265236Sken if (attaching || reallocating) { 465265236Sken /* 466265236Sken * Check if controller supports FW diag buffers and set flag to 467265236Sken * enable each type. 468265236Sken */ 469265236Sken if (sc->facts->IOCCapabilities & 470265236Sken MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) 471265236Sken sc->fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_TRACE]. 472265236Sken enabled = TRUE; 473265236Sken if (sc->facts->IOCCapabilities & 474265236Sken MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) 475265236Sken sc->fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_SNAPSHOT]. 476265236Sken enabled = TRUE; 477265236Sken if (sc->facts->IOCCapabilities & 478265236Sken MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) 479265236Sken sc->fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_EXTENDED]. 480265236Sken enabled = TRUE; 481265236Sken 482265236Sken /* 483265236Sken * Set flag if EEDP is supported and if TLR is supported. 484265236Sken */ 485265236Sken if (sc->facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_EEDP) 486265236Sken sc->eedp_enabled = TRUE; 487265236Sken if (sc->facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR) 488265236Sken sc->control_TLR = TRUE; 489265236Sken 490265236Sken /* 491265236Sken * Size the queues. Since the reply queues always need one free 492265236Sken * entry, we'll just deduct one reply message here. 493265236Sken */ 494265236Sken sc->num_reqs = MIN(MPR_REQ_FRAMES, sc->facts->RequestCredit); 495265236Sken sc->num_replies = MIN(MPR_REPLY_FRAMES + MPR_EVT_REPLY_FRAMES, 496265236Sken sc->facts->MaxReplyDescriptorPostQueueDepth) - 1; 497265236Sken 498265236Sken /* 499265236Sken * Initialize all Tail Queues 500265236Sken */ 501265236Sken TAILQ_INIT(&sc->req_list); 502265236Sken TAILQ_INIT(&sc->high_priority_req_list); 503265236Sken TAILQ_INIT(&sc->chain_list); 504265236Sken TAILQ_INIT(&sc->tm_list); 505265236Sken } 506265236Sken 507265236Sken /* 508265236Sken * If doing a Diag Reset and the FW is significantly different 509265236Sken * (reallocating will be set above in IOC Facts comparison), then all 510265236Sken * buffers based on the IOC Facts will need to be freed before they are 511265236Sken * reallocated. 512265236Sken */ 513265236Sken if (reallocating) { 514265236Sken mpr_iocfacts_free(sc); 515283661Sslm mprsas_realloc_targets(sc, saved_facts.MaxTargets); 516265236Sken } 517265236Sken 518265236Sken /* 519265236Sken * Any deallocation has been completed. Now start reallocating 520265236Sken * if needed. Will only need to reallocate if attaching or if the new 521265236Sken * IOC Facts are different from the previous IOC Facts after a Diag 522265236Sken * Reset. Targets have already been allocated above if needed. 523265236Sken */ 524265236Sken if (attaching || reallocating) { 525265236Sken if (((error = mpr_alloc_queues(sc)) != 0) || 526265236Sken ((error = mpr_alloc_replies(sc)) != 0) || 527265236Sken ((error = mpr_alloc_requests(sc)) != 0)) { 528265236Sken if (attaching ) { 529265236Sken mpr_dprint(sc, MPR_FAULT, "%s failed to alloc " 530265236Sken "queues with error %d\n", __func__, error); 531265236Sken mpr_free(sc); 532265236Sken return (error); 533265236Sken } else { 534265236Sken panic("%s failed to alloc queues with error " 535265236Sken "%d\n", __func__, error); 536265236Sken } 537265236Sken } 538265236Sken } 539265236Sken 540265236Sken /* Always initialize the queues */ 541265236Sken bzero(sc->free_queue, sc->fqdepth * 4); 542265236Sken mpr_init_queues(sc); 543265236Sken 544265236Sken /* 545265236Sken * Always get the chip out of the reset state, but only panic if not 546265236Sken * attaching. If attaching and there is an error, that is handled by 547265236Sken * the OS. 548265236Sken */ 549265236Sken error = mpr_transition_operational(sc); 550265236Sken if (error != 0) { 551265236Sken if (attaching) { 552299265Sslm mpr_printf(sc, "%s failed to transition to operational " 553299265Sslm "with error %d\n", __func__, error); 554265236Sken mpr_free(sc); 555265236Sken return (error); 556265236Sken } else { 557265236Sken panic("%s failed to transition to operational with " 558265236Sken "error %d\n", __func__, error); 559265236Sken } 560265236Sken } 561265236Sken 562265236Sken /* 563265236Sken * Finish the queue initialization. 564265236Sken * These are set here instead of in mpr_init_queues() because the 565265236Sken * IOC resets these values during the state transition in 566265236Sken * mpr_transition_operational(). The free index is set to 1 567265236Sken * because the corresponding index in the IOC is set to 0, and the 568265236Sken * IOC treats the queues as full if both are set to the same value. 569265236Sken * Hence the reason that the queue can't hold all of the possible 570265236Sken * replies. 571265236Sken */ 572265236Sken sc->replypostindex = 0; 573265236Sken mpr_regwrite(sc, MPI2_REPLY_FREE_HOST_INDEX_OFFSET, sc->replyfreeindex); 574265236Sken mpr_regwrite(sc, MPI2_REPLY_POST_HOST_INDEX_OFFSET, 0); 575265236Sken 576265236Sken /* 577265236Sken * Attach the subsystems so they can prepare their event masks. 578265236Sken */ 579265236Sken /* XXX Should be dynamic so that IM/IR and user modules can attach */ 580265236Sken if (attaching) { 581265236Sken if (((error = mpr_attach_log(sc)) != 0) || 582265236Sken ((error = mpr_attach_sas(sc)) != 0) || 583265236Sken ((error = mpr_attach_user(sc)) != 0)) { 584265236Sken mpr_printf(sc, "%s failed to attach all subsystems: " 585265236Sken "error %d\n", __func__, error); 586265236Sken mpr_free(sc); 587265236Sken return (error); 588265236Sken } 589265236Sken 590265236Sken if ((error = mpr_pci_setup_interrupts(sc)) != 0) { 591265236Sken mpr_printf(sc, "%s failed to setup interrupts\n", 592265236Sken __func__); 593265236Sken mpr_free(sc); 594265236Sken return (error); 595265236Sken } 596265236Sken } 597265236Sken 598265236Sken return (error); 599265236Sken} 600265236Sken 601265236Sken/* 602265236Sken * This is called if memory is being free (during detach for example) and when 603265236Sken * buffers need to be reallocated due to a Diag Reset. 604265236Sken */ 605265236Skenstatic void 606265236Skenmpr_iocfacts_free(struct mpr_softc *sc) 607265236Sken{ 608265236Sken struct mpr_command *cm; 609265236Sken int i; 610265236Sken 611265236Sken mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); 612265236Sken 613265236Sken if (sc->free_busaddr != 0) 614265236Sken bus_dmamap_unload(sc->queues_dmat, sc->queues_map); 615265236Sken if (sc->free_queue != NULL) 616265236Sken bus_dmamem_free(sc->queues_dmat, sc->free_queue, 617265236Sken sc->queues_map); 618265236Sken if (sc->queues_dmat != NULL) 619265236Sken bus_dma_tag_destroy(sc->queues_dmat); 620265236Sken 621265236Sken if (sc->chain_busaddr != 0) 622265236Sken bus_dmamap_unload(sc->chain_dmat, sc->chain_map); 623265236Sken if (sc->chain_frames != NULL) 624265236Sken bus_dmamem_free(sc->chain_dmat, sc->chain_frames, 625265236Sken sc->chain_map); 626265236Sken if (sc->chain_dmat != NULL) 627265236Sken bus_dma_tag_destroy(sc->chain_dmat); 628265236Sken 629265236Sken if (sc->sense_busaddr != 0) 630265236Sken bus_dmamap_unload(sc->sense_dmat, sc->sense_map); 631265236Sken if (sc->sense_frames != NULL) 632265236Sken bus_dmamem_free(sc->sense_dmat, sc->sense_frames, 633265236Sken sc->sense_map); 634265236Sken if (sc->sense_dmat != NULL) 635265236Sken bus_dma_tag_destroy(sc->sense_dmat); 636265236Sken 637265236Sken if (sc->reply_busaddr != 0) 638265236Sken bus_dmamap_unload(sc->reply_dmat, sc->reply_map); 639265236Sken if (sc->reply_frames != NULL) 640265236Sken bus_dmamem_free(sc->reply_dmat, sc->reply_frames, 641265236Sken sc->reply_map); 642265236Sken if (sc->reply_dmat != NULL) 643265236Sken bus_dma_tag_destroy(sc->reply_dmat); 644265236Sken 645265236Sken if (sc->req_busaddr != 0) 646265236Sken bus_dmamap_unload(sc->req_dmat, sc->req_map); 647265236Sken if (sc->req_frames != NULL) 648265236Sken bus_dmamem_free(sc->req_dmat, sc->req_frames, sc->req_map); 649265236Sken if (sc->req_dmat != NULL) 650265236Sken bus_dma_tag_destroy(sc->req_dmat); 651265236Sken 652265236Sken if (sc->chains != NULL) 653265236Sken free(sc->chains, M_MPR); 654265236Sken if (sc->commands != NULL) { 655265236Sken for (i = 1; i < sc->num_reqs; i++) { 656265236Sken cm = &sc->commands[i]; 657265236Sken bus_dmamap_destroy(sc->buffer_dmat, cm->cm_dmamap); 658265236Sken } 659265236Sken free(sc->commands, M_MPR); 660265236Sken } 661265236Sken if (sc->buffer_dmat != NULL) 662265236Sken bus_dma_tag_destroy(sc->buffer_dmat); 663265236Sken} 664265236Sken 665265236Sken/* 666265236Sken * The terms diag reset and hard reset are used interchangeably in the MPI 667265236Sken * docs to mean resetting the controller chip. In this code diag reset 668265236Sken * cleans everything up, and the hard reset function just sends the reset 669265236Sken * sequence to the chip. This should probably be refactored so that every 670265236Sken * subsystem gets a reset notification of some sort, and can clean up 671265236Sken * appropriately. 672265236Sken */ 673265236Skenint 674265236Skenmpr_reinit(struct mpr_softc *sc) 675265236Sken{ 676265236Sken int error; 677265236Sken struct mprsas_softc *sassc; 678265236Sken 679265236Sken sassc = sc->sassc; 680265236Sken 681265236Sken MPR_FUNCTRACE(sc); 682265236Sken 683265236Sken mtx_assert(&sc->mpr_mtx, MA_OWNED); 684265236Sken 685265236Sken if (sc->mpr_flags & MPR_FLAGS_DIAGRESET) { 686265236Sken mpr_dprint(sc, MPR_INIT, "%s reset already in progress\n", 687299265Sslm __func__); 688265236Sken return 0; 689265236Sken } 690265236Sken 691265236Sken mpr_dprint(sc, MPR_INFO, "Reinitializing controller,\n"); 692265236Sken /* make sure the completion callbacks can recognize they're getting 693265236Sken * a NULL cm_reply due to a reset. 694265236Sken */ 695265236Sken sc->mpr_flags |= MPR_FLAGS_DIAGRESET; 696265236Sken 697265236Sken /* 698265236Sken * Mask interrupts here. 699265236Sken */ 700265236Sken mpr_dprint(sc, MPR_INIT, "%s mask interrupts\n", __func__); 701265236Sken mpr_mask_intr(sc); 702265236Sken 703265236Sken error = mpr_diag_reset(sc, CAN_SLEEP); 704265236Sken if (error != 0) { 705265236Sken panic("%s hard reset failed with error %d\n", __func__, error); 706265236Sken } 707265236Sken 708265236Sken /* Restore the PCI state, including the MSI-X registers */ 709265236Sken mpr_pci_restore(sc); 710265236Sken 711265236Sken /* Give the I/O subsystem special priority to get itself prepared */ 712265236Sken mprsas_handle_reinit(sc); 713265236Sken 714265236Sken /* 715265236Sken * Get IOC Facts and allocate all structures based on this information. 716265236Sken * The attach function will also call mpr_iocfacts_allocate at startup. 717265236Sken * If relevant values have changed in IOC Facts, this function will free 718265236Sken * all of the memory based on IOC Facts and reallocate that memory. 719265236Sken */ 720265236Sken if ((error = mpr_iocfacts_allocate(sc, FALSE)) != 0) { 721265236Sken panic("%s IOC Facts based allocation failed with error %d\n", 722265236Sken __func__, error); 723265236Sken } 724265236Sken 725265236Sken /* 726265236Sken * Mapping structures will be re-allocated after getting IOC Page8, so 727265236Sken * free these structures here. 728265236Sken */ 729265236Sken mpr_mapping_exit(sc); 730265236Sken 731265236Sken /* 732265236Sken * The static page function currently read is IOC Page8. Others can be 733265236Sken * added in future. It's possible that the values in IOC Page8 have 734265236Sken * changed after a Diag Reset due to user modification, so always read 735265236Sken * these. Interrupts are masked, so unmask them before getting config 736265236Sken * pages. 737265236Sken */ 738265236Sken mpr_unmask_intr(sc); 739265236Sken sc->mpr_flags &= ~MPR_FLAGS_DIAGRESET; 740265236Sken mpr_base_static_config_pages(sc); 741265236Sken 742265236Sken /* 743265236Sken * Some mapping info is based in IOC Page8 data, so re-initialize the 744265236Sken * mapping tables. 745265236Sken */ 746265236Sken mpr_mapping_initialize(sc); 747265236Sken 748265236Sken /* 749265236Sken * Restart will reload the event masks clobbered by the reset, and 750265236Sken * then enable the port. 751265236Sken */ 752265236Sken mpr_reregister_events(sc); 753265236Sken 754265236Sken /* the end of discovery will release the simq, so we're done. */ 755265236Sken mpr_dprint(sc, MPR_INFO, "%s finished sc %p post %u free %u\n", 756265236Sken __func__, sc, sc->replypostindex, sc->replyfreeindex); 757283661Sslm mprsas_release_simq_reinit(sassc); 758265236Sken 759265236Sken return 0; 760265236Sken} 761265236Sken 762265236Sken/* Wait for the chip to ACK a word that we've put into its FIFO 763265236Sken * Wait for <timeout> seconds. In single loop wait for busy loop 764265236Sken * for 500 microseconds. 765265236Sken * Total is [ 0.5 * (2000 * <timeout>) ] in miliseconds. 766265236Sken * */ 767265236Skenstatic int 768265236Skenmpr_wait_db_ack(struct mpr_softc *sc, int timeout, int sleep_flag) 769265236Sken{ 770265236Sken u32 cntdn, count; 771265236Sken u32 int_status; 772265236Sken u32 doorbell; 773265236Sken 774265236Sken count = 0; 775265236Sken cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout; 776265236Sken do { 777265236Sken int_status = mpr_regread(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET); 778265236Sken if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) { 779265236Sken mpr_dprint(sc, MPR_INIT, "%s: successful count(%d), " 780265236Sken "timeout(%d)\n", __func__, count, timeout); 781265236Sken return 0; 782265236Sken } else if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) { 783265236Sken doorbell = mpr_regread(sc, MPI2_DOORBELL_OFFSET); 784265236Sken if ((doorbell & MPI2_IOC_STATE_MASK) == 785265236Sken MPI2_IOC_STATE_FAULT) { 786265236Sken mpr_dprint(sc, MPR_FAULT, 787265236Sken "fault_state(0x%04x)!\n", doorbell); 788265236Sken return (EFAULT); 789265236Sken } 790265236Sken } else if (int_status == 0xFFFFFFFF) 791265236Sken goto out; 792265236Sken 793265236Sken /* 794265236Sken * If it can sleep, sleep for 1 milisecond, else busy loop for 795265236Sken * 0.5 milisecond 796265236Sken */ 797265236Sken if (mtx_owned(&sc->mpr_mtx) && sleep_flag == CAN_SLEEP) 798283661Sslm msleep(&sc->msleep_fake_chan, &sc->mpr_mtx, 0, "mprdba", 799283661Sslm hz/1000); 800265236Sken else if (sleep_flag == CAN_SLEEP) 801265236Sken pause("mprdba", hz/1000); 802265236Sken else 803265236Sken DELAY(500); 804265236Sken count++; 805265236Sken } while (--cntdn); 806265236Sken 807265236Sken out: 808265236Sken mpr_dprint(sc, MPR_FAULT, "%s: failed due to timeout count(%d), " 809265236Sken "int_status(%x)!\n", __func__, count, int_status); 810265236Sken return (ETIMEDOUT); 811265236Sken} 812265236Sken 813265236Sken/* Wait for the chip to signal that the next word in its FIFO can be fetched */ 814265236Skenstatic int 815265236Skenmpr_wait_db_int(struct mpr_softc *sc) 816265236Sken{ 817265236Sken int retry; 818265236Sken 819265236Sken for (retry = 0; retry < MPR_DB_MAX_WAIT; retry++) { 820265236Sken if ((mpr_regread(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET) & 821265236Sken MPI2_HIS_IOC2SYS_DB_STATUS) != 0) 822265236Sken return (0); 823265236Sken DELAY(2000); 824265236Sken } 825265236Sken return (ETIMEDOUT); 826265236Sken} 827265236Sken 828265236Sken/* Step through the synchronous command state machine, i.e. "Doorbell mode" */ 829265236Skenstatic int 830265236Skenmpr_request_sync(struct mpr_softc *sc, void *req, MPI2_DEFAULT_REPLY *reply, 831265236Sken int req_sz, int reply_sz, int timeout) 832265236Sken{ 833265236Sken uint32_t *data32; 834265236Sken uint16_t *data16; 835265236Sken int i, count, ioc_sz, residual; 836265236Sken int sleep_flags = CAN_SLEEP; 837265236Sken 838265236Sken#if __FreeBSD_version >= 1000029 839265236Sken if (curthread->td_no_sleeping) 840265236Sken#else //__FreeBSD_version < 1000029 841265236Sken if (curthread->td_pflags & TDP_NOSLEEPING) 842265236Sken#endif //__FreeBSD_version >= 1000029 843265236Sken sleep_flags = NO_SLEEP; 844265236Sken 845265236Sken /* Step 1 */ 846265236Sken mpr_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); 847265236Sken 848265236Sken /* Step 2 */ 849265236Sken if (mpr_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_USED) 850265236Sken return (EBUSY); 851265236Sken 852265236Sken /* Step 3 853265236Sken * Announce that a message is coming through the doorbell. Messages 854265236Sken * are pushed at 32bit words, so round up if needed. 855265236Sken */ 856265236Sken count = (req_sz + 3) / 4; 857265236Sken mpr_regwrite(sc, MPI2_DOORBELL_OFFSET, 858265236Sken (MPI2_FUNCTION_HANDSHAKE << MPI2_DOORBELL_FUNCTION_SHIFT) | 859265236Sken (count << MPI2_DOORBELL_ADD_DWORDS_SHIFT)); 860265236Sken 861265236Sken /* Step 4 */ 862265236Sken if (mpr_wait_db_int(sc) || 863265236Sken (mpr_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_USED) == 0) { 864265236Sken mpr_dprint(sc, MPR_FAULT, "Doorbell failed to activate\n"); 865265236Sken return (ENXIO); 866265236Sken } 867265236Sken mpr_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); 868265236Sken if (mpr_wait_db_ack(sc, 5, sleep_flags) != 0) { 869265236Sken mpr_dprint(sc, MPR_FAULT, "Doorbell handshake failed\n"); 870265236Sken return (ENXIO); 871265236Sken } 872265236Sken 873265236Sken /* Step 5 */ 874265236Sken /* Clock out the message data synchronously in 32-bit dwords*/ 875265236Sken data32 = (uint32_t *)req; 876265236Sken for (i = 0; i < count; i++) { 877265236Sken mpr_regwrite(sc, MPI2_DOORBELL_OFFSET, htole32(data32[i])); 878265236Sken if (mpr_wait_db_ack(sc, 5, sleep_flags) != 0) { 879265236Sken mpr_dprint(sc, MPR_FAULT, 880265236Sken "Timeout while writing doorbell\n"); 881265236Sken return (ENXIO); 882265236Sken } 883265236Sken } 884265236Sken 885265236Sken /* Step 6 */ 886265236Sken /* Clock in the reply in 16-bit words. The total length of the 887265236Sken * message is always in the 4th byte, so clock out the first 2 words 888265236Sken * manually, then loop the rest. 889265236Sken */ 890265236Sken data16 = (uint16_t *)reply; 891265236Sken if (mpr_wait_db_int(sc) != 0) { 892265236Sken mpr_dprint(sc, MPR_FAULT, "Timeout reading doorbell 0\n"); 893265236Sken return (ENXIO); 894265236Sken } 895265236Sken data16[0] = 896265236Sken mpr_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_DATA_MASK; 897265236Sken mpr_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); 898265236Sken if (mpr_wait_db_int(sc) != 0) { 899265236Sken mpr_dprint(sc, MPR_FAULT, "Timeout reading doorbell 1\n"); 900265236Sken return (ENXIO); 901265236Sken } 902265236Sken data16[1] = 903265236Sken mpr_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_DATA_MASK; 904265236Sken mpr_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); 905265236Sken 906265236Sken /* Number of 32bit words in the message */ 907265236Sken ioc_sz = reply->MsgLength; 908265236Sken 909265236Sken /* 910265236Sken * Figure out how many 16bit words to clock in without overrunning. 911265236Sken * The precision loss with dividing reply_sz can safely be 912265236Sken * ignored because the messages can only be multiples of 32bits. 913265236Sken */ 914265236Sken residual = 0; 915265236Sken count = MIN((reply_sz / 4), ioc_sz) * 2; 916265236Sken if (count < ioc_sz * 2) { 917265236Sken residual = ioc_sz * 2 - count; 918265236Sken mpr_dprint(sc, MPR_ERROR, "Driver error, throwing away %d " 919265236Sken "residual message words\n", residual); 920265236Sken } 921265236Sken 922265236Sken for (i = 2; i < count; i++) { 923265236Sken if (mpr_wait_db_int(sc) != 0) { 924265236Sken mpr_dprint(sc, MPR_FAULT, 925265236Sken "Timeout reading doorbell %d\n", i); 926265236Sken return (ENXIO); 927265236Sken } 928265236Sken data16[i] = mpr_regread(sc, MPI2_DOORBELL_OFFSET) & 929265236Sken MPI2_DOORBELL_DATA_MASK; 930265236Sken mpr_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); 931265236Sken } 932265236Sken 933265236Sken /* 934265236Sken * Pull out residual words that won't fit into the provided buffer. 935265236Sken * This keeps the chip from hanging due to a driver programming 936265236Sken * error. 937265236Sken */ 938265236Sken while (residual--) { 939265236Sken if (mpr_wait_db_int(sc) != 0) { 940265236Sken mpr_dprint(sc, MPR_FAULT, "Timeout reading doorbell\n"); 941265236Sken return (ENXIO); 942265236Sken } 943265236Sken (void)mpr_regread(sc, MPI2_DOORBELL_OFFSET); 944265236Sken mpr_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); 945265236Sken } 946265236Sken 947265236Sken /* Step 7 */ 948265236Sken if (mpr_wait_db_int(sc) != 0) { 949265236Sken mpr_dprint(sc, MPR_FAULT, "Timeout waiting to exit doorbell\n"); 950265236Sken return (ENXIO); 951265236Sken } 952265236Sken if (mpr_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_USED) 953265236Sken mpr_dprint(sc, MPR_FAULT, "Warning, doorbell still active\n"); 954265236Sken mpr_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); 955265236Sken 956265236Sken return (0); 957265236Sken} 958265236Sken 959265236Skenstatic void 960265236Skenmpr_enqueue_request(struct mpr_softc *sc, struct mpr_command *cm) 961265236Sken{ 962265236Sken reply_descriptor rd; 963265236Sken 964265236Sken MPR_FUNCTRACE(sc); 965283661Sslm mpr_dprint(sc, MPR_TRACE, "SMID %u cm %p ccb %p\n", 966265236Sken cm->cm_desc.Default.SMID, cm, cm->cm_ccb); 967265236Sken 968265236Sken if (sc->mpr_flags & MPR_FLAGS_ATTACH_DONE && !(sc->mpr_flags & 969265236Sken MPR_FLAGS_SHUTDOWN)) 970265236Sken mtx_assert(&sc->mpr_mtx, MA_OWNED); 971265236Sken 972265236Sken if (++sc->io_cmds_active > sc->io_cmds_highwater) 973265236Sken sc->io_cmds_highwater++; 974265236Sken 975265236Sken rd.u.low = cm->cm_desc.Words.Low; 976265236Sken rd.u.high = cm->cm_desc.Words.High; 977265236Sken rd.word = htole64(rd.word); 978265236Sken /* TODO-We may need to make below regwrite atomic */ 979265236Sken mpr_regwrite(sc, MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET, 980265236Sken rd.u.low); 981265236Sken mpr_regwrite(sc, MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET, 982265236Sken rd.u.high); 983265236Sken} 984265236Sken 985265236Sken/* 986265236Sken * Just the FACTS, ma'am. 987265236Sken */ 988265236Skenstatic int 989265236Skenmpr_get_iocfacts(struct mpr_softc *sc, MPI2_IOC_FACTS_REPLY *facts) 990265236Sken{ 991265236Sken MPI2_DEFAULT_REPLY *reply; 992265236Sken MPI2_IOC_FACTS_REQUEST request; 993265236Sken int error, req_sz, reply_sz; 994265236Sken 995265236Sken MPR_FUNCTRACE(sc); 996265236Sken 997265236Sken req_sz = sizeof(MPI2_IOC_FACTS_REQUEST); 998265236Sken reply_sz = sizeof(MPI2_IOC_FACTS_REPLY); 999265236Sken reply = (MPI2_DEFAULT_REPLY *)facts; 1000265236Sken 1001265236Sken bzero(&request, req_sz); 1002265236Sken request.Function = MPI2_FUNCTION_IOC_FACTS; 1003265236Sken error = mpr_request_sync(sc, &request, reply, req_sz, reply_sz, 5); 1004265236Sken 1005265236Sken return (error); 1006265236Sken} 1007265236Sken 1008265236Skenstatic int 1009265236Skenmpr_send_iocinit(struct mpr_softc *sc) 1010265236Sken{ 1011265236Sken MPI2_IOC_INIT_REQUEST init; 1012265236Sken MPI2_DEFAULT_REPLY reply; 1013265236Sken int req_sz, reply_sz, error; 1014265236Sken struct timeval now; 1015265236Sken uint64_t time_in_msec; 1016265236Sken 1017265236Sken MPR_FUNCTRACE(sc); 1018265236Sken 1019265236Sken req_sz = sizeof(MPI2_IOC_INIT_REQUEST); 1020265236Sken reply_sz = sizeof(MPI2_IOC_INIT_REPLY); 1021265236Sken bzero(&init, req_sz); 1022265236Sken bzero(&reply, reply_sz); 1023265236Sken 1024265236Sken /* 1025265236Sken * Fill in the init block. Note that most addresses are 1026265236Sken * deliberately in the lower 32bits of memory. This is a micro- 1027265236Sken * optimzation for PCI/PCIX, though it's not clear if it helps PCIe. 1028265236Sken */ 1029265236Sken init.Function = MPI2_FUNCTION_IOC_INIT; 1030265236Sken init.WhoInit = MPI2_WHOINIT_HOST_DRIVER; 1031265236Sken init.MsgVersion = htole16(MPI2_VERSION); 1032265236Sken init.HeaderVersion = htole16(MPI2_HEADER_VERSION); 1033265236Sken init.SystemRequestFrameSize = htole16(sc->facts->IOCRequestFrameSize); 1034265236Sken init.ReplyDescriptorPostQueueDepth = htole16(sc->pqdepth); 1035265236Sken init.ReplyFreeQueueDepth = htole16(sc->fqdepth); 1036265236Sken init.SenseBufferAddressHigh = 0; 1037265236Sken init.SystemReplyAddressHigh = 0; 1038265236Sken init.SystemRequestFrameBaseAddress.High = 0; 1039265236Sken init.SystemRequestFrameBaseAddress.Low = 1040265236Sken htole32((uint32_t)sc->req_busaddr); 1041265236Sken init.ReplyDescriptorPostQueueAddress.High = 0; 1042265236Sken init.ReplyDescriptorPostQueueAddress.Low = 1043265236Sken htole32((uint32_t)sc->post_busaddr); 1044265236Sken init.ReplyFreeQueueAddress.High = 0; 1045265236Sken init.ReplyFreeQueueAddress.Low = htole32((uint32_t)sc->free_busaddr); 1046265236Sken getmicrotime(&now); 1047265236Sken time_in_msec = (now.tv_sec * 1000 + now.tv_usec/1000); 1048265236Sken init.TimeStamp.High = htole32((time_in_msec >> 32) & 0xFFFFFFFF); 1049265236Sken init.TimeStamp.Low = htole32(time_in_msec & 0xFFFFFFFF); 1050265236Sken 1051265236Sken error = mpr_request_sync(sc, &init, &reply, req_sz, reply_sz, 5); 1052265236Sken if ((reply.IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS) 1053265236Sken error = ENXIO; 1054265236Sken 1055265236Sken mpr_dprint(sc, MPR_INIT, "IOCInit status= 0x%x\n", reply.IOCStatus); 1056265236Sken return (error); 1057265236Sken} 1058265236Sken 1059265236Skenvoid 1060265236Skenmpr_memaddr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 1061265236Sken{ 1062265236Sken bus_addr_t *addr; 1063265236Sken 1064265236Sken addr = arg; 1065265236Sken *addr = segs[0].ds_addr; 1066265236Sken} 1067265236Sken 1068265236Skenstatic int 1069265236Skenmpr_alloc_queues(struct mpr_softc *sc) 1070265236Sken{ 1071265236Sken bus_addr_t queues_busaddr; 1072265236Sken uint8_t *queues; 1073265236Sken int qsize, fqsize, pqsize; 1074265236Sken 1075265236Sken /* 1076265236Sken * The reply free queue contains 4 byte entries in multiples of 16 and 1077265236Sken * aligned on a 16 byte boundary. There must always be an unused entry. 1078265236Sken * This queue supplies fresh reply frames for the firmware to use. 1079265236Sken * 1080265236Sken * The reply descriptor post queue contains 8 byte entries in 1081265236Sken * multiples of 16 and aligned on a 16 byte boundary. This queue 1082265236Sken * contains filled-in reply frames sent from the firmware to the host. 1083265236Sken * 1084265236Sken * These two queues are allocated together for simplicity. 1085265236Sken */ 1086298433Spfg sc->fqdepth = roundup2(sc->num_replies + 1, 16); 1087298433Spfg sc->pqdepth = roundup2(sc->num_replies + 1, 16); 1088265236Sken fqsize= sc->fqdepth * 4; 1089265236Sken pqsize = sc->pqdepth * 8; 1090265236Sken qsize = fqsize + pqsize; 1091265236Sken 1092265236Sken if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */ 1093265236Sken 16, 0, /* algnmnt, boundary */ 1094265236Sken BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 1095265236Sken BUS_SPACE_MAXADDR, /* highaddr */ 1096265236Sken NULL, NULL, /* filter, filterarg */ 1097265236Sken qsize, /* maxsize */ 1098265236Sken 1, /* nsegments */ 1099265236Sken qsize, /* maxsegsize */ 1100265236Sken 0, /* flags */ 1101265236Sken NULL, NULL, /* lockfunc, lockarg */ 1102265236Sken &sc->queues_dmat)) { 1103265236Sken device_printf(sc->mpr_dev, "Cannot allocate queues DMA tag\n"); 1104265236Sken return (ENOMEM); 1105265236Sken } 1106265236Sken if (bus_dmamem_alloc(sc->queues_dmat, (void **)&queues, BUS_DMA_NOWAIT, 1107265236Sken &sc->queues_map)) { 1108265236Sken device_printf(sc->mpr_dev, "Cannot allocate queues memory\n"); 1109265236Sken return (ENOMEM); 1110265236Sken } 1111265236Sken bzero(queues, qsize); 1112265236Sken bus_dmamap_load(sc->queues_dmat, sc->queues_map, queues, qsize, 1113265236Sken mpr_memaddr_cb, &queues_busaddr, 0); 1114265236Sken 1115265236Sken sc->free_queue = (uint32_t *)queues; 1116265236Sken sc->free_busaddr = queues_busaddr; 1117265236Sken sc->post_queue = (MPI2_REPLY_DESCRIPTORS_UNION *)(queues + fqsize); 1118265236Sken sc->post_busaddr = queues_busaddr + fqsize; 1119265236Sken 1120265236Sken return (0); 1121265236Sken} 1122265236Sken 1123265236Skenstatic int 1124265236Skenmpr_alloc_replies(struct mpr_softc *sc) 1125265236Sken{ 1126265236Sken int rsize, num_replies; 1127265236Sken 1128265236Sken /* 1129265236Sken * sc->num_replies should be one less than sc->fqdepth. We need to 1130265236Sken * allocate space for sc->fqdepth replies, but only sc->num_replies 1131265236Sken * replies can be used at once. 1132265236Sken */ 1133265236Sken num_replies = max(sc->fqdepth, sc->num_replies); 1134265236Sken 1135265236Sken rsize = sc->facts->ReplyFrameSize * num_replies * 4; 1136265236Sken if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */ 1137265236Sken 4, 0, /* algnmnt, boundary */ 1138265236Sken BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 1139265236Sken BUS_SPACE_MAXADDR, /* highaddr */ 1140265236Sken NULL, NULL, /* filter, filterarg */ 1141265236Sken rsize, /* maxsize */ 1142265236Sken 1, /* nsegments */ 1143265236Sken rsize, /* maxsegsize */ 1144265236Sken 0, /* flags */ 1145265236Sken NULL, NULL, /* lockfunc, lockarg */ 1146265236Sken &sc->reply_dmat)) { 1147265236Sken device_printf(sc->mpr_dev, "Cannot allocate replies DMA tag\n"); 1148265236Sken return (ENOMEM); 1149265236Sken } 1150265236Sken if (bus_dmamem_alloc(sc->reply_dmat, (void **)&sc->reply_frames, 1151265236Sken BUS_DMA_NOWAIT, &sc->reply_map)) { 1152265236Sken device_printf(sc->mpr_dev, "Cannot allocate replies memory\n"); 1153265236Sken return (ENOMEM); 1154265236Sken } 1155265236Sken bzero(sc->reply_frames, rsize); 1156265236Sken bus_dmamap_load(sc->reply_dmat, sc->reply_map, sc->reply_frames, rsize, 1157265236Sken mpr_memaddr_cb, &sc->reply_busaddr, 0); 1158265236Sken 1159265236Sken return (0); 1160265236Sken} 1161265236Sken 1162265236Skenstatic int 1163265236Skenmpr_alloc_requests(struct mpr_softc *sc) 1164265236Sken{ 1165265236Sken struct mpr_command *cm; 1166265236Sken struct mpr_chain *chain; 1167265236Sken int i, rsize, nsegs; 1168265236Sken 1169265236Sken rsize = sc->facts->IOCRequestFrameSize * sc->num_reqs * 4; 1170265236Sken if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */ 1171265236Sken 16, 0, /* algnmnt, boundary */ 1172265236Sken BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 1173265236Sken BUS_SPACE_MAXADDR, /* highaddr */ 1174265236Sken NULL, NULL, /* filter, filterarg */ 1175265236Sken rsize, /* maxsize */ 1176265236Sken 1, /* nsegments */ 1177265236Sken rsize, /* maxsegsize */ 1178265236Sken 0, /* flags */ 1179265236Sken NULL, NULL, /* lockfunc, lockarg */ 1180265236Sken &sc->req_dmat)) { 1181265236Sken device_printf(sc->mpr_dev, "Cannot allocate request DMA tag\n"); 1182265236Sken return (ENOMEM); 1183265236Sken } 1184265236Sken if (bus_dmamem_alloc(sc->req_dmat, (void **)&sc->req_frames, 1185265236Sken BUS_DMA_NOWAIT, &sc->req_map)) { 1186265236Sken device_printf(sc->mpr_dev, "Cannot allocate request memory\n"); 1187265236Sken return (ENOMEM); 1188265236Sken } 1189265236Sken bzero(sc->req_frames, rsize); 1190265236Sken bus_dmamap_load(sc->req_dmat, sc->req_map, sc->req_frames, rsize, 1191265236Sken mpr_memaddr_cb, &sc->req_busaddr, 0); 1192265236Sken 1193299266Sslm /* 1194299266Sslm * Gen3 and beyond uses the IOCMaxChainSegmentSize from IOC Facts to 1195299266Sslm * get the size of a Chain Frame. Previous versions use the size as a 1196299266Sslm * Request Frame for the Chain Frame size. If IOCMaxChainSegmentSize 1197299266Sslm * is 0, use the default value. The IOCMaxChainSegmentSize is the 1198299266Sslm * number of 16-byte elelements that can fit in a Chain Frame, which is 1199299266Sslm * the size of an IEEE Simple SGE. 1200299266Sslm */ 1201299266Sslm if (sc->facts->MsgVersion >= MPI2_VERSION_02_05) { 1202299266Sslm sc->chain_seg_size = 1203299266Sslm htole16(sc->facts->IOCMaxChainSegmentSize); 1204299266Sslm if (sc->chain_seg_size == 0) { 1205299266Sslm sc->chain_frame_size = MPR_DEFAULT_CHAIN_SEG_SIZE * 1206299266Sslm MPR_MAX_CHAIN_ELEMENT_SIZE; 1207299266Sslm } else { 1208299266Sslm sc->chain_frame_size = sc->chain_seg_size * 1209299266Sslm MPR_MAX_CHAIN_ELEMENT_SIZE; 1210299266Sslm } 1211299266Sslm } else { 1212299266Sslm sc->chain_frame_size = sc->facts->IOCRequestFrameSize * 4; 1213299266Sslm } 1214299266Sslm rsize = sc->chain_frame_size * sc->max_chains; 1215265236Sken if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */ 1216265236Sken 16, 0, /* algnmnt, boundary */ 1217265236Sken BUS_SPACE_MAXADDR, /* lowaddr */ 1218265236Sken BUS_SPACE_MAXADDR, /* highaddr */ 1219265236Sken NULL, NULL, /* filter, filterarg */ 1220265236Sken rsize, /* maxsize */ 1221265236Sken 1, /* nsegments */ 1222265236Sken rsize, /* maxsegsize */ 1223265236Sken 0, /* flags */ 1224265236Sken NULL, NULL, /* lockfunc, lockarg */ 1225265236Sken &sc->chain_dmat)) { 1226265236Sken device_printf(sc->mpr_dev, "Cannot allocate chain DMA tag\n"); 1227265236Sken return (ENOMEM); 1228265236Sken } 1229265236Sken if (bus_dmamem_alloc(sc->chain_dmat, (void **)&sc->chain_frames, 1230265236Sken BUS_DMA_NOWAIT, &sc->chain_map)) { 1231265236Sken device_printf(sc->mpr_dev, "Cannot allocate chain memory\n"); 1232265236Sken return (ENOMEM); 1233265236Sken } 1234265236Sken bzero(sc->chain_frames, rsize); 1235265236Sken bus_dmamap_load(sc->chain_dmat, sc->chain_map, sc->chain_frames, rsize, 1236265236Sken mpr_memaddr_cb, &sc->chain_busaddr, 0); 1237265236Sken 1238265236Sken rsize = MPR_SENSE_LEN * sc->num_reqs; 1239265236Sken if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */ 1240265236Sken 1, 0, /* algnmnt, boundary */ 1241265236Sken BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 1242265236Sken BUS_SPACE_MAXADDR, /* highaddr */ 1243265236Sken NULL, NULL, /* filter, filterarg */ 1244265236Sken rsize, /* maxsize */ 1245265236Sken 1, /* nsegments */ 1246265236Sken rsize, /* maxsegsize */ 1247265236Sken 0, /* flags */ 1248265236Sken NULL, NULL, /* lockfunc, lockarg */ 1249265236Sken &sc->sense_dmat)) { 1250265236Sken device_printf(sc->mpr_dev, "Cannot allocate sense DMA tag\n"); 1251265236Sken return (ENOMEM); 1252265236Sken } 1253265236Sken if (bus_dmamem_alloc(sc->sense_dmat, (void **)&sc->sense_frames, 1254265236Sken BUS_DMA_NOWAIT, &sc->sense_map)) { 1255265236Sken device_printf(sc->mpr_dev, "Cannot allocate sense memory\n"); 1256265236Sken return (ENOMEM); 1257265236Sken } 1258265236Sken bzero(sc->sense_frames, rsize); 1259265236Sken bus_dmamap_load(sc->sense_dmat, sc->sense_map, sc->sense_frames, rsize, 1260265236Sken mpr_memaddr_cb, &sc->sense_busaddr, 0); 1261265236Sken 1262265236Sken sc->chains = malloc(sizeof(struct mpr_chain) * sc->max_chains, M_MPR, 1263265236Sken M_WAITOK | M_ZERO); 1264265236Sken if (!sc->chains) { 1265265236Sken device_printf(sc->mpr_dev, "Cannot allocate memory %s %d\n", 1266265236Sken __func__, __LINE__); 1267265236Sken return (ENOMEM); 1268265236Sken } 1269265236Sken for (i = 0; i < sc->max_chains; i++) { 1270265236Sken chain = &sc->chains[i]; 1271265236Sken chain->chain = (MPI2_SGE_IO_UNION *)(sc->chain_frames + 1272299266Sslm i * sc->chain_frame_size); 1273265236Sken chain->chain_busaddr = sc->chain_busaddr + 1274299266Sslm i * sc->chain_frame_size; 1275265236Sken mpr_free_chain(sc, chain); 1276265236Sken sc->chain_free_lowwater++; 1277265236Sken } 1278265236Sken 1279265236Sken /* XXX Need to pick a more precise value */ 1280265236Sken nsegs = (MAXPHYS / PAGE_SIZE) + 1; 1281265236Sken if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */ 1282265236Sken 1, 0, /* algnmnt, boundary */ 1283265236Sken BUS_SPACE_MAXADDR, /* lowaddr */ 1284265236Sken BUS_SPACE_MAXADDR, /* highaddr */ 1285265236Sken NULL, NULL, /* filter, filterarg */ 1286265236Sken BUS_SPACE_MAXSIZE_32BIT,/* maxsize */ 1287265236Sken nsegs, /* nsegments */ 1288265236Sken BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 1289265236Sken BUS_DMA_ALLOCNOW, /* flags */ 1290265236Sken busdma_lock_mutex, /* lockfunc */ 1291265236Sken &sc->mpr_mtx, /* lockarg */ 1292265236Sken &sc->buffer_dmat)) { 1293265236Sken device_printf(sc->mpr_dev, "Cannot allocate buffer DMA tag\n"); 1294265236Sken return (ENOMEM); 1295265236Sken } 1296265236Sken 1297265236Sken /* 1298265236Sken * SMID 0 cannot be used as a free command per the firmware spec. 1299265236Sken * Just drop that command instead of risking accounting bugs. 1300265236Sken */ 1301265236Sken sc->commands = malloc(sizeof(struct mpr_command) * sc->num_reqs, 1302265236Sken M_MPR, M_WAITOK | M_ZERO); 1303265236Sken if (!sc->commands) { 1304265236Sken device_printf(sc->mpr_dev, "Cannot allocate memory %s %d\n", 1305265236Sken __func__, __LINE__); 1306265236Sken return (ENOMEM); 1307265236Sken } 1308265236Sken for (i = 1; i < sc->num_reqs; i++) { 1309265236Sken cm = &sc->commands[i]; 1310265236Sken cm->cm_req = sc->req_frames + 1311265236Sken i * sc->facts->IOCRequestFrameSize * 4; 1312265236Sken cm->cm_req_busaddr = sc->req_busaddr + 1313265236Sken i * sc->facts->IOCRequestFrameSize * 4; 1314265236Sken cm->cm_sense = &sc->sense_frames[i]; 1315265236Sken cm->cm_sense_busaddr = sc->sense_busaddr + i * MPR_SENSE_LEN; 1316265236Sken cm->cm_desc.Default.SMID = i; 1317265236Sken cm->cm_sc = sc; 1318265236Sken TAILQ_INIT(&cm->cm_chain_list); 1319265236Sken callout_init_mtx(&cm->cm_callout, &sc->mpr_mtx, 0); 1320265236Sken 1321265236Sken /* XXX Is a failure here a critical problem? */ 1322265236Sken if (bus_dmamap_create(sc->buffer_dmat, 0, &cm->cm_dmamap) == 0) 1323265236Sken if (i <= sc->facts->HighPriorityCredit) 1324265236Sken mpr_free_high_priority_command(sc, cm); 1325265236Sken else 1326265236Sken mpr_free_command(sc, cm); 1327265236Sken else { 1328265236Sken panic("failed to allocate command %d\n", i); 1329265236Sken sc->num_reqs = i; 1330265236Sken break; 1331265236Sken } 1332265236Sken } 1333265236Sken 1334265236Sken return (0); 1335265236Sken} 1336265236Sken 1337265236Skenstatic int 1338265236Skenmpr_init_queues(struct mpr_softc *sc) 1339265236Sken{ 1340265236Sken int i; 1341265236Sken 1342265236Sken memset((uint8_t *)sc->post_queue, 0xff, sc->pqdepth * 8); 1343265236Sken 1344265236Sken /* 1345265236Sken * According to the spec, we need to use one less reply than we 1346265236Sken * have space for on the queue. So sc->num_replies (the number we 1347265236Sken * use) should be less than sc->fqdepth (allocated size). 1348265236Sken */ 1349265236Sken if (sc->num_replies >= sc->fqdepth) 1350265236Sken return (EINVAL); 1351265236Sken 1352265236Sken /* 1353265236Sken * Initialize all of the free queue entries. 1354265236Sken */ 1355265236Sken for (i = 0; i < sc->fqdepth; i++) 1356265236Sken sc->free_queue[i] = sc->reply_busaddr + (i * sc->facts->ReplyFrameSize * 4); 1357265236Sken sc->replyfreeindex = sc->num_replies; 1358265236Sken 1359265236Sken return (0); 1360265236Sken} 1361265236Sken 1362265236Sken/* Get the driver parameter tunables. Lowest priority are the driver defaults. 1363265236Sken * Next are the global settings, if they exist. Highest are the per-unit 1364265236Sken * settings, if they exist. 1365265236Sken */ 1366265236Skenstatic void 1367265236Skenmpr_get_tunables(struct mpr_softc *sc) 1368265236Sken{ 1369265236Sken char tmpstr[80]; 1370265236Sken 1371265236Sken /* XXX default to some debugging for now */ 1372265236Sken sc->mpr_debug = MPR_INFO | MPR_FAULT; 1373265236Sken sc->disable_msix = 0; 1374265236Sken sc->disable_msi = 0; 1375265236Sken sc->max_chains = MPR_CHAIN_FRAMES; 1376303029Sslm sc->max_io_pages = MPR_MAXIO_PAGES; 1377283661Sslm sc->enable_ssu = MPR_SSU_ENABLE_SSD_DISABLE_HDD; 1378283661Sslm sc->spinup_wait_time = DEFAULT_SPINUP_WAIT; 1379265236Sken 1380265236Sken /* 1381265236Sken * Grab the global variables. 1382265236Sken */ 1383265236Sken TUNABLE_INT_FETCH("hw.mpr.debug_level", &sc->mpr_debug); 1384265236Sken TUNABLE_INT_FETCH("hw.mpr.disable_msix", &sc->disable_msix); 1385265236Sken TUNABLE_INT_FETCH("hw.mpr.disable_msi", &sc->disable_msi); 1386265236Sken TUNABLE_INT_FETCH("hw.mpr.max_chains", &sc->max_chains); 1387303029Sslm TUNABLE_INT_FETCH("hw.mpr.max_io_pages", &sc->max_io_pages); 1388283661Sslm TUNABLE_INT_FETCH("hw.mpr.enable_ssu", &sc->enable_ssu); 1389283661Sslm TUNABLE_INT_FETCH("hw.mpr.spinup_wait_time", &sc->spinup_wait_time); 1390265236Sken 1391265236Sken /* Grab the unit-instance variables */ 1392265236Sken snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.debug_level", 1393265236Sken device_get_unit(sc->mpr_dev)); 1394265236Sken TUNABLE_INT_FETCH(tmpstr, &sc->mpr_debug); 1395265236Sken 1396265236Sken snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.disable_msix", 1397265236Sken device_get_unit(sc->mpr_dev)); 1398265236Sken TUNABLE_INT_FETCH(tmpstr, &sc->disable_msix); 1399265236Sken 1400265236Sken snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.disable_msi", 1401265236Sken device_get_unit(sc->mpr_dev)); 1402265236Sken TUNABLE_INT_FETCH(tmpstr, &sc->disable_msi); 1403265236Sken 1404265236Sken snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.max_chains", 1405265236Sken device_get_unit(sc->mpr_dev)); 1406265236Sken TUNABLE_INT_FETCH(tmpstr, &sc->max_chains); 1407265236Sken 1408303029Sslm snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.max_io_pages", 1409303029Sslm device_get_unit(sc->mpr_dev)); 1410303029Sslm TUNABLE_INT_FETCH(tmpstr, &sc->max_io_pages); 1411303029Sslm 1412265236Sken bzero(sc->exclude_ids, sizeof(sc->exclude_ids)); 1413265236Sken snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.exclude_ids", 1414265236Sken device_get_unit(sc->mpr_dev)); 1415265236Sken TUNABLE_STR_FETCH(tmpstr, sc->exclude_ids, sizeof(sc->exclude_ids)); 1416283661Sslm 1417283661Sslm snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.enable_ssu", 1418283661Sslm device_get_unit(sc->mpr_dev)); 1419283661Sslm TUNABLE_INT_FETCH(tmpstr, &sc->enable_ssu); 1420283661Sslm 1421283661Sslm snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.spinup_wait_time", 1422283661Sslm device_get_unit(sc->mpr_dev)); 1423283661Sslm TUNABLE_INT_FETCH(tmpstr, &sc->spinup_wait_time); 1424265236Sken} 1425265236Sken 1426265236Skenstatic void 1427265236Skenmpr_setup_sysctl(struct mpr_softc *sc) 1428265236Sken{ 1429265236Sken struct sysctl_ctx_list *sysctl_ctx = NULL; 1430265236Sken struct sysctl_oid *sysctl_tree = NULL; 1431265236Sken char tmpstr[80], tmpstr2[80]; 1432265236Sken 1433265236Sken /* 1434265236Sken * Setup the sysctl variable so the user can change the debug level 1435265236Sken * on the fly. 1436265236Sken */ 1437265236Sken snprintf(tmpstr, sizeof(tmpstr), "MPR controller %d", 1438265236Sken device_get_unit(sc->mpr_dev)); 1439265236Sken snprintf(tmpstr2, sizeof(tmpstr2), "%d", device_get_unit(sc->mpr_dev)); 1440265236Sken 1441265236Sken sysctl_ctx = device_get_sysctl_ctx(sc->mpr_dev); 1442265236Sken if (sysctl_ctx != NULL) 1443265236Sken sysctl_tree = device_get_sysctl_tree(sc->mpr_dev); 1444265236Sken 1445265236Sken if (sysctl_tree == NULL) { 1446265236Sken sysctl_ctx_init(&sc->sysctl_ctx); 1447265236Sken sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx, 1448265236Sken SYSCTL_STATIC_CHILDREN(_hw_mpr), OID_AUTO, tmpstr2, 1449265236Sken CTLFLAG_RD, 0, tmpstr); 1450265236Sken if (sc->sysctl_tree == NULL) 1451265236Sken return; 1452265236Sken sysctl_ctx = &sc->sysctl_ctx; 1453265236Sken sysctl_tree = sc->sysctl_tree; 1454265236Sken } 1455265236Sken 1456265236Sken SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1457265236Sken OID_AUTO, "debug_level", CTLFLAG_RW, &sc->mpr_debug, 0, 1458265236Sken "mpr debug level"); 1459265236Sken 1460265236Sken SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1461265236Sken OID_AUTO, "disable_msix", CTLFLAG_RD, &sc->disable_msix, 0, 1462265236Sken "Disable the use of MSI-X interrupts"); 1463265236Sken 1464265236Sken SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1465265236Sken OID_AUTO, "disable_msi", CTLFLAG_RD, &sc->disable_msi, 0, 1466265236Sken "Disable the use of MSI interrupts"); 1467265236Sken 1468265236Sken SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1469273377Shselasky OID_AUTO, "firmware_version", CTLFLAG_RW, sc->fw_version, 1470265236Sken strlen(sc->fw_version), "firmware version"); 1471265236Sken 1472265236Sken SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1473265236Sken OID_AUTO, "driver_version", CTLFLAG_RW, MPR_DRIVER_VERSION, 1474265236Sken strlen(MPR_DRIVER_VERSION), "driver version"); 1475265236Sken 1476265236Sken SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1477265236Sken OID_AUTO, "io_cmds_active", CTLFLAG_RD, 1478265236Sken &sc->io_cmds_active, 0, "number of currently active commands"); 1479265236Sken 1480265236Sken SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1481265236Sken OID_AUTO, "io_cmds_highwater", CTLFLAG_RD, 1482265236Sken &sc->io_cmds_highwater, 0, "maximum active commands seen"); 1483265236Sken 1484265236Sken SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1485265236Sken OID_AUTO, "chain_free", CTLFLAG_RD, 1486265236Sken &sc->chain_free, 0, "number of free chain elements"); 1487265236Sken 1488265236Sken SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1489265236Sken OID_AUTO, "chain_free_lowwater", CTLFLAG_RD, 1490265236Sken &sc->chain_free_lowwater, 0,"lowest number of free chain elements"); 1491265236Sken 1492265236Sken SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1493265236Sken OID_AUTO, "max_chains", CTLFLAG_RD, 1494265236Sken &sc->max_chains, 0,"maximum chain frames that will be allocated"); 1495265236Sken 1496283661Sslm SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1497303029Sslm OID_AUTO, "max_io_pages", CTLFLAG_RD, 1498303029Sslm &sc->max_io_pages, 0,"maximum pages to allow per I/O (if <1 use " 1499303029Sslm "IOCFacts)"); 1500303029Sslm 1501303029Sslm SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1502283661Sslm OID_AUTO, "enable_ssu", CTLFLAG_RW, &sc->enable_ssu, 0, 1503283661Sslm "enable SSU to SATA SSD/HDD at shutdown"); 1504283661Sslm 1505265236Sken SYSCTL_ADD_UQUAD(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1506265236Sken OID_AUTO, "chain_alloc_fail", CTLFLAG_RD, 1507265236Sken &sc->chain_alloc_fail, "chain allocation failures"); 1508283661Sslm 1509283661Sslm SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1510283661Sslm OID_AUTO, "spinup_wait_time", CTLFLAG_RD, 1511283661Sslm &sc->spinup_wait_time, DEFAULT_SPINUP_WAIT, "seconds to wait for " 1512283661Sslm "spinup after SATA ID error"); 1513265236Sken} 1514265236Sken 1515265236Skenint 1516265236Skenmpr_attach(struct mpr_softc *sc) 1517265236Sken{ 1518265236Sken int error; 1519265236Sken 1520265236Sken mpr_get_tunables(sc); 1521265236Sken 1522265236Sken MPR_FUNCTRACE(sc); 1523265236Sken 1524265236Sken mtx_init(&sc->mpr_mtx, "MPR lock", NULL, MTX_DEF); 1525265236Sken callout_init_mtx(&sc->periodic, &sc->mpr_mtx, 0); 1526265236Sken TAILQ_INIT(&sc->event_list); 1527265236Sken timevalclear(&sc->lastfail); 1528265236Sken 1529265236Sken if ((error = mpr_transition_ready(sc)) != 0) { 1530265236Sken mpr_printf(sc, "%s failed to transition ready\n", __func__); 1531265236Sken return (error); 1532265236Sken } 1533265236Sken 1534265236Sken sc->facts = malloc(sizeof(MPI2_IOC_FACTS_REPLY), M_MPR, 1535265236Sken M_ZERO|M_NOWAIT); 1536265236Sken if (!sc->facts) { 1537265236Sken device_printf(sc->mpr_dev, "Cannot allocate memory %s %d\n", 1538265236Sken __func__, __LINE__); 1539265236Sken return (ENOMEM); 1540265236Sken } 1541265236Sken 1542265236Sken /* 1543265236Sken * Get IOC Facts and allocate all structures based on this information. 1544265236Sken * A Diag Reset will also call mpr_iocfacts_allocate and re-read the IOC 1545265236Sken * Facts. If relevant values have changed in IOC Facts, this function 1546265236Sken * will free all of the memory based on IOC Facts and reallocate that 1547265236Sken * memory. If this fails, any allocated memory should already be freed. 1548265236Sken */ 1549265236Sken if ((error = mpr_iocfacts_allocate(sc, TRUE)) != 0) { 1550265236Sken mpr_dprint(sc, MPR_FAULT, "%s IOC Facts based allocation " 1551265236Sken "failed with error %d\n", __func__, error); 1552265236Sken return (error); 1553265236Sken } 1554265236Sken 1555265236Sken /* Start the periodic watchdog check on the IOC Doorbell */ 1556265236Sken mpr_periodic(sc); 1557265236Sken 1558265236Sken /* 1559265236Sken * The portenable will kick off discovery events that will drive the 1560265236Sken * rest of the initialization process. The CAM/SAS module will 1561265236Sken * hold up the boot sequence until discovery is complete. 1562265236Sken */ 1563265236Sken sc->mpr_ich.ich_func = mpr_startup; 1564265236Sken sc->mpr_ich.ich_arg = sc; 1565265236Sken if (config_intrhook_establish(&sc->mpr_ich) != 0) { 1566265236Sken mpr_dprint(sc, MPR_ERROR, "Cannot establish MPR config hook\n"); 1567265236Sken error = EINVAL; 1568265236Sken } 1569265236Sken 1570265236Sken /* 1571265236Sken * Allow IR to shutdown gracefully when shutdown occurs. 1572265236Sken */ 1573265236Sken sc->shutdown_eh = EVENTHANDLER_REGISTER(shutdown_final, 1574265236Sken mprsas_ir_shutdown, sc, SHUTDOWN_PRI_DEFAULT); 1575265236Sken 1576265236Sken if (sc->shutdown_eh == NULL) 1577265236Sken mpr_dprint(sc, MPR_ERROR, "shutdown event registration " 1578265236Sken "failed\n"); 1579265236Sken 1580265236Sken mpr_setup_sysctl(sc); 1581265236Sken 1582265236Sken sc->mpr_flags |= MPR_FLAGS_ATTACH_DONE; 1583265236Sken 1584265236Sken return (error); 1585265236Sken} 1586265236Sken 1587265236Sken/* Run through any late-start handlers. */ 1588265236Skenstatic void 1589265236Skenmpr_startup(void *arg) 1590265236Sken{ 1591265236Sken struct mpr_softc *sc; 1592265236Sken 1593265236Sken sc = (struct mpr_softc *)arg; 1594265236Sken 1595265236Sken mpr_lock(sc); 1596265236Sken mpr_unmask_intr(sc); 1597265236Sken 1598265236Sken /* initialize device mapping tables */ 1599265236Sken mpr_base_static_config_pages(sc); 1600265236Sken mpr_mapping_initialize(sc); 1601265236Sken mprsas_startup(sc); 1602265236Sken mpr_unlock(sc); 1603265236Sken} 1604265236Sken 1605265236Sken/* Periodic watchdog. Is called with the driver lock already held. */ 1606265236Skenstatic void 1607265236Skenmpr_periodic(void *arg) 1608265236Sken{ 1609265236Sken struct mpr_softc *sc; 1610265236Sken uint32_t db; 1611265236Sken 1612265236Sken sc = (struct mpr_softc *)arg; 1613265236Sken if (sc->mpr_flags & MPR_FLAGS_SHUTDOWN) 1614265236Sken return; 1615265236Sken 1616265236Sken db = mpr_regread(sc, MPI2_DOORBELL_OFFSET); 1617265236Sken if ((db & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { 1618265236Sken if ((db & MPI2_DOORBELL_FAULT_CODE_MASK) == 1619265236Sken IFAULT_IOP_OVER_TEMP_THRESHOLD_EXCEEDED) { 1620265236Sken panic("TEMPERATURE FAULT: STOPPING."); 1621265236Sken } 1622265236Sken mpr_dprint(sc, MPR_FAULT, "IOC Fault 0x%08x, Resetting\n", db); 1623265236Sken mpr_reinit(sc); 1624265236Sken } 1625265236Sken 1626265236Sken callout_reset(&sc->periodic, MPR_PERIODIC_DELAY * hz, mpr_periodic, sc); 1627265236Sken} 1628265236Sken 1629265236Skenstatic void 1630265236Skenmpr_log_evt_handler(struct mpr_softc *sc, uintptr_t data, 1631265236Sken MPI2_EVENT_NOTIFICATION_REPLY *event) 1632265236Sken{ 1633265236Sken MPI2_EVENT_DATA_LOG_ENTRY_ADDED *entry; 1634265236Sken 1635265236Sken mpr_print_event(sc, event); 1636265236Sken 1637265236Sken switch (event->Event) { 1638265236Sken case MPI2_EVENT_LOG_DATA: 1639265236Sken mpr_dprint(sc, MPR_EVENT, "MPI2_EVENT_LOG_DATA:\n"); 1640265236Sken if (sc->mpr_debug & MPR_EVENT) 1641265236Sken hexdump(event->EventData, event->EventDataLength, NULL, 1642265236Sken 0); 1643265236Sken break; 1644265236Sken case MPI2_EVENT_LOG_ENTRY_ADDED: 1645265236Sken entry = (MPI2_EVENT_DATA_LOG_ENTRY_ADDED *)event->EventData; 1646265236Sken mpr_dprint(sc, MPR_EVENT, "MPI2_EVENT_LOG_ENTRY_ADDED event " 1647265236Sken "0x%x Sequence %d:\n", entry->LogEntryQualifier, 1648265236Sken entry->LogSequence); 1649265236Sken break; 1650265236Sken default: 1651265236Sken break; 1652265236Sken } 1653265236Sken return; 1654265236Sken} 1655265236Sken 1656265236Skenstatic int 1657265236Skenmpr_attach_log(struct mpr_softc *sc) 1658265236Sken{ 1659265236Sken uint8_t events[16]; 1660265236Sken 1661265236Sken bzero(events, 16); 1662265236Sken setbit(events, MPI2_EVENT_LOG_DATA); 1663265236Sken setbit(events, MPI2_EVENT_LOG_ENTRY_ADDED); 1664265236Sken 1665265236Sken mpr_register_events(sc, events, mpr_log_evt_handler, NULL, 1666265236Sken &sc->mpr_log_eh); 1667265236Sken 1668265236Sken return (0); 1669265236Sken} 1670265236Sken 1671265236Skenstatic int 1672265236Skenmpr_detach_log(struct mpr_softc *sc) 1673265236Sken{ 1674265236Sken 1675265236Sken if (sc->mpr_log_eh != NULL) 1676265236Sken mpr_deregister_events(sc, sc->mpr_log_eh); 1677265236Sken return (0); 1678265236Sken} 1679265236Sken 1680265236Sken/* 1681265236Sken * Free all of the driver resources and detach submodules. Should be called 1682265236Sken * without the lock held. 1683265236Sken */ 1684265236Skenint 1685265236Skenmpr_free(struct mpr_softc *sc) 1686265236Sken{ 1687265236Sken int error; 1688265236Sken 1689265236Sken /* Turn off the watchdog */ 1690265236Sken mpr_lock(sc); 1691265236Sken sc->mpr_flags |= MPR_FLAGS_SHUTDOWN; 1692265236Sken mpr_unlock(sc); 1693265236Sken /* Lock must not be held for this */ 1694265236Sken callout_drain(&sc->periodic); 1695265236Sken 1696265236Sken if (((error = mpr_detach_log(sc)) != 0) || 1697265236Sken ((error = mpr_detach_sas(sc)) != 0)) 1698265236Sken return (error); 1699265236Sken 1700265236Sken mpr_detach_user(sc); 1701265236Sken 1702265236Sken /* Put the IOC back in the READY state. */ 1703265236Sken mpr_lock(sc); 1704265236Sken if ((error = mpr_transition_ready(sc)) != 0) { 1705265236Sken mpr_unlock(sc); 1706265236Sken return (error); 1707265236Sken } 1708265236Sken mpr_unlock(sc); 1709265236Sken 1710265236Sken if (sc->facts != NULL) 1711265236Sken free(sc->facts, M_MPR); 1712265236Sken 1713265236Sken /* 1714265236Sken * Free all buffers that are based on IOC Facts. A Diag Reset may need 1715265236Sken * to free these buffers too. 1716265236Sken */ 1717265236Sken mpr_iocfacts_free(sc); 1718265236Sken 1719265236Sken if (sc->sysctl_tree != NULL) 1720265236Sken sysctl_ctx_free(&sc->sysctl_ctx); 1721265236Sken 1722265236Sken /* Deregister the shutdown function */ 1723265236Sken if (sc->shutdown_eh != NULL) 1724265236Sken EVENTHANDLER_DEREGISTER(shutdown_final, sc->shutdown_eh); 1725265236Sken 1726265236Sken mtx_destroy(&sc->mpr_mtx); 1727265236Sken 1728265236Sken return (0); 1729265236Sken} 1730265236Sken 1731265236Skenstatic __inline void 1732265236Skenmpr_complete_command(struct mpr_softc *sc, struct mpr_command *cm) 1733265236Sken{ 1734265236Sken MPR_FUNCTRACE(sc); 1735265236Sken 1736265236Sken if (cm == NULL) { 1737265236Sken mpr_dprint(sc, MPR_ERROR, "Completing NULL command\n"); 1738265236Sken return; 1739265236Sken } 1740265236Sken 1741265236Sken if (cm->cm_flags & MPR_CM_FLAGS_POLLED) 1742265236Sken cm->cm_flags |= MPR_CM_FLAGS_COMPLETE; 1743265236Sken 1744265236Sken if (cm->cm_complete != NULL) { 1745265236Sken mpr_dprint(sc, MPR_TRACE, 1746299265Sslm "%s cm %p calling cm_complete %p data %p reply %p\n", 1747299265Sslm __func__, cm, cm->cm_complete, cm->cm_complete_data, 1748299265Sslm cm->cm_reply); 1749265236Sken cm->cm_complete(sc, cm); 1750265236Sken } 1751265236Sken 1752265236Sken if (cm->cm_flags & MPR_CM_FLAGS_WAKEUP) { 1753265236Sken mpr_dprint(sc, MPR_TRACE, "waking up %p\n", cm); 1754265236Sken wakeup(cm); 1755265236Sken } 1756265236Sken 1757265236Sken if (sc->io_cmds_active != 0) { 1758265236Sken sc->io_cmds_active--; 1759265236Sken } else { 1760265236Sken mpr_dprint(sc, MPR_ERROR, "Warning: io_cmds_active is " 1761265236Sken "out of sync - resynching to 0\n"); 1762265236Sken } 1763265236Sken} 1764265236Sken 1765265236Skenstatic void 1766265236Skenmpr_sas_log_info(struct mpr_softc *sc , u32 log_info) 1767265236Sken{ 1768265236Sken union loginfo_type { 1769265236Sken u32 loginfo; 1770265236Sken struct { 1771265236Sken u32 subcode:16; 1772265236Sken u32 code:8; 1773265236Sken u32 originator:4; 1774265236Sken u32 bus_type:4; 1775265236Sken } dw; 1776265236Sken }; 1777265236Sken union loginfo_type sas_loginfo; 1778265236Sken char *originator_str = NULL; 1779265236Sken 1780265236Sken sas_loginfo.loginfo = log_info; 1781265236Sken if (sas_loginfo.dw.bus_type != 3 /*SAS*/) 1782265236Sken return; 1783265236Sken 1784265236Sken /* each nexus loss loginfo */ 1785265236Sken if (log_info == 0x31170000) 1786265236Sken return; 1787265236Sken 1788265236Sken /* eat the loginfos associated with task aborts */ 1789265236Sken if ((log_info == 30050000) || (log_info == 0x31140000) || 1790265236Sken (log_info == 0x31130000)) 1791265236Sken return; 1792265236Sken 1793265236Sken switch (sas_loginfo.dw.originator) { 1794265236Sken case 0: 1795265236Sken originator_str = "IOP"; 1796265236Sken break; 1797265236Sken case 1: 1798265236Sken originator_str = "PL"; 1799265236Sken break; 1800265236Sken case 2: 1801265236Sken originator_str = "IR"; 1802265236Sken break; 1803265236Sken } 1804265236Sken 1805299268Sslm mpr_dprint(sc, MPR_LOG, "log_info(0x%08x): originator(%s), " 1806299265Sslm "code(0x%02x), sub_code(0x%04x)\n", log_info, originator_str, 1807299265Sslm sas_loginfo.dw.code, sas_loginfo.dw.subcode); 1808265236Sken} 1809265236Sken 1810265236Skenstatic void 1811265236Skenmpr_display_reply_info(struct mpr_softc *sc, uint8_t *reply) 1812265236Sken{ 1813265236Sken MPI2DefaultReply_t *mpi_reply; 1814265236Sken u16 sc_status; 1815265236Sken 1816265236Sken mpi_reply = (MPI2DefaultReply_t*)reply; 1817265236Sken sc_status = le16toh(mpi_reply->IOCStatus); 1818265236Sken if (sc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) 1819265236Sken mpr_sas_log_info(sc, le32toh(mpi_reply->IOCLogInfo)); 1820265236Sken} 1821265236Sken 1822265236Skenvoid 1823265236Skenmpr_intr(void *data) 1824265236Sken{ 1825265236Sken struct mpr_softc *sc; 1826265236Sken uint32_t status; 1827265236Sken 1828265236Sken sc = (struct mpr_softc *)data; 1829265236Sken mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); 1830265236Sken 1831265236Sken /* 1832265236Sken * Check interrupt status register to flush the bus. This is 1833265236Sken * needed for both INTx interrupts and driver-driven polling 1834265236Sken */ 1835265236Sken status = mpr_regread(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET); 1836265236Sken if ((status & MPI2_HIS_REPLY_DESCRIPTOR_INTERRUPT) == 0) 1837265236Sken return; 1838265236Sken 1839265236Sken mpr_lock(sc); 1840265236Sken mpr_intr_locked(data); 1841265236Sken mpr_unlock(sc); 1842265236Sken return; 1843265236Sken} 1844265236Sken 1845265236Sken/* 1846265236Sken * In theory, MSI/MSIX interrupts shouldn't need to read any registers on the 1847265236Sken * chip. Hopefully this theory is correct. 1848265236Sken */ 1849265236Skenvoid 1850265236Skenmpr_intr_msi(void *data) 1851265236Sken{ 1852265236Sken struct mpr_softc *sc; 1853265236Sken 1854265236Sken sc = (struct mpr_softc *)data; 1855265236Sken mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); 1856265236Sken mpr_lock(sc); 1857265236Sken mpr_intr_locked(data); 1858265236Sken mpr_unlock(sc); 1859265236Sken return; 1860265236Sken} 1861265236Sken 1862265236Sken/* 1863265236Sken * The locking is overly broad and simplistic, but easy to deal with for now. 1864265236Sken */ 1865265236Skenvoid 1866265236Skenmpr_intr_locked(void *data) 1867265236Sken{ 1868265236Sken MPI2_REPLY_DESCRIPTORS_UNION *desc; 1869265236Sken struct mpr_softc *sc; 1870265236Sken struct mpr_command *cm = NULL; 1871265236Sken uint8_t flags; 1872265236Sken u_int pq; 1873265236Sken MPI2_DIAG_RELEASE_REPLY *rel_rep; 1874265236Sken mpr_fw_diagnostic_buffer_t *pBuffer; 1875265236Sken 1876265236Sken sc = (struct mpr_softc *)data; 1877265236Sken 1878265236Sken pq = sc->replypostindex; 1879265236Sken mpr_dprint(sc, MPR_TRACE, 1880265236Sken "%s sc %p starting with replypostindex %u\n", 1881265236Sken __func__, sc, sc->replypostindex); 1882265236Sken 1883265236Sken for ( ;; ) { 1884265236Sken cm = NULL; 1885265236Sken desc = &sc->post_queue[sc->replypostindex]; 1886265236Sken flags = desc->Default.ReplyFlags & 1887265236Sken MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; 1888265236Sken if ((flags == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) || 1889265236Sken (le32toh(desc->Words.High) == 0xffffffff)) 1890265236Sken break; 1891265236Sken 1892265236Sken /* increment the replypostindex now, so that event handlers 1893265236Sken * and cm completion handlers which decide to do a diag 1894265236Sken * reset can zero it without it getting incremented again 1895265236Sken * afterwards, and we break out of this loop on the next 1896265236Sken * iteration since the reply post queue has been cleared to 1897265236Sken * 0xFF and all descriptors look unused (which they are). 1898265236Sken */ 1899265236Sken if (++sc->replypostindex >= sc->pqdepth) 1900265236Sken sc->replypostindex = 0; 1901265236Sken 1902265236Sken switch (flags) { 1903265236Sken case MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS: 1904265236Sken case MPI25_RPY_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO_SUCCESS: 1905265236Sken cm = &sc->commands[le16toh(desc->SCSIIOSuccess.SMID)]; 1906265236Sken cm->cm_reply = NULL; 1907265236Sken break; 1908265236Sken case MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY: 1909265236Sken { 1910265236Sken uint32_t baddr; 1911265236Sken uint8_t *reply; 1912265236Sken 1913265236Sken /* 1914265236Sken * Re-compose the reply address from the address 1915265236Sken * sent back from the chip. The ReplyFrameAddress 1916265236Sken * is the lower 32 bits of the physical address of 1917265236Sken * particular reply frame. Convert that address to 1918265236Sken * host format, and then use that to provide the 1919265236Sken * offset against the virtual address base 1920265236Sken * (sc->reply_frames). 1921265236Sken */ 1922265236Sken baddr = le32toh(desc->AddressReply.ReplyFrameAddress); 1923265236Sken reply = sc->reply_frames + 1924265236Sken (baddr - ((uint32_t)sc->reply_busaddr)); 1925265236Sken /* 1926265236Sken * Make sure the reply we got back is in a valid 1927265236Sken * range. If not, go ahead and panic here, since 1928265236Sken * we'll probably panic as soon as we deference the 1929265236Sken * reply pointer anyway. 1930265236Sken */ 1931265236Sken if ((reply < sc->reply_frames) 1932265236Sken || (reply > (sc->reply_frames + 1933265236Sken (sc->fqdepth * sc->facts->ReplyFrameSize * 4)))) { 1934265236Sken printf("%s: WARNING: reply %p out of range!\n", 1935265236Sken __func__, reply); 1936265236Sken printf("%s: reply_frames %p, fqdepth %d, " 1937265236Sken "frame size %d\n", __func__, 1938265236Sken sc->reply_frames, sc->fqdepth, 1939265236Sken sc->facts->ReplyFrameSize * 4); 1940265236Sken printf("%s: baddr %#x,\n", __func__, baddr); 1941265236Sken /* LSI-TODO. See Linux Code for Graceful exit */ 1942265236Sken panic("Reply address out of range"); 1943265236Sken } 1944265236Sken if (le16toh(desc->AddressReply.SMID) == 0) { 1945265236Sken if (((MPI2_DEFAULT_REPLY *)reply)->Function == 1946265236Sken MPI2_FUNCTION_DIAG_BUFFER_POST) { 1947265236Sken /* 1948265236Sken * If SMID is 0 for Diag Buffer Post, 1949265236Sken * this implies that the reply is due to 1950265236Sken * a release function with a status that 1951265236Sken * the buffer has been released. Set 1952265236Sken * the buffer flags accordingly. 1953265236Sken */ 1954265236Sken rel_rep = 1955265236Sken (MPI2_DIAG_RELEASE_REPLY *)reply; 1956299267Sslm if ((le16toh(rel_rep->IOCStatus) & 1957299267Sslm MPI2_IOCSTATUS_MASK) == 1958265236Sken MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED) 1959299267Sslm { 1960265236Sken pBuffer = 1961265236Sken &sc->fw_diag_buffer_list[ 1962265236Sken rel_rep->BufferType]; 1963265236Sken pBuffer->valid_data = TRUE; 1964265236Sken pBuffer->owned_by_firmware = 1965265236Sken FALSE; 1966265236Sken pBuffer->immediate = FALSE; 1967265236Sken } 1968265236Sken } else 1969265236Sken mpr_dispatch_event(sc, baddr, 1970265236Sken (MPI2_EVENT_NOTIFICATION_REPLY *) 1971265236Sken reply); 1972265236Sken } else { 1973265236Sken cm = &sc->commands[ 1974265236Sken le16toh(desc->AddressReply.SMID)]; 1975265236Sken cm->cm_reply = reply; 1976265236Sken cm->cm_reply_data = 1977265236Sken le32toh(desc->AddressReply. 1978265236Sken ReplyFrameAddress); 1979265236Sken } 1980265236Sken break; 1981265236Sken } 1982265236Sken case MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS: 1983265236Sken case MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER: 1984265236Sken case MPI2_RPY_DESCRIPT_FLAGS_RAID_ACCELERATOR_SUCCESS: 1985265236Sken default: 1986265236Sken /* Unhandled */ 1987265236Sken mpr_dprint(sc, MPR_ERROR, "Unhandled reply 0x%x\n", 1988265236Sken desc->Default.ReplyFlags); 1989265236Sken cm = NULL; 1990265236Sken break; 1991265236Sken } 1992265236Sken 1993265236Sken if (cm != NULL) { 1994265236Sken // Print Error reply frame 1995265236Sken if (cm->cm_reply) 1996265236Sken mpr_display_reply_info(sc,cm->cm_reply); 1997265236Sken mpr_complete_command(sc, cm); 1998265236Sken } 1999265236Sken 2000265236Sken desc->Words.Low = 0xffffffff; 2001265236Sken desc->Words.High = 0xffffffff; 2002265236Sken } 2003265236Sken 2004265236Sken if (pq != sc->replypostindex) { 2005265236Sken mpr_dprint(sc, MPR_TRACE, 2006265236Sken "%s sc %p writing postindex %d\n", 2007265236Sken __func__, sc, sc->replypostindex); 2008265236Sken mpr_regwrite(sc, MPI2_REPLY_POST_HOST_INDEX_OFFSET, 2009265236Sken sc->replypostindex); 2010265236Sken } 2011265236Sken 2012265236Sken return; 2013265236Sken} 2014265236Sken 2015265236Skenstatic void 2016265236Skenmpr_dispatch_event(struct mpr_softc *sc, uintptr_t data, 2017265236Sken MPI2_EVENT_NOTIFICATION_REPLY *reply) 2018265236Sken{ 2019265236Sken struct mpr_event_handle *eh; 2020265236Sken int event, handled = 0; 2021265236Sken 2022265236Sken event = le16toh(reply->Event); 2023265236Sken TAILQ_FOREACH(eh, &sc->event_list, eh_list) { 2024265236Sken if (isset(eh->mask, event)) { 2025265236Sken eh->callback(sc, data, reply); 2026265236Sken handled++; 2027265236Sken } 2028265236Sken } 2029265236Sken 2030265236Sken if (handled == 0) 2031265236Sken mpr_dprint(sc, MPR_EVENT, "Unhandled event 0x%x\n", 2032265236Sken le16toh(event)); 2033265236Sken 2034265236Sken /* 2035265236Sken * This is the only place that the event/reply should be freed. 2036265236Sken * Anything wanting to hold onto the event data should have 2037265236Sken * already copied it into their own storage. 2038265236Sken */ 2039265236Sken mpr_free_reply(sc, data); 2040265236Sken} 2041265236Sken 2042265236Skenstatic void 2043265236Skenmpr_reregister_events_complete(struct mpr_softc *sc, struct mpr_command *cm) 2044265236Sken{ 2045265236Sken mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); 2046265236Sken 2047265236Sken if (cm->cm_reply) 2048265236Sken mpr_print_event(sc, 2049265236Sken (MPI2_EVENT_NOTIFICATION_REPLY *)cm->cm_reply); 2050265236Sken 2051265236Sken mpr_free_command(sc, cm); 2052265236Sken 2053265236Sken /* next, send a port enable */ 2054265236Sken mprsas_startup(sc); 2055265236Sken} 2056265236Sken 2057265236Sken/* 2058265236Sken * For both register_events and update_events, the caller supplies a bitmap 2059265236Sken * of events that it _wants_. These functions then turn that into a bitmask 2060265236Sken * suitable for the controller. 2061265236Sken */ 2062265236Skenint 2063265236Skenmpr_register_events(struct mpr_softc *sc, uint8_t *mask, 2064265236Sken mpr_evt_callback_t *cb, void *data, struct mpr_event_handle **handle) 2065265236Sken{ 2066265236Sken struct mpr_event_handle *eh; 2067265236Sken int error = 0; 2068265236Sken 2069265236Sken eh = malloc(sizeof(struct mpr_event_handle), M_MPR, M_WAITOK|M_ZERO); 2070265236Sken if (!eh) { 2071265236Sken device_printf(sc->mpr_dev, "Cannot allocate memory %s %d\n", 2072265236Sken __func__, __LINE__); 2073265236Sken return (ENOMEM); 2074265236Sken } 2075265236Sken eh->callback = cb; 2076265236Sken eh->data = data; 2077265236Sken TAILQ_INSERT_TAIL(&sc->event_list, eh, eh_list); 2078265236Sken if (mask != NULL) 2079265236Sken error = mpr_update_events(sc, eh, mask); 2080265236Sken *handle = eh; 2081265236Sken 2082265236Sken return (error); 2083265236Sken} 2084265236Sken 2085265236Skenint 2086265236Skenmpr_update_events(struct mpr_softc *sc, struct mpr_event_handle *handle, 2087265236Sken uint8_t *mask) 2088265236Sken{ 2089265236Sken MPI2_EVENT_NOTIFICATION_REQUEST *evtreq; 2090265236Sken MPI2_EVENT_NOTIFICATION_REPLY *reply; 2091265236Sken struct mpr_command *cm; 2092265236Sken struct mpr_event_handle *eh; 2093265236Sken int error, i; 2094265236Sken 2095265236Sken mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); 2096265236Sken 2097265236Sken if ((mask != NULL) && (handle != NULL)) 2098265236Sken bcopy(mask, &handle->mask[0], 16); 2099265236Sken memset(sc->event_mask, 0xff, 16); 2100265236Sken 2101265236Sken TAILQ_FOREACH(eh, &sc->event_list, eh_list) { 2102265236Sken for (i = 0; i < 16; i++) 2103265236Sken sc->event_mask[i] &= ~eh->mask[i]; 2104265236Sken } 2105265236Sken 2106265236Sken if ((cm = mpr_alloc_command(sc)) == NULL) 2107265236Sken return (EBUSY); 2108265236Sken evtreq = (MPI2_EVENT_NOTIFICATION_REQUEST *)cm->cm_req; 2109265236Sken evtreq->Function = MPI2_FUNCTION_EVENT_NOTIFICATION; 2110265236Sken evtreq->MsgFlags = 0; 2111265236Sken evtreq->SASBroadcastPrimitiveMasks = 0; 2112265236Sken#ifdef MPR_DEBUG_ALL_EVENTS 2113265236Sken { 2114265236Sken u_char fullmask[16]; 2115265236Sken memset(fullmask, 0x00, 16); 2116265236Sken bcopy(fullmask, (uint8_t *)&evtreq->EventMasks, 16); 2117265236Sken } 2118265236Sken#else 2119265236Sken bcopy(sc->event_mask, (uint8_t *)&evtreq->EventMasks, 16); 2120265236Sken#endif 2121265236Sken cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 2122265236Sken cm->cm_data = NULL; 2123265236Sken 2124265236Sken error = mpr_request_polled(sc, cm); 2125265236Sken reply = (MPI2_EVENT_NOTIFICATION_REPLY *)cm->cm_reply; 2126265236Sken if ((reply == NULL) || 2127265236Sken (reply->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS) 2128265236Sken error = ENXIO; 2129265236Sken 2130283661Sslm if (reply) 2131265236Sken mpr_print_event(sc, reply); 2132265236Sken 2133265236Sken mpr_dprint(sc, MPR_TRACE, "%s finished error %d\n", __func__, error); 2134265236Sken 2135265236Sken mpr_free_command(sc, cm); 2136265236Sken return (error); 2137265236Sken} 2138265236Sken 2139265236Skenstatic int 2140265236Skenmpr_reregister_events(struct mpr_softc *sc) 2141265236Sken{ 2142265236Sken MPI2_EVENT_NOTIFICATION_REQUEST *evtreq; 2143265236Sken struct mpr_command *cm; 2144265236Sken struct mpr_event_handle *eh; 2145265236Sken int error, i; 2146265236Sken 2147265236Sken mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); 2148265236Sken 2149265236Sken /* first, reregister events */ 2150265236Sken 2151265236Sken memset(sc->event_mask, 0xff, 16); 2152265236Sken 2153265236Sken TAILQ_FOREACH(eh, &sc->event_list, eh_list) { 2154265236Sken for (i = 0; i < 16; i++) 2155265236Sken sc->event_mask[i] &= ~eh->mask[i]; 2156265236Sken } 2157265236Sken 2158265236Sken if ((cm = mpr_alloc_command(sc)) == NULL) 2159265236Sken return (EBUSY); 2160265236Sken evtreq = (MPI2_EVENT_NOTIFICATION_REQUEST *)cm->cm_req; 2161265236Sken evtreq->Function = MPI2_FUNCTION_EVENT_NOTIFICATION; 2162265236Sken evtreq->MsgFlags = 0; 2163265236Sken evtreq->SASBroadcastPrimitiveMasks = 0; 2164265236Sken#ifdef MPR_DEBUG_ALL_EVENTS 2165265236Sken { 2166265236Sken u_char fullmask[16]; 2167265236Sken memset(fullmask, 0x00, 16); 2168265236Sken bcopy(fullmask, (uint8_t *)&evtreq->EventMasks, 16); 2169265236Sken } 2170265236Sken#else 2171265236Sken bcopy(sc->event_mask, (uint8_t *)&evtreq->EventMasks, 16); 2172265236Sken#endif 2173265236Sken cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 2174265236Sken cm->cm_data = NULL; 2175265236Sken cm->cm_complete = mpr_reregister_events_complete; 2176265236Sken 2177265236Sken error = mpr_map_command(sc, cm); 2178265236Sken 2179265236Sken mpr_dprint(sc, MPR_TRACE, "%s finished with error %d\n", __func__, 2180265236Sken error); 2181265236Sken return (error); 2182265236Sken} 2183265236Sken 2184265236Skenint 2185265236Skenmpr_deregister_events(struct mpr_softc *sc, struct mpr_event_handle *handle) 2186265236Sken{ 2187265236Sken 2188265236Sken TAILQ_REMOVE(&sc->event_list, handle, eh_list); 2189265236Sken free(handle, M_MPR); 2190265236Sken return (mpr_update_events(sc, NULL, NULL)); 2191265236Sken} 2192265236Sken 2193265236Sken/* 2194265236Sken * Add a chain element as the next SGE for the specified command. 2195265236Sken * Reset cm_sge and cm_sgesize to indicate all the available space. Chains are 2196265236Sken * only required for IEEE commands. Therefore there is no code for commands 2197283661Sslm * that have the MPR_CM_FLAGS_SGE_SIMPLE flag set (and those commands 2198283661Sslm * shouldn't be requesting chains). 2199265236Sken */ 2200265236Skenstatic int 2201265236Skenmpr_add_chain(struct mpr_command *cm, int segsleft) 2202265236Sken{ 2203265236Sken struct mpr_softc *sc = cm->cm_sc; 2204265236Sken MPI2_REQUEST_HEADER *req; 2205265236Sken MPI25_IEEE_SGE_CHAIN64 *ieee_sgc; 2206265236Sken struct mpr_chain *chain; 2207299266Sslm int sgc_size, current_segs, rem_segs, segs_per_frame; 2208265236Sken uint8_t next_chain_offset = 0; 2209265236Sken 2210265236Sken /* 2211265236Sken * Fail if a command is requesting a chain for SIMPLE SGE's. For SAS3 2212265236Sken * only IEEE commands should be requesting chains. Return some error 2213265236Sken * code other than 0. 2214265236Sken */ 2215265236Sken if (cm->cm_flags & MPR_CM_FLAGS_SGE_SIMPLE) { 2216265236Sken mpr_dprint(sc, MPR_ERROR, "A chain element cannot be added to " 2217265236Sken "an MPI SGL.\n"); 2218265236Sken return(ENOBUFS); 2219265236Sken } 2220265236Sken 2221265236Sken sgc_size = sizeof(MPI25_IEEE_SGE_CHAIN64); 2222265236Sken if (cm->cm_sglsize < sgc_size) 2223265236Sken panic("MPR: Need SGE Error Code\n"); 2224265236Sken 2225265236Sken chain = mpr_alloc_chain(cm->cm_sc); 2226265236Sken if (chain == NULL) 2227265236Sken return (ENOBUFS); 2228265236Sken 2229265236Sken /* 2230265236Sken * Note: a double-linked list is used to make it easier to walk for 2231265236Sken * debugging. 2232265236Sken */ 2233265236Sken TAILQ_INSERT_TAIL(&cm->cm_chain_list, chain, chain_link); 2234265236Sken 2235265236Sken /* 2236265236Sken * Need to know if the number of frames left is more than 1 or not. If 2237265236Sken * more than 1 frame is required, NextChainOffset will need to be set, 2238265236Sken * which will just be the last segment of the frame. 2239265236Sken */ 2240265236Sken rem_segs = 0; 2241265236Sken if (cm->cm_sglsize < (sgc_size * segsleft)) { 2242265236Sken /* 2243265236Sken * rem_segs is the number of segements remaining after the 2244265236Sken * segments that will go into the current frame. Since it is 2245265236Sken * known that at least one more frame is required, account for 2246265236Sken * the chain element. To know if more than one more frame is 2247265236Sken * required, just check if there will be a remainder after using 2248265236Sken * the current frame (with this chain) and the next frame. If 2249265236Sken * so the NextChainOffset must be the last element of the next 2250265236Sken * frame. 2251265236Sken */ 2252265236Sken current_segs = (cm->cm_sglsize / sgc_size) - 1; 2253265236Sken rem_segs = segsleft - current_segs; 2254299266Sslm segs_per_frame = sc->chain_frame_size / sgc_size; 2255265236Sken if (rem_segs > segs_per_frame) { 2256265236Sken next_chain_offset = segs_per_frame - 1; 2257265236Sken } 2258265236Sken } 2259265236Sken ieee_sgc = &((MPI25_SGE_IO_UNION *)cm->cm_sge)->IeeeChain; 2260299266Sslm ieee_sgc->Length = next_chain_offset ? 2261299266Sslm htole32((uint32_t)sc->chain_frame_size) : 2262265236Sken htole32((uint32_t)rem_segs * (uint32_t)sgc_size); 2263265236Sken ieee_sgc->NextChainOffset = next_chain_offset; 2264265236Sken ieee_sgc->Flags = (MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT | 2265265236Sken MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR); 2266265236Sken ieee_sgc->Address.Low = htole32(chain->chain_busaddr); 2267265236Sken ieee_sgc->Address.High = htole32(chain->chain_busaddr >> 32); 2268265236Sken cm->cm_sge = &((MPI25_SGE_IO_UNION *)chain->chain)->IeeeSimple; 2269265236Sken req = (MPI2_REQUEST_HEADER *)cm->cm_req; 2270299266Sslm req->ChainOffset = (sc->chain_frame_size - sgc_size) >> 4; 2271265236Sken 2272299266Sslm cm->cm_sglsize = sc->chain_frame_size; 2273265236Sken return (0); 2274265236Sken} 2275265236Sken 2276265236Sken/* 2277265236Sken * Add one scatter-gather element to the scatter-gather list for a command. 2278283661Sslm * Maintain cm_sglsize and cm_sge as the remaining size and pointer to the 2279283661Sslm * next SGE to fill in, respectively. In Gen3, the MPI SGL does not have a 2280283661Sslm * chain, so don't consider any chain additions. 2281265236Sken */ 2282265236Skenint 2283265236Skenmpr_push_sge(struct mpr_command *cm, MPI2_SGE_SIMPLE64 *sge, size_t len, 2284265236Sken int segsleft) 2285265236Sken{ 2286265236Sken uint32_t saved_buf_len, saved_address_low, saved_address_high; 2287265236Sken u32 sge_flags; 2288265236Sken 2289265236Sken /* 2290265236Sken * case 1: >=1 more segment, no room for anything (error) 2291265236Sken * case 2: 1 more segment and enough room for it 2292265236Sken */ 2293265236Sken 2294265236Sken if (cm->cm_sglsize < (segsleft * sizeof(MPI2_SGE_SIMPLE64))) { 2295265236Sken mpr_dprint(cm->cm_sc, MPR_ERROR, 2296265236Sken "%s: warning: Not enough room for MPI SGL in frame.\n", 2297265236Sken __func__); 2298265236Sken return(ENOBUFS); 2299265236Sken } 2300265236Sken 2301265236Sken KASSERT(segsleft == 1, 2302265236Sken ("segsleft cannot be more than 1 for an MPI SGL; segsleft = %d\n", 2303265236Sken segsleft)); 2304265236Sken 2305265236Sken /* 2306265236Sken * There is one more segment left to add for the MPI SGL and there is 2307265236Sken * enough room in the frame to add it. This is the normal case because 2308265236Sken * MPI SGL's don't have chains, otherwise something is wrong. 2309265236Sken * 2310265236Sken * If this is a bi-directional request, need to account for that 2311265236Sken * here. Save the pre-filled sge values. These will be used 2312265236Sken * either for the 2nd SGL or for a single direction SGL. If 2313265236Sken * cm_out_len is non-zero, this is a bi-directional request, so 2314265236Sken * fill in the OUT SGL first, then the IN SGL, otherwise just 2315265236Sken * fill in the IN SGL. Note that at this time, when filling in 2316265236Sken * 2 SGL's for a bi-directional request, they both use the same 2317265236Sken * DMA buffer (same cm command). 2318265236Sken */ 2319265236Sken saved_buf_len = sge->FlagsLength & 0x00FFFFFF; 2320265236Sken saved_address_low = sge->Address.Low; 2321265236Sken saved_address_high = sge->Address.High; 2322265236Sken if (cm->cm_out_len) { 2323265236Sken sge->FlagsLength = cm->cm_out_len | 2324265236Sken ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT | 2325265236Sken MPI2_SGE_FLAGS_END_OF_BUFFER | 2326265236Sken MPI2_SGE_FLAGS_HOST_TO_IOC | 2327265236Sken MPI2_SGE_FLAGS_64_BIT_ADDRESSING) << 2328265236Sken MPI2_SGE_FLAGS_SHIFT); 2329265236Sken cm->cm_sglsize -= len; 2330265236Sken /* Endian Safe code */ 2331265236Sken sge_flags = sge->FlagsLength; 2332265236Sken sge->FlagsLength = htole32(sge_flags); 2333265236Sken sge->Address.High = htole32(sge->Address.High); 2334265236Sken sge->Address.Low = htole32(sge->Address.Low); 2335265236Sken bcopy(sge, cm->cm_sge, len); 2336265236Sken cm->cm_sge = (MPI2_SGE_IO_UNION *)((uintptr_t)cm->cm_sge + len); 2337265236Sken } 2338265236Sken sge->FlagsLength = saved_buf_len | 2339265236Sken ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT | 2340265236Sken MPI2_SGE_FLAGS_END_OF_BUFFER | 2341265236Sken MPI2_SGE_FLAGS_LAST_ELEMENT | 2342265236Sken MPI2_SGE_FLAGS_END_OF_LIST | 2343265236Sken MPI2_SGE_FLAGS_64_BIT_ADDRESSING) << 2344265236Sken MPI2_SGE_FLAGS_SHIFT); 2345265236Sken if (cm->cm_flags & MPR_CM_FLAGS_DATAIN) { 2346265236Sken sge->FlagsLength |= 2347265236Sken ((uint32_t)(MPI2_SGE_FLAGS_IOC_TO_HOST) << 2348265236Sken MPI2_SGE_FLAGS_SHIFT); 2349265236Sken } else { 2350265236Sken sge->FlagsLength |= 2351265236Sken ((uint32_t)(MPI2_SGE_FLAGS_HOST_TO_IOC) << 2352265236Sken MPI2_SGE_FLAGS_SHIFT); 2353265236Sken } 2354265236Sken sge->Address.Low = saved_address_low; 2355265236Sken sge->Address.High = saved_address_high; 2356265236Sken 2357265236Sken cm->cm_sglsize -= len; 2358265236Sken /* Endian Safe code */ 2359265236Sken sge_flags = sge->FlagsLength; 2360265236Sken sge->FlagsLength = htole32(sge_flags); 2361265236Sken sge->Address.High = htole32(sge->Address.High); 2362265236Sken sge->Address.Low = htole32(sge->Address.Low); 2363265236Sken bcopy(sge, cm->cm_sge, len); 2364265236Sken cm->cm_sge = (MPI2_SGE_IO_UNION *)((uintptr_t)cm->cm_sge + len); 2365265236Sken return (0); 2366265236Sken} 2367265236Sken 2368265236Sken/* 2369265236Sken * Add one IEEE scatter-gather element (chain or simple) to the IEEE scatter- 2370265236Sken * gather list for a command. Maintain cm_sglsize and cm_sge as the 2371265236Sken * remaining size and pointer to the next SGE to fill in, respectively. 2372265236Sken */ 2373265236Skenint 2374265236Skenmpr_push_ieee_sge(struct mpr_command *cm, void *sgep, int segsleft) 2375265236Sken{ 2376265236Sken MPI2_IEEE_SGE_SIMPLE64 *sge = sgep; 2377265236Sken int error, ieee_sge_size = sizeof(MPI25_SGE_IO_UNION); 2378265236Sken uint32_t saved_buf_len, saved_address_low, saved_address_high; 2379265236Sken uint32_t sge_length; 2380265236Sken 2381265236Sken /* 2382265236Sken * case 1: No room for chain or segment (error). 2383265236Sken * case 2: Two or more segments left but only room for chain. 2384265236Sken * case 3: Last segment and room for it, so set flags. 2385265236Sken */ 2386265236Sken 2387265236Sken /* 2388265236Sken * There should be room for at least one element, or there is a big 2389265236Sken * problem. 2390265236Sken */ 2391265236Sken if (cm->cm_sglsize < ieee_sge_size) 2392265236Sken panic("MPR: Need SGE Error Code\n"); 2393265236Sken 2394265236Sken if ((segsleft >= 2) && (cm->cm_sglsize < (ieee_sge_size * 2))) { 2395265236Sken if ((error = mpr_add_chain(cm, segsleft)) != 0) 2396265236Sken return (error); 2397265236Sken } 2398265236Sken 2399265236Sken if (segsleft == 1) { 2400265236Sken /* 2401265236Sken * If this is a bi-directional request, need to account for that 2402265236Sken * here. Save the pre-filled sge values. These will be used 2403265236Sken * either for the 2nd SGL or for a single direction SGL. If 2404265236Sken * cm_out_len is non-zero, this is a bi-directional request, so 2405265236Sken * fill in the OUT SGL first, then the IN SGL, otherwise just 2406265236Sken * fill in the IN SGL. Note that at this time, when filling in 2407265236Sken * 2 SGL's for a bi-directional request, they both use the same 2408265236Sken * DMA buffer (same cm command). 2409265236Sken */ 2410265236Sken saved_buf_len = sge->Length; 2411265236Sken saved_address_low = sge->Address.Low; 2412265236Sken saved_address_high = sge->Address.High; 2413265236Sken if (cm->cm_out_len) { 2414265236Sken sge->Length = cm->cm_out_len; 2415265236Sken sge->Flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | 2416265236Sken MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR); 2417265236Sken cm->cm_sglsize -= ieee_sge_size; 2418265236Sken /* Endian Safe code */ 2419265236Sken sge_length = sge->Length; 2420265236Sken sge->Length = htole32(sge_length); 2421265236Sken sge->Address.High = htole32(sge->Address.High); 2422265236Sken sge->Address.Low = htole32(sge->Address.Low); 2423265236Sken bcopy(sgep, cm->cm_sge, ieee_sge_size); 2424265236Sken cm->cm_sge = 2425265236Sken (MPI25_SGE_IO_UNION *)((uintptr_t)cm->cm_sge + 2426265236Sken ieee_sge_size); 2427265236Sken } 2428265236Sken sge->Length = saved_buf_len; 2429265236Sken sge->Flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | 2430265236Sken MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR | 2431265236Sken MPI25_IEEE_SGE_FLAGS_END_OF_LIST); 2432265236Sken sge->Address.Low = saved_address_low; 2433265236Sken sge->Address.High = saved_address_high; 2434265236Sken } 2435265236Sken 2436265236Sken cm->cm_sglsize -= ieee_sge_size; 2437265236Sken /* Endian Safe code */ 2438265236Sken sge_length = sge->Length; 2439265236Sken sge->Length = htole32(sge_length); 2440265236Sken sge->Address.High = htole32(sge->Address.High); 2441265236Sken sge->Address.Low = htole32(sge->Address.Low); 2442265236Sken bcopy(sgep, cm->cm_sge, ieee_sge_size); 2443265236Sken cm->cm_sge = (MPI25_SGE_IO_UNION *)((uintptr_t)cm->cm_sge + 2444265236Sken ieee_sge_size); 2445265236Sken return (0); 2446265236Sken} 2447265236Sken 2448265236Sken/* 2449265236Sken * Add one dma segment to the scatter-gather list for a command. 2450265236Sken */ 2451265236Skenint 2452265236Skenmpr_add_dmaseg(struct mpr_command *cm, vm_paddr_t pa, size_t len, u_int flags, 2453265236Sken int segsleft) 2454265236Sken{ 2455265236Sken MPI2_SGE_SIMPLE64 sge; 2456265236Sken MPI2_IEEE_SGE_SIMPLE64 ieee_sge; 2457265236Sken 2458265236Sken if (!(cm->cm_flags & MPR_CM_FLAGS_SGE_SIMPLE)) { 2459265236Sken ieee_sge.Flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | 2460265236Sken MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR); 2461265236Sken ieee_sge.Length = len; 2462265236Sken mpr_from_u64(pa, &ieee_sge.Address); 2463265236Sken 2464265236Sken return (mpr_push_ieee_sge(cm, &ieee_sge, segsleft)); 2465265236Sken } else { 2466265236Sken /* 2467265236Sken * This driver always uses 64-bit address elements for 2468265236Sken * simplicity. 2469265236Sken */ 2470265236Sken flags |= MPI2_SGE_FLAGS_SIMPLE_ELEMENT | 2471265236Sken MPI2_SGE_FLAGS_64_BIT_ADDRESSING; 2472265236Sken /* Set Endian safe macro in mpr_push_sge */ 2473265236Sken sge.FlagsLength = len | (flags << MPI2_SGE_FLAGS_SHIFT); 2474265236Sken mpr_from_u64(pa, &sge.Address); 2475265236Sken 2476265236Sken return (mpr_push_sge(cm, &sge, sizeof sge, segsleft)); 2477265236Sken } 2478265236Sken} 2479265236Sken 2480265236Skenstatic void 2481265236Skenmpr_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 2482265236Sken{ 2483265236Sken struct mpr_softc *sc; 2484265236Sken struct mpr_command *cm; 2485265236Sken u_int i, dir, sflags; 2486265236Sken 2487265236Sken cm = (struct mpr_command *)arg; 2488265236Sken sc = cm->cm_sc; 2489265236Sken 2490265236Sken /* 2491265236Sken * In this case, just print out a warning and let the chip tell the 2492265236Sken * user they did the wrong thing. 2493265236Sken */ 2494265236Sken if ((cm->cm_max_segs != 0) && (nsegs > cm->cm_max_segs)) { 2495299265Sslm mpr_dprint(sc, MPR_ERROR, "%s: warning: busdma returned %d " 2496299265Sslm "segments, more than the %d allowed\n", __func__, nsegs, 2497299265Sslm cm->cm_max_segs); 2498265236Sken } 2499265236Sken 2500265236Sken /* 2501265236Sken * Set up DMA direction flags. Bi-directional requests are also handled 2502265236Sken * here. In that case, both direction flags will be set. 2503265236Sken */ 2504265236Sken sflags = 0; 2505265236Sken if (cm->cm_flags & MPR_CM_FLAGS_SMP_PASS) { 2506265236Sken /* 2507265236Sken * We have to add a special case for SMP passthrough, there 2508265236Sken * is no easy way to generically handle it. The first 2509265236Sken * S/G element is used for the command (therefore the 2510265236Sken * direction bit needs to be set). The second one is used 2511265236Sken * for the reply. We'll leave it to the caller to make 2512265236Sken * sure we only have two buffers. 2513265236Sken */ 2514265236Sken /* 2515265236Sken * Even though the busdma man page says it doesn't make 2516265236Sken * sense to have both direction flags, it does in this case. 2517265236Sken * We have one s/g element being accessed in each direction. 2518265236Sken */ 2519265236Sken dir = BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD; 2520265236Sken 2521265236Sken /* 2522265236Sken * Set the direction flag on the first buffer in the SMP 2523265236Sken * passthrough request. We'll clear it for the second one. 2524265236Sken */ 2525265236Sken sflags |= MPI2_SGE_FLAGS_DIRECTION | 2526265236Sken MPI2_SGE_FLAGS_END_OF_BUFFER; 2527265236Sken } else if (cm->cm_flags & MPR_CM_FLAGS_DATAOUT) { 2528265236Sken sflags |= MPI2_SGE_FLAGS_HOST_TO_IOC; 2529265236Sken dir = BUS_DMASYNC_PREWRITE; 2530265236Sken } else 2531265236Sken dir = BUS_DMASYNC_PREREAD; 2532265236Sken 2533265236Sken for (i = 0; i < nsegs; i++) { 2534265236Sken if ((cm->cm_flags & MPR_CM_FLAGS_SMP_PASS) && (i != 0)) { 2535265236Sken sflags &= ~MPI2_SGE_FLAGS_DIRECTION; 2536265236Sken } 2537265236Sken error = mpr_add_dmaseg(cm, segs[i].ds_addr, segs[i].ds_len, 2538265236Sken sflags, nsegs - i); 2539265236Sken if (error != 0) { 2540265236Sken /* Resource shortage, roll back! */ 2541265236Sken if (ratecheck(&sc->lastfail, &mpr_chainfail_interval)) 2542265236Sken mpr_dprint(sc, MPR_INFO, "Out of chain frames, " 2543265236Sken "consider increasing hw.mpr.max_chains.\n"); 2544265236Sken cm->cm_flags |= MPR_CM_FLAGS_CHAIN_FAILED; 2545265236Sken mpr_complete_command(sc, cm); 2546265236Sken return; 2547265236Sken } 2548265236Sken } 2549265236Sken 2550265236Sken bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir); 2551265236Sken mpr_enqueue_request(sc, cm); 2552265236Sken 2553265236Sken return; 2554265236Sken} 2555265236Sken 2556265236Skenstatic void 2557265236Skenmpr_data_cb2(void *arg, bus_dma_segment_t *segs, int nsegs, bus_size_t mapsize, 2558265236Sken int error) 2559265236Sken{ 2560265236Sken mpr_data_cb(arg, segs, nsegs, error); 2561265236Sken} 2562265236Sken 2563265236Sken/* 2564265236Sken * This is the routine to enqueue commands ansynchronously. 2565265236Sken * Note that the only error path here is from bus_dmamap_load(), which can 2566265236Sken * return EINPROGRESS if it is waiting for resources. Other than this, it's 2567265236Sken * assumed that if you have a command in-hand, then you have enough credits 2568265236Sken * to use it. 2569265236Sken */ 2570265236Skenint 2571265236Skenmpr_map_command(struct mpr_softc *sc, struct mpr_command *cm) 2572265236Sken{ 2573265236Sken int error = 0; 2574265236Sken 2575265236Sken if (cm->cm_flags & MPR_CM_FLAGS_USE_UIO) { 2576265236Sken error = bus_dmamap_load_uio(sc->buffer_dmat, cm->cm_dmamap, 2577265236Sken &cm->cm_uio, mpr_data_cb2, cm, 0); 2578265236Sken } else if (cm->cm_flags & MPR_CM_FLAGS_USE_CCB) { 2579265236Sken error = bus_dmamap_load_ccb(sc->buffer_dmat, cm->cm_dmamap, 2580265236Sken cm->cm_data, mpr_data_cb, cm, 0); 2581265236Sken } else if ((cm->cm_data != NULL) && (cm->cm_length != 0)) { 2582265236Sken error = bus_dmamap_load(sc->buffer_dmat, cm->cm_dmamap, 2583265236Sken cm->cm_data, cm->cm_length, mpr_data_cb, cm, 0); 2584265236Sken } else { 2585265236Sken /* Add a zero-length element as needed */ 2586265236Sken if (cm->cm_sge != NULL) 2587265236Sken mpr_add_dmaseg(cm, 0, 0, 0, 1); 2588265236Sken mpr_enqueue_request(sc, cm); 2589265236Sken } 2590265236Sken 2591265236Sken return (error); 2592265236Sken} 2593265236Sken 2594265236Sken/* 2595265236Sken * This is the routine to enqueue commands synchronously. An error of 2596265236Sken * EINPROGRESS from mpr_map_command() is ignored since the command will 2597265236Sken * be executed and enqueued automatically. Other errors come from msleep(). 2598265236Sken */ 2599265236Skenint 2600265236Skenmpr_wait_command(struct mpr_softc *sc, struct mpr_command *cm, int timeout, 2601265236Sken int sleep_flag) 2602265236Sken{ 2603265236Sken int error, rc; 2604265236Sken struct timeval cur_time, start_time; 2605265236Sken 2606265236Sken if (sc->mpr_flags & MPR_FLAGS_DIAGRESET) 2607265236Sken return EBUSY; 2608265236Sken 2609265236Sken cm->cm_complete = NULL; 2610265236Sken cm->cm_flags |= (MPR_CM_FLAGS_WAKEUP + MPR_CM_FLAGS_POLLED); 2611265236Sken error = mpr_map_command(sc, cm); 2612265236Sken if ((error != 0) && (error != EINPROGRESS)) 2613265236Sken return (error); 2614265236Sken 2615265236Sken // Check for context and wait for 50 mSec at a time until time has 2616265236Sken // expired or the command has finished. If msleep can't be used, need 2617265236Sken // to poll. 2618265236Sken#if __FreeBSD_version >= 1000029 2619265236Sken if (curthread->td_no_sleeping) 2620265236Sken#else //__FreeBSD_version < 1000029 2621265236Sken if (curthread->td_pflags & TDP_NOSLEEPING) 2622265236Sken#endif //__FreeBSD_version >= 1000029 2623265236Sken sleep_flag = NO_SLEEP; 2624265236Sken getmicrotime(&start_time); 2625265236Sken if (mtx_owned(&sc->mpr_mtx) && sleep_flag == CAN_SLEEP) { 2626265236Sken error = msleep(cm, &sc->mpr_mtx, 0, "mprwait", timeout*hz); 2627265236Sken } else { 2628265236Sken while ((cm->cm_flags & MPR_CM_FLAGS_COMPLETE) == 0) { 2629265236Sken mpr_intr_locked(sc); 2630265236Sken if (sleep_flag == CAN_SLEEP) 2631265236Sken pause("mprwait", hz/20); 2632265236Sken else 2633265236Sken DELAY(50000); 2634265236Sken 2635265236Sken getmicrotime(&cur_time); 2636265236Sken if ((cur_time.tv_sec - start_time.tv_sec) > timeout) { 2637265236Sken error = EWOULDBLOCK; 2638265236Sken break; 2639265236Sken } 2640265236Sken } 2641265236Sken } 2642265236Sken 2643265236Sken if (error == EWOULDBLOCK) { 2644265236Sken mpr_dprint(sc, MPR_FAULT, "Calling Reinit from %s\n", __func__); 2645265236Sken rc = mpr_reinit(sc); 2646265236Sken mpr_dprint(sc, MPR_FAULT, "Reinit %s\n", (rc == 0) ? "success" : 2647265236Sken "failed"); 2648265236Sken error = ETIMEDOUT; 2649265236Sken } 2650265236Sken return (error); 2651265236Sken} 2652265236Sken 2653265236Sken/* 2654265236Sken * This is the routine to enqueue a command synchonously and poll for 2655265236Sken * completion. Its use should be rare. 2656265236Sken */ 2657265236Skenint 2658265236Skenmpr_request_polled(struct mpr_softc *sc, struct mpr_command *cm) 2659265236Sken{ 2660265236Sken int error, timeout = 0, rc; 2661265236Sken struct timeval cur_time, start_time; 2662265236Sken 2663265236Sken error = 0; 2664265236Sken 2665265236Sken cm->cm_flags |= MPR_CM_FLAGS_POLLED; 2666265236Sken cm->cm_complete = NULL; 2667265236Sken mpr_map_command(sc, cm); 2668265236Sken 2669265236Sken getmicrotime(&start_time); 2670265236Sken while ((cm->cm_flags & MPR_CM_FLAGS_COMPLETE) == 0) { 2671265236Sken mpr_intr_locked(sc); 2672265236Sken 2673265236Sken if (mtx_owned(&sc->mpr_mtx)) 2674265236Sken msleep(&sc->msleep_fake_chan, &sc->mpr_mtx, 0, 2675265236Sken "mprpoll", hz/20); 2676265236Sken else 2677265236Sken pause("mprpoll", hz/20); 2678265236Sken 2679265236Sken /* 2680265236Sken * Check for real-time timeout and fail if more than 60 seconds. 2681265236Sken */ 2682265236Sken getmicrotime(&cur_time); 2683265236Sken timeout = cur_time.tv_sec - start_time.tv_sec; 2684265236Sken if (timeout > 60) { 2685265236Sken mpr_dprint(sc, MPR_FAULT, "polling failed\n"); 2686265236Sken error = ETIMEDOUT; 2687265236Sken break; 2688265236Sken } 2689265236Sken } 2690265236Sken 2691283661Sslm if (error) { 2692265236Sken mpr_dprint(sc, MPR_FAULT, "Calling Reinit from %s\n", __func__); 2693265236Sken rc = mpr_reinit(sc); 2694299265Sslm mpr_dprint(sc, MPR_FAULT, "Reinit %s\n", (rc == 0) ? "success" : 2695299265Sslm "failed"); 2696265236Sken } 2697265236Sken return (error); 2698265236Sken} 2699265236Sken 2700265236Sken/* 2701265236Sken * The MPT driver had a verbose interface for config pages. In this driver, 2702298955Spfg * reduce it to much simpler terms, similar to the Linux driver. 2703265236Sken */ 2704265236Skenint 2705265236Skenmpr_read_config_page(struct mpr_softc *sc, struct mpr_config_params *params) 2706265236Sken{ 2707265236Sken MPI2_CONFIG_REQUEST *req; 2708265236Sken struct mpr_command *cm; 2709265236Sken int error; 2710265236Sken 2711265236Sken if (sc->mpr_flags & MPR_FLAGS_BUSY) { 2712265236Sken return (EBUSY); 2713265236Sken } 2714265236Sken 2715265236Sken cm = mpr_alloc_command(sc); 2716265236Sken if (cm == NULL) { 2717265236Sken return (EBUSY); 2718265236Sken } 2719265236Sken 2720265236Sken req = (MPI2_CONFIG_REQUEST *)cm->cm_req; 2721265236Sken req->Function = MPI2_FUNCTION_CONFIG; 2722265236Sken req->Action = params->action; 2723265236Sken req->SGLFlags = 0; 2724265236Sken req->ChainOffset = 0; 2725265236Sken req->PageAddress = params->page_address; 2726265236Sken if (params->hdr.Struct.PageType == MPI2_CONFIG_PAGETYPE_EXTENDED) { 2727265236Sken MPI2_CONFIG_EXTENDED_PAGE_HEADER *hdr; 2728265236Sken 2729265236Sken hdr = ¶ms->hdr.Ext; 2730265236Sken req->ExtPageType = hdr->ExtPageType; 2731265236Sken req->ExtPageLength = hdr->ExtPageLength; 2732265236Sken req->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; 2733265236Sken req->Header.PageLength = 0; /* Must be set to zero */ 2734265236Sken req->Header.PageNumber = hdr->PageNumber; 2735265236Sken req->Header.PageVersion = hdr->PageVersion; 2736265236Sken } else { 2737265236Sken MPI2_CONFIG_PAGE_HEADER *hdr; 2738265236Sken 2739265236Sken hdr = ¶ms->hdr.Struct; 2740265236Sken req->Header.PageType = hdr->PageType; 2741265236Sken req->Header.PageNumber = hdr->PageNumber; 2742265236Sken req->Header.PageLength = hdr->PageLength; 2743265236Sken req->Header.PageVersion = hdr->PageVersion; 2744265236Sken } 2745265236Sken 2746265236Sken cm->cm_data = params->buffer; 2747265236Sken cm->cm_length = params->length; 2748283661Sslm if (cm->cm_data != NULL) { 2749283661Sslm cm->cm_sge = &req->PageBufferSGE; 2750283661Sslm cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); 2751283661Sslm cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE | MPR_CM_FLAGS_DATAIN; 2752283661Sslm } else 2753283661Sslm cm->cm_sge = NULL; 2754265236Sken cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 2755265236Sken 2756265236Sken cm->cm_complete_data = params; 2757265236Sken if (params->callback != NULL) { 2758265236Sken cm->cm_complete = mpr_config_complete; 2759265236Sken return (mpr_map_command(sc, cm)); 2760265236Sken } else { 2761265236Sken error = mpr_wait_command(sc, cm, 0, CAN_SLEEP); 2762265236Sken if (error) { 2763265236Sken mpr_dprint(sc, MPR_FAULT, 2764265236Sken "Error %d reading config page\n", error); 2765265236Sken mpr_free_command(sc, cm); 2766265236Sken return (error); 2767265236Sken } 2768265236Sken mpr_config_complete(sc, cm); 2769265236Sken } 2770265236Sken 2771265236Sken return (0); 2772265236Sken} 2773265236Sken 2774265236Skenint 2775265236Skenmpr_write_config_page(struct mpr_softc *sc, struct mpr_config_params *params) 2776265236Sken{ 2777265236Sken return (EINVAL); 2778265236Sken} 2779265236Sken 2780265236Skenstatic void 2781265236Skenmpr_config_complete(struct mpr_softc *sc, struct mpr_command *cm) 2782265236Sken{ 2783265236Sken MPI2_CONFIG_REPLY *reply; 2784265236Sken struct mpr_config_params *params; 2785265236Sken 2786265236Sken MPR_FUNCTRACE(sc); 2787265236Sken params = cm->cm_complete_data; 2788265236Sken 2789265236Sken if (cm->cm_data != NULL) { 2790265236Sken bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, 2791265236Sken BUS_DMASYNC_POSTREAD); 2792265236Sken bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap); 2793265236Sken } 2794265236Sken 2795265236Sken /* 2796265236Sken * XXX KDM need to do more error recovery? This results in the 2797265236Sken * device in question not getting probed. 2798265236Sken */ 2799265236Sken if ((cm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 2800265236Sken params->status = MPI2_IOCSTATUS_BUSY; 2801265236Sken goto done; 2802265236Sken } 2803265236Sken 2804265236Sken reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; 2805265236Sken if (reply == NULL) { 2806265236Sken params->status = MPI2_IOCSTATUS_BUSY; 2807265236Sken goto done; 2808265236Sken } 2809265236Sken params->status = reply->IOCStatus; 2810283661Sslm if (params->hdr.Struct.PageType == MPI2_CONFIG_PAGETYPE_EXTENDED) { 2811265236Sken params->hdr.Ext.ExtPageType = reply->ExtPageType; 2812265236Sken params->hdr.Ext.ExtPageLength = reply->ExtPageLength; 2813283661Sslm params->hdr.Ext.PageType = reply->Header.PageType; 2814283661Sslm params->hdr.Ext.PageNumber = reply->Header.PageNumber; 2815283661Sslm params->hdr.Ext.PageVersion = reply->Header.PageVersion; 2816265236Sken } else { 2817265236Sken params->hdr.Struct.PageType = reply->Header.PageType; 2818265236Sken params->hdr.Struct.PageNumber = reply->Header.PageNumber; 2819265236Sken params->hdr.Struct.PageLength = reply->Header.PageLength; 2820265236Sken params->hdr.Struct.PageVersion = reply->Header.PageVersion; 2821265236Sken } 2822265236Sken 2823265236Skendone: 2824265236Sken mpr_free_command(sc, cm); 2825265236Sken if (params->callback != NULL) 2826265236Sken params->callback(sc, params); 2827265236Sken 2828265236Sken return; 2829265236Sken} 2830