mpr.c revision 299267
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: head/sys/dev/mpr/mpr.c 299267 2016-05-09 16:21:14Z 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; 1376283661Sslm sc->enable_ssu = MPR_SSU_ENABLE_SSD_DISABLE_HDD; 1377283661Sslm sc->spinup_wait_time = DEFAULT_SPINUP_WAIT; 1378265236Sken 1379265236Sken /* 1380265236Sken * Grab the global variables. 1381265236Sken */ 1382265236Sken TUNABLE_INT_FETCH("hw.mpr.debug_level", &sc->mpr_debug); 1383265236Sken TUNABLE_INT_FETCH("hw.mpr.disable_msix", &sc->disable_msix); 1384265236Sken TUNABLE_INT_FETCH("hw.mpr.disable_msi", &sc->disable_msi); 1385265236Sken TUNABLE_INT_FETCH("hw.mpr.max_chains", &sc->max_chains); 1386283661Sslm TUNABLE_INT_FETCH("hw.mpr.enable_ssu", &sc->enable_ssu); 1387283661Sslm TUNABLE_INT_FETCH("hw.mpr.spinup_wait_time", &sc->spinup_wait_time); 1388265236Sken 1389265236Sken /* Grab the unit-instance variables */ 1390265236Sken snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.debug_level", 1391265236Sken device_get_unit(sc->mpr_dev)); 1392265236Sken TUNABLE_INT_FETCH(tmpstr, &sc->mpr_debug); 1393265236Sken 1394265236Sken snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.disable_msix", 1395265236Sken device_get_unit(sc->mpr_dev)); 1396265236Sken TUNABLE_INT_FETCH(tmpstr, &sc->disable_msix); 1397265236Sken 1398265236Sken snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.disable_msi", 1399265236Sken device_get_unit(sc->mpr_dev)); 1400265236Sken TUNABLE_INT_FETCH(tmpstr, &sc->disable_msi); 1401265236Sken 1402265236Sken snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.max_chains", 1403265236Sken device_get_unit(sc->mpr_dev)); 1404265236Sken TUNABLE_INT_FETCH(tmpstr, &sc->max_chains); 1405265236Sken 1406265236Sken bzero(sc->exclude_ids, sizeof(sc->exclude_ids)); 1407265236Sken snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.exclude_ids", 1408265236Sken device_get_unit(sc->mpr_dev)); 1409265236Sken TUNABLE_STR_FETCH(tmpstr, sc->exclude_ids, sizeof(sc->exclude_ids)); 1410283661Sslm 1411283661Sslm snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.enable_ssu", 1412283661Sslm device_get_unit(sc->mpr_dev)); 1413283661Sslm TUNABLE_INT_FETCH(tmpstr, &sc->enable_ssu); 1414283661Sslm 1415283661Sslm snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.spinup_wait_time", 1416283661Sslm device_get_unit(sc->mpr_dev)); 1417283661Sslm TUNABLE_INT_FETCH(tmpstr, &sc->spinup_wait_time); 1418265236Sken} 1419265236Sken 1420265236Skenstatic void 1421265236Skenmpr_setup_sysctl(struct mpr_softc *sc) 1422265236Sken{ 1423265236Sken struct sysctl_ctx_list *sysctl_ctx = NULL; 1424265236Sken struct sysctl_oid *sysctl_tree = NULL; 1425265236Sken char tmpstr[80], tmpstr2[80]; 1426265236Sken 1427265236Sken /* 1428265236Sken * Setup the sysctl variable so the user can change the debug level 1429265236Sken * on the fly. 1430265236Sken */ 1431265236Sken snprintf(tmpstr, sizeof(tmpstr), "MPR controller %d", 1432265236Sken device_get_unit(sc->mpr_dev)); 1433265236Sken snprintf(tmpstr2, sizeof(tmpstr2), "%d", device_get_unit(sc->mpr_dev)); 1434265236Sken 1435265236Sken sysctl_ctx = device_get_sysctl_ctx(sc->mpr_dev); 1436265236Sken if (sysctl_ctx != NULL) 1437265236Sken sysctl_tree = device_get_sysctl_tree(sc->mpr_dev); 1438265236Sken 1439265236Sken if (sysctl_tree == NULL) { 1440265236Sken sysctl_ctx_init(&sc->sysctl_ctx); 1441265236Sken sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx, 1442265236Sken SYSCTL_STATIC_CHILDREN(_hw_mpr), OID_AUTO, tmpstr2, 1443265236Sken CTLFLAG_RD, 0, tmpstr); 1444265236Sken if (sc->sysctl_tree == NULL) 1445265236Sken return; 1446265236Sken sysctl_ctx = &sc->sysctl_ctx; 1447265236Sken sysctl_tree = sc->sysctl_tree; 1448265236Sken } 1449265236Sken 1450265236Sken SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1451265236Sken OID_AUTO, "debug_level", CTLFLAG_RW, &sc->mpr_debug, 0, 1452265236Sken "mpr debug level"); 1453265236Sken 1454265236Sken SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1455265236Sken OID_AUTO, "disable_msix", CTLFLAG_RD, &sc->disable_msix, 0, 1456265236Sken "Disable the use of MSI-X interrupts"); 1457265236Sken 1458265236Sken SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1459265236Sken OID_AUTO, "disable_msi", CTLFLAG_RD, &sc->disable_msi, 0, 1460265236Sken "Disable the use of MSI interrupts"); 1461265236Sken 1462265236Sken SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1463273377Shselasky OID_AUTO, "firmware_version", CTLFLAG_RW, sc->fw_version, 1464265236Sken strlen(sc->fw_version), "firmware version"); 1465265236Sken 1466265236Sken SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1467265236Sken OID_AUTO, "driver_version", CTLFLAG_RW, MPR_DRIVER_VERSION, 1468265236Sken strlen(MPR_DRIVER_VERSION), "driver version"); 1469265236Sken 1470265236Sken SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1471265236Sken OID_AUTO, "io_cmds_active", CTLFLAG_RD, 1472265236Sken &sc->io_cmds_active, 0, "number of currently active commands"); 1473265236Sken 1474265236Sken SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1475265236Sken OID_AUTO, "io_cmds_highwater", CTLFLAG_RD, 1476265236Sken &sc->io_cmds_highwater, 0, "maximum active commands seen"); 1477265236Sken 1478265236Sken SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1479265236Sken OID_AUTO, "chain_free", CTLFLAG_RD, 1480265236Sken &sc->chain_free, 0, "number of free chain elements"); 1481265236Sken 1482265236Sken SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1483265236Sken OID_AUTO, "chain_free_lowwater", CTLFLAG_RD, 1484265236Sken &sc->chain_free_lowwater, 0,"lowest number of free chain elements"); 1485265236Sken 1486265236Sken SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1487265236Sken OID_AUTO, "max_chains", CTLFLAG_RD, 1488265236Sken &sc->max_chains, 0,"maximum chain frames that will be allocated"); 1489265236Sken 1490283661Sslm SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1491283661Sslm OID_AUTO, "enable_ssu", CTLFLAG_RW, &sc->enable_ssu, 0, 1492283661Sslm "enable SSU to SATA SSD/HDD at shutdown"); 1493283661Sslm 1494265236Sken SYSCTL_ADD_UQUAD(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1495265236Sken OID_AUTO, "chain_alloc_fail", CTLFLAG_RD, 1496265236Sken &sc->chain_alloc_fail, "chain allocation failures"); 1497283661Sslm 1498283661Sslm SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1499283661Sslm OID_AUTO, "spinup_wait_time", CTLFLAG_RD, 1500283661Sslm &sc->spinup_wait_time, DEFAULT_SPINUP_WAIT, "seconds to wait for " 1501283661Sslm "spinup after SATA ID error"); 1502265236Sken} 1503265236Sken 1504265236Skenint 1505265236Skenmpr_attach(struct mpr_softc *sc) 1506265236Sken{ 1507265236Sken int error; 1508265236Sken 1509265236Sken mpr_get_tunables(sc); 1510265236Sken 1511265236Sken MPR_FUNCTRACE(sc); 1512265236Sken 1513265236Sken mtx_init(&sc->mpr_mtx, "MPR lock", NULL, MTX_DEF); 1514265236Sken callout_init_mtx(&sc->periodic, &sc->mpr_mtx, 0); 1515265236Sken TAILQ_INIT(&sc->event_list); 1516265236Sken timevalclear(&sc->lastfail); 1517265236Sken 1518265236Sken if ((error = mpr_transition_ready(sc)) != 0) { 1519265236Sken mpr_printf(sc, "%s failed to transition ready\n", __func__); 1520265236Sken return (error); 1521265236Sken } 1522265236Sken 1523265236Sken sc->facts = malloc(sizeof(MPI2_IOC_FACTS_REPLY), M_MPR, 1524265236Sken M_ZERO|M_NOWAIT); 1525265236Sken if (!sc->facts) { 1526265236Sken device_printf(sc->mpr_dev, "Cannot allocate memory %s %d\n", 1527265236Sken __func__, __LINE__); 1528265236Sken return (ENOMEM); 1529265236Sken } 1530265236Sken 1531265236Sken /* 1532265236Sken * Get IOC Facts and allocate all structures based on this information. 1533265236Sken * A Diag Reset will also call mpr_iocfacts_allocate and re-read the IOC 1534265236Sken * Facts. If relevant values have changed in IOC Facts, this function 1535265236Sken * will free all of the memory based on IOC Facts and reallocate that 1536265236Sken * memory. If this fails, any allocated memory should already be freed. 1537265236Sken */ 1538265236Sken if ((error = mpr_iocfacts_allocate(sc, TRUE)) != 0) { 1539265236Sken mpr_dprint(sc, MPR_FAULT, "%s IOC Facts based allocation " 1540265236Sken "failed with error %d\n", __func__, error); 1541265236Sken return (error); 1542265236Sken } 1543265236Sken 1544265236Sken /* Start the periodic watchdog check on the IOC Doorbell */ 1545265236Sken mpr_periodic(sc); 1546265236Sken 1547265236Sken /* 1548265236Sken * The portenable will kick off discovery events that will drive the 1549265236Sken * rest of the initialization process. The CAM/SAS module will 1550265236Sken * hold up the boot sequence until discovery is complete. 1551265236Sken */ 1552265236Sken sc->mpr_ich.ich_func = mpr_startup; 1553265236Sken sc->mpr_ich.ich_arg = sc; 1554265236Sken if (config_intrhook_establish(&sc->mpr_ich) != 0) { 1555265236Sken mpr_dprint(sc, MPR_ERROR, "Cannot establish MPR config hook\n"); 1556265236Sken error = EINVAL; 1557265236Sken } 1558265236Sken 1559265236Sken /* 1560265236Sken * Allow IR to shutdown gracefully when shutdown occurs. 1561265236Sken */ 1562265236Sken sc->shutdown_eh = EVENTHANDLER_REGISTER(shutdown_final, 1563265236Sken mprsas_ir_shutdown, sc, SHUTDOWN_PRI_DEFAULT); 1564265236Sken 1565265236Sken if (sc->shutdown_eh == NULL) 1566265236Sken mpr_dprint(sc, MPR_ERROR, "shutdown event registration " 1567265236Sken "failed\n"); 1568265236Sken 1569265236Sken mpr_setup_sysctl(sc); 1570265236Sken 1571265236Sken sc->mpr_flags |= MPR_FLAGS_ATTACH_DONE; 1572265236Sken 1573265236Sken return (error); 1574265236Sken} 1575265236Sken 1576265236Sken/* Run through any late-start handlers. */ 1577265236Skenstatic void 1578265236Skenmpr_startup(void *arg) 1579265236Sken{ 1580265236Sken struct mpr_softc *sc; 1581265236Sken 1582265236Sken sc = (struct mpr_softc *)arg; 1583265236Sken 1584265236Sken mpr_lock(sc); 1585265236Sken mpr_unmask_intr(sc); 1586265236Sken 1587265236Sken /* initialize device mapping tables */ 1588265236Sken mpr_base_static_config_pages(sc); 1589265236Sken mpr_mapping_initialize(sc); 1590265236Sken mprsas_startup(sc); 1591265236Sken mpr_unlock(sc); 1592265236Sken} 1593265236Sken 1594265236Sken/* Periodic watchdog. Is called with the driver lock already held. */ 1595265236Skenstatic void 1596265236Skenmpr_periodic(void *arg) 1597265236Sken{ 1598265236Sken struct mpr_softc *sc; 1599265236Sken uint32_t db; 1600265236Sken 1601265236Sken sc = (struct mpr_softc *)arg; 1602265236Sken if (sc->mpr_flags & MPR_FLAGS_SHUTDOWN) 1603265236Sken return; 1604265236Sken 1605265236Sken db = mpr_regread(sc, MPI2_DOORBELL_OFFSET); 1606265236Sken if ((db & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { 1607265236Sken if ((db & MPI2_DOORBELL_FAULT_CODE_MASK) == 1608265236Sken IFAULT_IOP_OVER_TEMP_THRESHOLD_EXCEEDED) { 1609265236Sken panic("TEMPERATURE FAULT: STOPPING."); 1610265236Sken } 1611265236Sken mpr_dprint(sc, MPR_FAULT, "IOC Fault 0x%08x, Resetting\n", db); 1612265236Sken mpr_reinit(sc); 1613265236Sken } 1614265236Sken 1615265236Sken callout_reset(&sc->periodic, MPR_PERIODIC_DELAY * hz, mpr_periodic, sc); 1616265236Sken} 1617265236Sken 1618265236Skenstatic void 1619265236Skenmpr_log_evt_handler(struct mpr_softc *sc, uintptr_t data, 1620265236Sken MPI2_EVENT_NOTIFICATION_REPLY *event) 1621265236Sken{ 1622265236Sken MPI2_EVENT_DATA_LOG_ENTRY_ADDED *entry; 1623265236Sken 1624265236Sken mpr_print_event(sc, event); 1625265236Sken 1626265236Sken switch (event->Event) { 1627265236Sken case MPI2_EVENT_LOG_DATA: 1628265236Sken mpr_dprint(sc, MPR_EVENT, "MPI2_EVENT_LOG_DATA:\n"); 1629265236Sken if (sc->mpr_debug & MPR_EVENT) 1630265236Sken hexdump(event->EventData, event->EventDataLength, NULL, 1631265236Sken 0); 1632265236Sken break; 1633265236Sken case MPI2_EVENT_LOG_ENTRY_ADDED: 1634265236Sken entry = (MPI2_EVENT_DATA_LOG_ENTRY_ADDED *)event->EventData; 1635265236Sken mpr_dprint(sc, MPR_EVENT, "MPI2_EVENT_LOG_ENTRY_ADDED event " 1636265236Sken "0x%x Sequence %d:\n", entry->LogEntryQualifier, 1637265236Sken entry->LogSequence); 1638265236Sken break; 1639265236Sken default: 1640265236Sken break; 1641265236Sken } 1642265236Sken return; 1643265236Sken} 1644265236Sken 1645265236Skenstatic int 1646265236Skenmpr_attach_log(struct mpr_softc *sc) 1647265236Sken{ 1648265236Sken uint8_t events[16]; 1649265236Sken 1650265236Sken bzero(events, 16); 1651265236Sken setbit(events, MPI2_EVENT_LOG_DATA); 1652265236Sken setbit(events, MPI2_EVENT_LOG_ENTRY_ADDED); 1653265236Sken 1654265236Sken mpr_register_events(sc, events, mpr_log_evt_handler, NULL, 1655265236Sken &sc->mpr_log_eh); 1656265236Sken 1657265236Sken return (0); 1658265236Sken} 1659265236Sken 1660265236Skenstatic int 1661265236Skenmpr_detach_log(struct mpr_softc *sc) 1662265236Sken{ 1663265236Sken 1664265236Sken if (sc->mpr_log_eh != NULL) 1665265236Sken mpr_deregister_events(sc, sc->mpr_log_eh); 1666265236Sken return (0); 1667265236Sken} 1668265236Sken 1669265236Sken/* 1670265236Sken * Free all of the driver resources and detach submodules. Should be called 1671265236Sken * without the lock held. 1672265236Sken */ 1673265236Skenint 1674265236Skenmpr_free(struct mpr_softc *sc) 1675265236Sken{ 1676265236Sken int error; 1677265236Sken 1678265236Sken /* Turn off the watchdog */ 1679265236Sken mpr_lock(sc); 1680265236Sken sc->mpr_flags |= MPR_FLAGS_SHUTDOWN; 1681265236Sken mpr_unlock(sc); 1682265236Sken /* Lock must not be held for this */ 1683265236Sken callout_drain(&sc->periodic); 1684265236Sken 1685265236Sken if (((error = mpr_detach_log(sc)) != 0) || 1686265236Sken ((error = mpr_detach_sas(sc)) != 0)) 1687265236Sken return (error); 1688265236Sken 1689265236Sken mpr_detach_user(sc); 1690265236Sken 1691265236Sken /* Put the IOC back in the READY state. */ 1692265236Sken mpr_lock(sc); 1693265236Sken if ((error = mpr_transition_ready(sc)) != 0) { 1694265236Sken mpr_unlock(sc); 1695265236Sken return (error); 1696265236Sken } 1697265236Sken mpr_unlock(sc); 1698265236Sken 1699265236Sken if (sc->facts != NULL) 1700265236Sken free(sc->facts, M_MPR); 1701265236Sken 1702265236Sken /* 1703265236Sken * Free all buffers that are based on IOC Facts. A Diag Reset may need 1704265236Sken * to free these buffers too. 1705265236Sken */ 1706265236Sken mpr_iocfacts_free(sc); 1707265236Sken 1708265236Sken if (sc->sysctl_tree != NULL) 1709265236Sken sysctl_ctx_free(&sc->sysctl_ctx); 1710265236Sken 1711265236Sken /* Deregister the shutdown function */ 1712265236Sken if (sc->shutdown_eh != NULL) 1713265236Sken EVENTHANDLER_DEREGISTER(shutdown_final, sc->shutdown_eh); 1714265236Sken 1715265236Sken mtx_destroy(&sc->mpr_mtx); 1716265236Sken 1717265236Sken return (0); 1718265236Sken} 1719265236Sken 1720265236Skenstatic __inline void 1721265236Skenmpr_complete_command(struct mpr_softc *sc, struct mpr_command *cm) 1722265236Sken{ 1723265236Sken MPR_FUNCTRACE(sc); 1724265236Sken 1725265236Sken if (cm == NULL) { 1726265236Sken mpr_dprint(sc, MPR_ERROR, "Completing NULL command\n"); 1727265236Sken return; 1728265236Sken } 1729265236Sken 1730265236Sken if (cm->cm_flags & MPR_CM_FLAGS_POLLED) 1731265236Sken cm->cm_flags |= MPR_CM_FLAGS_COMPLETE; 1732265236Sken 1733265236Sken if (cm->cm_complete != NULL) { 1734265236Sken mpr_dprint(sc, MPR_TRACE, 1735299265Sslm "%s cm %p calling cm_complete %p data %p reply %p\n", 1736299265Sslm __func__, cm, cm->cm_complete, cm->cm_complete_data, 1737299265Sslm cm->cm_reply); 1738265236Sken cm->cm_complete(sc, cm); 1739265236Sken } 1740265236Sken 1741265236Sken if (cm->cm_flags & MPR_CM_FLAGS_WAKEUP) { 1742265236Sken mpr_dprint(sc, MPR_TRACE, "waking up %p\n", cm); 1743265236Sken wakeup(cm); 1744265236Sken } 1745265236Sken 1746265236Sken if (sc->io_cmds_active != 0) { 1747265236Sken sc->io_cmds_active--; 1748265236Sken } else { 1749265236Sken mpr_dprint(sc, MPR_ERROR, "Warning: io_cmds_active is " 1750265236Sken "out of sync - resynching to 0\n"); 1751265236Sken } 1752265236Sken} 1753265236Sken 1754265236Skenstatic void 1755265236Skenmpr_sas_log_info(struct mpr_softc *sc , u32 log_info) 1756265236Sken{ 1757265236Sken union loginfo_type { 1758265236Sken u32 loginfo; 1759265236Sken struct { 1760265236Sken u32 subcode:16; 1761265236Sken u32 code:8; 1762265236Sken u32 originator:4; 1763265236Sken u32 bus_type:4; 1764265236Sken } dw; 1765265236Sken }; 1766265236Sken union loginfo_type sas_loginfo; 1767265236Sken char *originator_str = NULL; 1768265236Sken 1769265236Sken sas_loginfo.loginfo = log_info; 1770265236Sken if (sas_loginfo.dw.bus_type != 3 /*SAS*/) 1771265236Sken return; 1772265236Sken 1773265236Sken /* each nexus loss loginfo */ 1774265236Sken if (log_info == 0x31170000) 1775265236Sken return; 1776265236Sken 1777265236Sken /* eat the loginfos associated with task aborts */ 1778265236Sken if ((log_info == 30050000) || (log_info == 0x31140000) || 1779265236Sken (log_info == 0x31130000)) 1780265236Sken return; 1781265236Sken 1782265236Sken switch (sas_loginfo.dw.originator) { 1783265236Sken case 0: 1784265236Sken originator_str = "IOP"; 1785265236Sken break; 1786265236Sken case 1: 1787265236Sken originator_str = "PL"; 1788265236Sken break; 1789265236Sken case 2: 1790265236Sken originator_str = "IR"; 1791265236Sken break; 1792265236Sken } 1793265236Sken 1794265236Sken mpr_dprint(sc, MPR_INFO, "log_info(0x%08x): originator(%s), " 1795299265Sslm "code(0x%02x), sub_code(0x%04x)\n", log_info, originator_str, 1796299265Sslm sas_loginfo.dw.code, sas_loginfo.dw.subcode); 1797265236Sken} 1798265236Sken 1799265236Skenstatic void 1800265236Skenmpr_display_reply_info(struct mpr_softc *sc, uint8_t *reply) 1801265236Sken{ 1802265236Sken MPI2DefaultReply_t *mpi_reply; 1803265236Sken u16 sc_status; 1804265236Sken 1805265236Sken mpi_reply = (MPI2DefaultReply_t*)reply; 1806265236Sken sc_status = le16toh(mpi_reply->IOCStatus); 1807265236Sken if (sc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) 1808265236Sken mpr_sas_log_info(sc, le32toh(mpi_reply->IOCLogInfo)); 1809265236Sken} 1810265236Sken 1811265236Skenvoid 1812265236Skenmpr_intr(void *data) 1813265236Sken{ 1814265236Sken struct mpr_softc *sc; 1815265236Sken uint32_t status; 1816265236Sken 1817265236Sken sc = (struct mpr_softc *)data; 1818265236Sken mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); 1819265236Sken 1820265236Sken /* 1821265236Sken * Check interrupt status register to flush the bus. This is 1822265236Sken * needed for both INTx interrupts and driver-driven polling 1823265236Sken */ 1824265236Sken status = mpr_regread(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET); 1825265236Sken if ((status & MPI2_HIS_REPLY_DESCRIPTOR_INTERRUPT) == 0) 1826265236Sken return; 1827265236Sken 1828265236Sken mpr_lock(sc); 1829265236Sken mpr_intr_locked(data); 1830265236Sken mpr_unlock(sc); 1831265236Sken return; 1832265236Sken} 1833265236Sken 1834265236Sken/* 1835265236Sken * In theory, MSI/MSIX interrupts shouldn't need to read any registers on the 1836265236Sken * chip. Hopefully this theory is correct. 1837265236Sken */ 1838265236Skenvoid 1839265236Skenmpr_intr_msi(void *data) 1840265236Sken{ 1841265236Sken struct mpr_softc *sc; 1842265236Sken 1843265236Sken sc = (struct mpr_softc *)data; 1844265236Sken mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); 1845265236Sken mpr_lock(sc); 1846265236Sken mpr_intr_locked(data); 1847265236Sken mpr_unlock(sc); 1848265236Sken return; 1849265236Sken} 1850265236Sken 1851265236Sken/* 1852265236Sken * The locking is overly broad and simplistic, but easy to deal with for now. 1853265236Sken */ 1854265236Skenvoid 1855265236Skenmpr_intr_locked(void *data) 1856265236Sken{ 1857265236Sken MPI2_REPLY_DESCRIPTORS_UNION *desc; 1858265236Sken struct mpr_softc *sc; 1859265236Sken struct mpr_command *cm = NULL; 1860265236Sken uint8_t flags; 1861265236Sken u_int pq; 1862265236Sken MPI2_DIAG_RELEASE_REPLY *rel_rep; 1863265236Sken mpr_fw_diagnostic_buffer_t *pBuffer; 1864265236Sken 1865265236Sken sc = (struct mpr_softc *)data; 1866265236Sken 1867265236Sken pq = sc->replypostindex; 1868265236Sken mpr_dprint(sc, MPR_TRACE, 1869265236Sken "%s sc %p starting with replypostindex %u\n", 1870265236Sken __func__, sc, sc->replypostindex); 1871265236Sken 1872265236Sken for ( ;; ) { 1873265236Sken cm = NULL; 1874265236Sken desc = &sc->post_queue[sc->replypostindex]; 1875265236Sken flags = desc->Default.ReplyFlags & 1876265236Sken MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; 1877265236Sken if ((flags == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) || 1878265236Sken (le32toh(desc->Words.High) == 0xffffffff)) 1879265236Sken break; 1880265236Sken 1881265236Sken /* increment the replypostindex now, so that event handlers 1882265236Sken * and cm completion handlers which decide to do a diag 1883265236Sken * reset can zero it without it getting incremented again 1884265236Sken * afterwards, and we break out of this loop on the next 1885265236Sken * iteration since the reply post queue has been cleared to 1886265236Sken * 0xFF and all descriptors look unused (which they are). 1887265236Sken */ 1888265236Sken if (++sc->replypostindex >= sc->pqdepth) 1889265236Sken sc->replypostindex = 0; 1890265236Sken 1891265236Sken switch (flags) { 1892265236Sken case MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS: 1893265236Sken case MPI25_RPY_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO_SUCCESS: 1894265236Sken cm = &sc->commands[le16toh(desc->SCSIIOSuccess.SMID)]; 1895265236Sken cm->cm_reply = NULL; 1896265236Sken break; 1897265236Sken case MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY: 1898265236Sken { 1899265236Sken uint32_t baddr; 1900265236Sken uint8_t *reply; 1901265236Sken 1902265236Sken /* 1903265236Sken * Re-compose the reply address from the address 1904265236Sken * sent back from the chip. The ReplyFrameAddress 1905265236Sken * is the lower 32 bits of the physical address of 1906265236Sken * particular reply frame. Convert that address to 1907265236Sken * host format, and then use that to provide the 1908265236Sken * offset against the virtual address base 1909265236Sken * (sc->reply_frames). 1910265236Sken */ 1911265236Sken baddr = le32toh(desc->AddressReply.ReplyFrameAddress); 1912265236Sken reply = sc->reply_frames + 1913265236Sken (baddr - ((uint32_t)sc->reply_busaddr)); 1914265236Sken /* 1915265236Sken * Make sure the reply we got back is in a valid 1916265236Sken * range. If not, go ahead and panic here, since 1917265236Sken * we'll probably panic as soon as we deference the 1918265236Sken * reply pointer anyway. 1919265236Sken */ 1920265236Sken if ((reply < sc->reply_frames) 1921265236Sken || (reply > (sc->reply_frames + 1922265236Sken (sc->fqdepth * sc->facts->ReplyFrameSize * 4)))) { 1923265236Sken printf("%s: WARNING: reply %p out of range!\n", 1924265236Sken __func__, reply); 1925265236Sken printf("%s: reply_frames %p, fqdepth %d, " 1926265236Sken "frame size %d\n", __func__, 1927265236Sken sc->reply_frames, sc->fqdepth, 1928265236Sken sc->facts->ReplyFrameSize * 4); 1929265236Sken printf("%s: baddr %#x,\n", __func__, baddr); 1930265236Sken /* LSI-TODO. See Linux Code for Graceful exit */ 1931265236Sken panic("Reply address out of range"); 1932265236Sken } 1933265236Sken if (le16toh(desc->AddressReply.SMID) == 0) { 1934265236Sken if (((MPI2_DEFAULT_REPLY *)reply)->Function == 1935265236Sken MPI2_FUNCTION_DIAG_BUFFER_POST) { 1936265236Sken /* 1937265236Sken * If SMID is 0 for Diag Buffer Post, 1938265236Sken * this implies that the reply is due to 1939265236Sken * a release function with a status that 1940265236Sken * the buffer has been released. Set 1941265236Sken * the buffer flags accordingly. 1942265236Sken */ 1943265236Sken rel_rep = 1944265236Sken (MPI2_DIAG_RELEASE_REPLY *)reply; 1945299267Sslm if ((le16toh(rel_rep->IOCStatus) & 1946299267Sslm MPI2_IOCSTATUS_MASK) == 1947265236Sken MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED) 1948299267Sslm { 1949265236Sken pBuffer = 1950265236Sken &sc->fw_diag_buffer_list[ 1951265236Sken rel_rep->BufferType]; 1952265236Sken pBuffer->valid_data = TRUE; 1953265236Sken pBuffer->owned_by_firmware = 1954265236Sken FALSE; 1955265236Sken pBuffer->immediate = FALSE; 1956265236Sken } 1957265236Sken } else 1958265236Sken mpr_dispatch_event(sc, baddr, 1959265236Sken (MPI2_EVENT_NOTIFICATION_REPLY *) 1960265236Sken reply); 1961265236Sken } else { 1962265236Sken cm = &sc->commands[ 1963265236Sken le16toh(desc->AddressReply.SMID)]; 1964265236Sken cm->cm_reply = reply; 1965265236Sken cm->cm_reply_data = 1966265236Sken le32toh(desc->AddressReply. 1967265236Sken ReplyFrameAddress); 1968265236Sken } 1969265236Sken break; 1970265236Sken } 1971265236Sken case MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS: 1972265236Sken case MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER: 1973265236Sken case MPI2_RPY_DESCRIPT_FLAGS_RAID_ACCELERATOR_SUCCESS: 1974265236Sken default: 1975265236Sken /* Unhandled */ 1976265236Sken mpr_dprint(sc, MPR_ERROR, "Unhandled reply 0x%x\n", 1977265236Sken desc->Default.ReplyFlags); 1978265236Sken cm = NULL; 1979265236Sken break; 1980265236Sken } 1981265236Sken 1982265236Sken if (cm != NULL) { 1983265236Sken // Print Error reply frame 1984265236Sken if (cm->cm_reply) 1985265236Sken mpr_display_reply_info(sc,cm->cm_reply); 1986265236Sken mpr_complete_command(sc, cm); 1987265236Sken } 1988265236Sken 1989265236Sken desc->Words.Low = 0xffffffff; 1990265236Sken desc->Words.High = 0xffffffff; 1991265236Sken } 1992265236Sken 1993265236Sken if (pq != sc->replypostindex) { 1994265236Sken mpr_dprint(sc, MPR_TRACE, 1995265236Sken "%s sc %p writing postindex %d\n", 1996265236Sken __func__, sc, sc->replypostindex); 1997265236Sken mpr_regwrite(sc, MPI2_REPLY_POST_HOST_INDEX_OFFSET, 1998265236Sken sc->replypostindex); 1999265236Sken } 2000265236Sken 2001265236Sken return; 2002265236Sken} 2003265236Sken 2004265236Skenstatic void 2005265236Skenmpr_dispatch_event(struct mpr_softc *sc, uintptr_t data, 2006265236Sken MPI2_EVENT_NOTIFICATION_REPLY *reply) 2007265236Sken{ 2008265236Sken struct mpr_event_handle *eh; 2009265236Sken int event, handled = 0; 2010265236Sken 2011265236Sken event = le16toh(reply->Event); 2012265236Sken TAILQ_FOREACH(eh, &sc->event_list, eh_list) { 2013265236Sken if (isset(eh->mask, event)) { 2014265236Sken eh->callback(sc, data, reply); 2015265236Sken handled++; 2016265236Sken } 2017265236Sken } 2018265236Sken 2019265236Sken if (handled == 0) 2020265236Sken mpr_dprint(sc, MPR_EVENT, "Unhandled event 0x%x\n", 2021265236Sken le16toh(event)); 2022265236Sken 2023265236Sken /* 2024265236Sken * This is the only place that the event/reply should be freed. 2025265236Sken * Anything wanting to hold onto the event data should have 2026265236Sken * already copied it into their own storage. 2027265236Sken */ 2028265236Sken mpr_free_reply(sc, data); 2029265236Sken} 2030265236Sken 2031265236Skenstatic void 2032265236Skenmpr_reregister_events_complete(struct mpr_softc *sc, struct mpr_command *cm) 2033265236Sken{ 2034265236Sken mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); 2035265236Sken 2036265236Sken if (cm->cm_reply) 2037265236Sken mpr_print_event(sc, 2038265236Sken (MPI2_EVENT_NOTIFICATION_REPLY *)cm->cm_reply); 2039265236Sken 2040265236Sken mpr_free_command(sc, cm); 2041265236Sken 2042265236Sken /* next, send a port enable */ 2043265236Sken mprsas_startup(sc); 2044265236Sken} 2045265236Sken 2046265236Sken/* 2047265236Sken * For both register_events and update_events, the caller supplies a bitmap 2048265236Sken * of events that it _wants_. These functions then turn that into a bitmask 2049265236Sken * suitable for the controller. 2050265236Sken */ 2051265236Skenint 2052265236Skenmpr_register_events(struct mpr_softc *sc, uint8_t *mask, 2053265236Sken mpr_evt_callback_t *cb, void *data, struct mpr_event_handle **handle) 2054265236Sken{ 2055265236Sken struct mpr_event_handle *eh; 2056265236Sken int error = 0; 2057265236Sken 2058265236Sken eh = malloc(sizeof(struct mpr_event_handle), M_MPR, M_WAITOK|M_ZERO); 2059265236Sken if (!eh) { 2060265236Sken device_printf(sc->mpr_dev, "Cannot allocate memory %s %d\n", 2061265236Sken __func__, __LINE__); 2062265236Sken return (ENOMEM); 2063265236Sken } 2064265236Sken eh->callback = cb; 2065265236Sken eh->data = data; 2066265236Sken TAILQ_INSERT_TAIL(&sc->event_list, eh, eh_list); 2067265236Sken if (mask != NULL) 2068265236Sken error = mpr_update_events(sc, eh, mask); 2069265236Sken *handle = eh; 2070265236Sken 2071265236Sken return (error); 2072265236Sken} 2073265236Sken 2074265236Skenint 2075265236Skenmpr_update_events(struct mpr_softc *sc, struct mpr_event_handle *handle, 2076265236Sken uint8_t *mask) 2077265236Sken{ 2078265236Sken MPI2_EVENT_NOTIFICATION_REQUEST *evtreq; 2079265236Sken MPI2_EVENT_NOTIFICATION_REPLY *reply; 2080265236Sken struct mpr_command *cm; 2081265236Sken struct mpr_event_handle *eh; 2082265236Sken int error, i; 2083265236Sken 2084265236Sken mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); 2085265236Sken 2086265236Sken if ((mask != NULL) && (handle != NULL)) 2087265236Sken bcopy(mask, &handle->mask[0], 16); 2088265236Sken memset(sc->event_mask, 0xff, 16); 2089265236Sken 2090265236Sken TAILQ_FOREACH(eh, &sc->event_list, eh_list) { 2091265236Sken for (i = 0; i < 16; i++) 2092265236Sken sc->event_mask[i] &= ~eh->mask[i]; 2093265236Sken } 2094265236Sken 2095265236Sken if ((cm = mpr_alloc_command(sc)) == NULL) 2096265236Sken return (EBUSY); 2097265236Sken evtreq = (MPI2_EVENT_NOTIFICATION_REQUEST *)cm->cm_req; 2098265236Sken evtreq->Function = MPI2_FUNCTION_EVENT_NOTIFICATION; 2099265236Sken evtreq->MsgFlags = 0; 2100265236Sken evtreq->SASBroadcastPrimitiveMasks = 0; 2101265236Sken#ifdef MPR_DEBUG_ALL_EVENTS 2102265236Sken { 2103265236Sken u_char fullmask[16]; 2104265236Sken memset(fullmask, 0x00, 16); 2105265236Sken bcopy(fullmask, (uint8_t *)&evtreq->EventMasks, 16); 2106265236Sken } 2107265236Sken#else 2108265236Sken bcopy(sc->event_mask, (uint8_t *)&evtreq->EventMasks, 16); 2109265236Sken#endif 2110265236Sken cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 2111265236Sken cm->cm_data = NULL; 2112265236Sken 2113265236Sken error = mpr_request_polled(sc, cm); 2114265236Sken reply = (MPI2_EVENT_NOTIFICATION_REPLY *)cm->cm_reply; 2115265236Sken if ((reply == NULL) || 2116265236Sken (reply->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS) 2117265236Sken error = ENXIO; 2118265236Sken 2119283661Sslm if (reply) 2120265236Sken mpr_print_event(sc, reply); 2121265236Sken 2122265236Sken mpr_dprint(sc, MPR_TRACE, "%s finished error %d\n", __func__, error); 2123265236Sken 2124265236Sken mpr_free_command(sc, cm); 2125265236Sken return (error); 2126265236Sken} 2127265236Sken 2128265236Skenstatic int 2129265236Skenmpr_reregister_events(struct mpr_softc *sc) 2130265236Sken{ 2131265236Sken MPI2_EVENT_NOTIFICATION_REQUEST *evtreq; 2132265236Sken struct mpr_command *cm; 2133265236Sken struct mpr_event_handle *eh; 2134265236Sken int error, i; 2135265236Sken 2136265236Sken mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); 2137265236Sken 2138265236Sken /* first, reregister events */ 2139265236Sken 2140265236Sken memset(sc->event_mask, 0xff, 16); 2141265236Sken 2142265236Sken TAILQ_FOREACH(eh, &sc->event_list, eh_list) { 2143265236Sken for (i = 0; i < 16; i++) 2144265236Sken sc->event_mask[i] &= ~eh->mask[i]; 2145265236Sken } 2146265236Sken 2147265236Sken if ((cm = mpr_alloc_command(sc)) == NULL) 2148265236Sken return (EBUSY); 2149265236Sken evtreq = (MPI2_EVENT_NOTIFICATION_REQUEST *)cm->cm_req; 2150265236Sken evtreq->Function = MPI2_FUNCTION_EVENT_NOTIFICATION; 2151265236Sken evtreq->MsgFlags = 0; 2152265236Sken evtreq->SASBroadcastPrimitiveMasks = 0; 2153265236Sken#ifdef MPR_DEBUG_ALL_EVENTS 2154265236Sken { 2155265236Sken u_char fullmask[16]; 2156265236Sken memset(fullmask, 0x00, 16); 2157265236Sken bcopy(fullmask, (uint8_t *)&evtreq->EventMasks, 16); 2158265236Sken } 2159265236Sken#else 2160265236Sken bcopy(sc->event_mask, (uint8_t *)&evtreq->EventMasks, 16); 2161265236Sken#endif 2162265236Sken cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 2163265236Sken cm->cm_data = NULL; 2164265236Sken cm->cm_complete = mpr_reregister_events_complete; 2165265236Sken 2166265236Sken error = mpr_map_command(sc, cm); 2167265236Sken 2168265236Sken mpr_dprint(sc, MPR_TRACE, "%s finished with error %d\n", __func__, 2169265236Sken error); 2170265236Sken return (error); 2171265236Sken} 2172265236Sken 2173265236Skenint 2174265236Skenmpr_deregister_events(struct mpr_softc *sc, struct mpr_event_handle *handle) 2175265236Sken{ 2176265236Sken 2177265236Sken TAILQ_REMOVE(&sc->event_list, handle, eh_list); 2178265236Sken free(handle, M_MPR); 2179265236Sken return (mpr_update_events(sc, NULL, NULL)); 2180265236Sken} 2181265236Sken 2182265236Sken/* 2183265236Sken * Add a chain element as the next SGE for the specified command. 2184265236Sken * Reset cm_sge and cm_sgesize to indicate all the available space. Chains are 2185265236Sken * only required for IEEE commands. Therefore there is no code for commands 2186283661Sslm * that have the MPR_CM_FLAGS_SGE_SIMPLE flag set (and those commands 2187283661Sslm * shouldn't be requesting chains). 2188265236Sken */ 2189265236Skenstatic int 2190265236Skenmpr_add_chain(struct mpr_command *cm, int segsleft) 2191265236Sken{ 2192265236Sken struct mpr_softc *sc = cm->cm_sc; 2193265236Sken MPI2_REQUEST_HEADER *req; 2194265236Sken MPI25_IEEE_SGE_CHAIN64 *ieee_sgc; 2195265236Sken struct mpr_chain *chain; 2196299266Sslm int sgc_size, current_segs, rem_segs, segs_per_frame; 2197265236Sken uint8_t next_chain_offset = 0; 2198265236Sken 2199265236Sken /* 2200265236Sken * Fail if a command is requesting a chain for SIMPLE SGE's. For SAS3 2201265236Sken * only IEEE commands should be requesting chains. Return some error 2202265236Sken * code other than 0. 2203265236Sken */ 2204265236Sken if (cm->cm_flags & MPR_CM_FLAGS_SGE_SIMPLE) { 2205265236Sken mpr_dprint(sc, MPR_ERROR, "A chain element cannot be added to " 2206265236Sken "an MPI SGL.\n"); 2207265236Sken return(ENOBUFS); 2208265236Sken } 2209265236Sken 2210265236Sken sgc_size = sizeof(MPI25_IEEE_SGE_CHAIN64); 2211265236Sken if (cm->cm_sglsize < sgc_size) 2212265236Sken panic("MPR: Need SGE Error Code\n"); 2213265236Sken 2214265236Sken chain = mpr_alloc_chain(cm->cm_sc); 2215265236Sken if (chain == NULL) 2216265236Sken return (ENOBUFS); 2217265236Sken 2218265236Sken /* 2219265236Sken * Note: a double-linked list is used to make it easier to walk for 2220265236Sken * debugging. 2221265236Sken */ 2222265236Sken TAILQ_INSERT_TAIL(&cm->cm_chain_list, chain, chain_link); 2223265236Sken 2224265236Sken /* 2225265236Sken * Need to know if the number of frames left is more than 1 or not. If 2226265236Sken * more than 1 frame is required, NextChainOffset will need to be set, 2227265236Sken * which will just be the last segment of the frame. 2228265236Sken */ 2229265236Sken rem_segs = 0; 2230265236Sken if (cm->cm_sglsize < (sgc_size * segsleft)) { 2231265236Sken /* 2232265236Sken * rem_segs is the number of segements remaining after the 2233265236Sken * segments that will go into the current frame. Since it is 2234265236Sken * known that at least one more frame is required, account for 2235265236Sken * the chain element. To know if more than one more frame is 2236265236Sken * required, just check if there will be a remainder after using 2237265236Sken * the current frame (with this chain) and the next frame. If 2238265236Sken * so the NextChainOffset must be the last element of the next 2239265236Sken * frame. 2240265236Sken */ 2241265236Sken current_segs = (cm->cm_sglsize / sgc_size) - 1; 2242265236Sken rem_segs = segsleft - current_segs; 2243299266Sslm segs_per_frame = sc->chain_frame_size / sgc_size; 2244265236Sken if (rem_segs > segs_per_frame) { 2245265236Sken next_chain_offset = segs_per_frame - 1; 2246265236Sken } 2247265236Sken } 2248265236Sken ieee_sgc = &((MPI25_SGE_IO_UNION *)cm->cm_sge)->IeeeChain; 2249299266Sslm ieee_sgc->Length = next_chain_offset ? 2250299266Sslm htole32((uint32_t)sc->chain_frame_size) : 2251265236Sken htole32((uint32_t)rem_segs * (uint32_t)sgc_size); 2252265236Sken ieee_sgc->NextChainOffset = next_chain_offset; 2253265236Sken ieee_sgc->Flags = (MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT | 2254265236Sken MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR); 2255265236Sken ieee_sgc->Address.Low = htole32(chain->chain_busaddr); 2256265236Sken ieee_sgc->Address.High = htole32(chain->chain_busaddr >> 32); 2257265236Sken cm->cm_sge = &((MPI25_SGE_IO_UNION *)chain->chain)->IeeeSimple; 2258265236Sken req = (MPI2_REQUEST_HEADER *)cm->cm_req; 2259299266Sslm req->ChainOffset = (sc->chain_frame_size - sgc_size) >> 4; 2260265236Sken 2261299266Sslm cm->cm_sglsize = sc->chain_frame_size; 2262265236Sken return (0); 2263265236Sken} 2264265236Sken 2265265236Sken/* 2266265236Sken * Add one scatter-gather element to the scatter-gather list for a command. 2267283661Sslm * Maintain cm_sglsize and cm_sge as the remaining size and pointer to the 2268283661Sslm * next SGE to fill in, respectively. In Gen3, the MPI SGL does not have a 2269283661Sslm * chain, so don't consider any chain additions. 2270265236Sken */ 2271265236Skenint 2272265236Skenmpr_push_sge(struct mpr_command *cm, MPI2_SGE_SIMPLE64 *sge, size_t len, 2273265236Sken int segsleft) 2274265236Sken{ 2275265236Sken uint32_t saved_buf_len, saved_address_low, saved_address_high; 2276265236Sken u32 sge_flags; 2277265236Sken 2278265236Sken /* 2279265236Sken * case 1: >=1 more segment, no room for anything (error) 2280265236Sken * case 2: 1 more segment and enough room for it 2281265236Sken */ 2282265236Sken 2283265236Sken if (cm->cm_sglsize < (segsleft * sizeof(MPI2_SGE_SIMPLE64))) { 2284265236Sken mpr_dprint(cm->cm_sc, MPR_ERROR, 2285265236Sken "%s: warning: Not enough room for MPI SGL in frame.\n", 2286265236Sken __func__); 2287265236Sken return(ENOBUFS); 2288265236Sken } 2289265236Sken 2290265236Sken KASSERT(segsleft == 1, 2291265236Sken ("segsleft cannot be more than 1 for an MPI SGL; segsleft = %d\n", 2292265236Sken segsleft)); 2293265236Sken 2294265236Sken /* 2295265236Sken * There is one more segment left to add for the MPI SGL and there is 2296265236Sken * enough room in the frame to add it. This is the normal case because 2297265236Sken * MPI SGL's don't have chains, otherwise something is wrong. 2298265236Sken * 2299265236Sken * If this is a bi-directional request, need to account for that 2300265236Sken * here. Save the pre-filled sge values. These will be used 2301265236Sken * either for the 2nd SGL or for a single direction SGL. If 2302265236Sken * cm_out_len is non-zero, this is a bi-directional request, so 2303265236Sken * fill in the OUT SGL first, then the IN SGL, otherwise just 2304265236Sken * fill in the IN SGL. Note that at this time, when filling in 2305265236Sken * 2 SGL's for a bi-directional request, they both use the same 2306265236Sken * DMA buffer (same cm command). 2307265236Sken */ 2308265236Sken saved_buf_len = sge->FlagsLength & 0x00FFFFFF; 2309265236Sken saved_address_low = sge->Address.Low; 2310265236Sken saved_address_high = sge->Address.High; 2311265236Sken if (cm->cm_out_len) { 2312265236Sken sge->FlagsLength = cm->cm_out_len | 2313265236Sken ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT | 2314265236Sken MPI2_SGE_FLAGS_END_OF_BUFFER | 2315265236Sken MPI2_SGE_FLAGS_HOST_TO_IOC | 2316265236Sken MPI2_SGE_FLAGS_64_BIT_ADDRESSING) << 2317265236Sken MPI2_SGE_FLAGS_SHIFT); 2318265236Sken cm->cm_sglsize -= len; 2319265236Sken /* Endian Safe code */ 2320265236Sken sge_flags = sge->FlagsLength; 2321265236Sken sge->FlagsLength = htole32(sge_flags); 2322265236Sken sge->Address.High = htole32(sge->Address.High); 2323265236Sken sge->Address.Low = htole32(sge->Address.Low); 2324265236Sken bcopy(sge, cm->cm_sge, len); 2325265236Sken cm->cm_sge = (MPI2_SGE_IO_UNION *)((uintptr_t)cm->cm_sge + len); 2326265236Sken } 2327265236Sken sge->FlagsLength = saved_buf_len | 2328265236Sken ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT | 2329265236Sken MPI2_SGE_FLAGS_END_OF_BUFFER | 2330265236Sken MPI2_SGE_FLAGS_LAST_ELEMENT | 2331265236Sken MPI2_SGE_FLAGS_END_OF_LIST | 2332265236Sken MPI2_SGE_FLAGS_64_BIT_ADDRESSING) << 2333265236Sken MPI2_SGE_FLAGS_SHIFT); 2334265236Sken if (cm->cm_flags & MPR_CM_FLAGS_DATAIN) { 2335265236Sken sge->FlagsLength |= 2336265236Sken ((uint32_t)(MPI2_SGE_FLAGS_IOC_TO_HOST) << 2337265236Sken MPI2_SGE_FLAGS_SHIFT); 2338265236Sken } else { 2339265236Sken sge->FlagsLength |= 2340265236Sken ((uint32_t)(MPI2_SGE_FLAGS_HOST_TO_IOC) << 2341265236Sken MPI2_SGE_FLAGS_SHIFT); 2342265236Sken } 2343265236Sken sge->Address.Low = saved_address_low; 2344265236Sken sge->Address.High = saved_address_high; 2345265236Sken 2346265236Sken cm->cm_sglsize -= len; 2347265236Sken /* Endian Safe code */ 2348265236Sken sge_flags = sge->FlagsLength; 2349265236Sken sge->FlagsLength = htole32(sge_flags); 2350265236Sken sge->Address.High = htole32(sge->Address.High); 2351265236Sken sge->Address.Low = htole32(sge->Address.Low); 2352265236Sken bcopy(sge, cm->cm_sge, len); 2353265236Sken cm->cm_sge = (MPI2_SGE_IO_UNION *)((uintptr_t)cm->cm_sge + len); 2354265236Sken return (0); 2355265236Sken} 2356265236Sken 2357265236Sken/* 2358265236Sken * Add one IEEE scatter-gather element (chain or simple) to the IEEE scatter- 2359265236Sken * gather list for a command. Maintain cm_sglsize and cm_sge as the 2360265236Sken * remaining size and pointer to the next SGE to fill in, respectively. 2361265236Sken */ 2362265236Skenint 2363265236Skenmpr_push_ieee_sge(struct mpr_command *cm, void *sgep, int segsleft) 2364265236Sken{ 2365265236Sken MPI2_IEEE_SGE_SIMPLE64 *sge = sgep; 2366265236Sken int error, ieee_sge_size = sizeof(MPI25_SGE_IO_UNION); 2367265236Sken uint32_t saved_buf_len, saved_address_low, saved_address_high; 2368265236Sken uint32_t sge_length; 2369265236Sken 2370265236Sken /* 2371265236Sken * case 1: No room for chain or segment (error). 2372265236Sken * case 2: Two or more segments left but only room for chain. 2373265236Sken * case 3: Last segment and room for it, so set flags. 2374265236Sken */ 2375265236Sken 2376265236Sken /* 2377265236Sken * There should be room for at least one element, or there is a big 2378265236Sken * problem. 2379265236Sken */ 2380265236Sken if (cm->cm_sglsize < ieee_sge_size) 2381265236Sken panic("MPR: Need SGE Error Code\n"); 2382265236Sken 2383265236Sken if ((segsleft >= 2) && (cm->cm_sglsize < (ieee_sge_size * 2))) { 2384265236Sken if ((error = mpr_add_chain(cm, segsleft)) != 0) 2385265236Sken return (error); 2386265236Sken } 2387265236Sken 2388265236Sken if (segsleft == 1) { 2389265236Sken /* 2390265236Sken * If this is a bi-directional request, need to account for that 2391265236Sken * here. Save the pre-filled sge values. These will be used 2392265236Sken * either for the 2nd SGL or for a single direction SGL. If 2393265236Sken * cm_out_len is non-zero, this is a bi-directional request, so 2394265236Sken * fill in the OUT SGL first, then the IN SGL, otherwise just 2395265236Sken * fill in the IN SGL. Note that at this time, when filling in 2396265236Sken * 2 SGL's for a bi-directional request, they both use the same 2397265236Sken * DMA buffer (same cm command). 2398265236Sken */ 2399265236Sken saved_buf_len = sge->Length; 2400265236Sken saved_address_low = sge->Address.Low; 2401265236Sken saved_address_high = sge->Address.High; 2402265236Sken if (cm->cm_out_len) { 2403265236Sken sge->Length = cm->cm_out_len; 2404265236Sken sge->Flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | 2405265236Sken MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR); 2406265236Sken cm->cm_sglsize -= ieee_sge_size; 2407265236Sken /* Endian Safe code */ 2408265236Sken sge_length = sge->Length; 2409265236Sken sge->Length = htole32(sge_length); 2410265236Sken sge->Address.High = htole32(sge->Address.High); 2411265236Sken sge->Address.Low = htole32(sge->Address.Low); 2412265236Sken bcopy(sgep, cm->cm_sge, ieee_sge_size); 2413265236Sken cm->cm_sge = 2414265236Sken (MPI25_SGE_IO_UNION *)((uintptr_t)cm->cm_sge + 2415265236Sken ieee_sge_size); 2416265236Sken } 2417265236Sken sge->Length = saved_buf_len; 2418265236Sken sge->Flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | 2419265236Sken MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR | 2420265236Sken MPI25_IEEE_SGE_FLAGS_END_OF_LIST); 2421265236Sken sge->Address.Low = saved_address_low; 2422265236Sken sge->Address.High = saved_address_high; 2423265236Sken } 2424265236Sken 2425265236Sken cm->cm_sglsize -= ieee_sge_size; 2426265236Sken /* Endian Safe code */ 2427265236Sken sge_length = sge->Length; 2428265236Sken sge->Length = htole32(sge_length); 2429265236Sken sge->Address.High = htole32(sge->Address.High); 2430265236Sken sge->Address.Low = htole32(sge->Address.Low); 2431265236Sken bcopy(sgep, cm->cm_sge, ieee_sge_size); 2432265236Sken cm->cm_sge = (MPI25_SGE_IO_UNION *)((uintptr_t)cm->cm_sge + 2433265236Sken ieee_sge_size); 2434265236Sken return (0); 2435265236Sken} 2436265236Sken 2437265236Sken/* 2438265236Sken * Add one dma segment to the scatter-gather list for a command. 2439265236Sken */ 2440265236Skenint 2441265236Skenmpr_add_dmaseg(struct mpr_command *cm, vm_paddr_t pa, size_t len, u_int flags, 2442265236Sken int segsleft) 2443265236Sken{ 2444265236Sken MPI2_SGE_SIMPLE64 sge; 2445265236Sken MPI2_IEEE_SGE_SIMPLE64 ieee_sge; 2446265236Sken 2447265236Sken if (!(cm->cm_flags & MPR_CM_FLAGS_SGE_SIMPLE)) { 2448265236Sken ieee_sge.Flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | 2449265236Sken MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR); 2450265236Sken ieee_sge.Length = len; 2451265236Sken mpr_from_u64(pa, &ieee_sge.Address); 2452265236Sken 2453265236Sken return (mpr_push_ieee_sge(cm, &ieee_sge, segsleft)); 2454265236Sken } else { 2455265236Sken /* 2456265236Sken * This driver always uses 64-bit address elements for 2457265236Sken * simplicity. 2458265236Sken */ 2459265236Sken flags |= MPI2_SGE_FLAGS_SIMPLE_ELEMENT | 2460265236Sken MPI2_SGE_FLAGS_64_BIT_ADDRESSING; 2461265236Sken /* Set Endian safe macro in mpr_push_sge */ 2462265236Sken sge.FlagsLength = len | (flags << MPI2_SGE_FLAGS_SHIFT); 2463265236Sken mpr_from_u64(pa, &sge.Address); 2464265236Sken 2465265236Sken return (mpr_push_sge(cm, &sge, sizeof sge, segsleft)); 2466265236Sken } 2467265236Sken} 2468265236Sken 2469265236Skenstatic void 2470265236Skenmpr_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 2471265236Sken{ 2472265236Sken struct mpr_softc *sc; 2473265236Sken struct mpr_command *cm; 2474265236Sken u_int i, dir, sflags; 2475265236Sken 2476265236Sken cm = (struct mpr_command *)arg; 2477265236Sken sc = cm->cm_sc; 2478265236Sken 2479265236Sken /* 2480265236Sken * In this case, just print out a warning and let the chip tell the 2481265236Sken * user they did the wrong thing. 2482265236Sken */ 2483265236Sken if ((cm->cm_max_segs != 0) && (nsegs > cm->cm_max_segs)) { 2484299265Sslm mpr_dprint(sc, MPR_ERROR, "%s: warning: busdma returned %d " 2485299265Sslm "segments, more than the %d allowed\n", __func__, nsegs, 2486299265Sslm cm->cm_max_segs); 2487265236Sken } 2488265236Sken 2489265236Sken /* 2490265236Sken * Set up DMA direction flags. Bi-directional requests are also handled 2491265236Sken * here. In that case, both direction flags will be set. 2492265236Sken */ 2493265236Sken sflags = 0; 2494265236Sken if (cm->cm_flags & MPR_CM_FLAGS_SMP_PASS) { 2495265236Sken /* 2496265236Sken * We have to add a special case for SMP passthrough, there 2497265236Sken * is no easy way to generically handle it. The first 2498265236Sken * S/G element is used for the command (therefore the 2499265236Sken * direction bit needs to be set). The second one is used 2500265236Sken * for the reply. We'll leave it to the caller to make 2501265236Sken * sure we only have two buffers. 2502265236Sken */ 2503265236Sken /* 2504265236Sken * Even though the busdma man page says it doesn't make 2505265236Sken * sense to have both direction flags, it does in this case. 2506265236Sken * We have one s/g element being accessed in each direction. 2507265236Sken */ 2508265236Sken dir = BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD; 2509265236Sken 2510265236Sken /* 2511265236Sken * Set the direction flag on the first buffer in the SMP 2512265236Sken * passthrough request. We'll clear it for the second one. 2513265236Sken */ 2514265236Sken sflags |= MPI2_SGE_FLAGS_DIRECTION | 2515265236Sken MPI2_SGE_FLAGS_END_OF_BUFFER; 2516265236Sken } else if (cm->cm_flags & MPR_CM_FLAGS_DATAOUT) { 2517265236Sken sflags |= MPI2_SGE_FLAGS_HOST_TO_IOC; 2518265236Sken dir = BUS_DMASYNC_PREWRITE; 2519265236Sken } else 2520265236Sken dir = BUS_DMASYNC_PREREAD; 2521265236Sken 2522265236Sken for (i = 0; i < nsegs; i++) { 2523265236Sken if ((cm->cm_flags & MPR_CM_FLAGS_SMP_PASS) && (i != 0)) { 2524265236Sken sflags &= ~MPI2_SGE_FLAGS_DIRECTION; 2525265236Sken } 2526265236Sken error = mpr_add_dmaseg(cm, segs[i].ds_addr, segs[i].ds_len, 2527265236Sken sflags, nsegs - i); 2528265236Sken if (error != 0) { 2529265236Sken /* Resource shortage, roll back! */ 2530265236Sken if (ratecheck(&sc->lastfail, &mpr_chainfail_interval)) 2531265236Sken mpr_dprint(sc, MPR_INFO, "Out of chain frames, " 2532265236Sken "consider increasing hw.mpr.max_chains.\n"); 2533265236Sken cm->cm_flags |= MPR_CM_FLAGS_CHAIN_FAILED; 2534265236Sken mpr_complete_command(sc, cm); 2535265236Sken return; 2536265236Sken } 2537265236Sken } 2538265236Sken 2539265236Sken bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir); 2540265236Sken mpr_enqueue_request(sc, cm); 2541265236Sken 2542265236Sken return; 2543265236Sken} 2544265236Sken 2545265236Skenstatic void 2546265236Skenmpr_data_cb2(void *arg, bus_dma_segment_t *segs, int nsegs, bus_size_t mapsize, 2547265236Sken int error) 2548265236Sken{ 2549265236Sken mpr_data_cb(arg, segs, nsegs, error); 2550265236Sken} 2551265236Sken 2552265236Sken/* 2553265236Sken * This is the routine to enqueue commands ansynchronously. 2554265236Sken * Note that the only error path here is from bus_dmamap_load(), which can 2555265236Sken * return EINPROGRESS if it is waiting for resources. Other than this, it's 2556265236Sken * assumed that if you have a command in-hand, then you have enough credits 2557265236Sken * to use it. 2558265236Sken */ 2559265236Skenint 2560265236Skenmpr_map_command(struct mpr_softc *sc, struct mpr_command *cm) 2561265236Sken{ 2562265236Sken int error = 0; 2563265236Sken 2564265236Sken if (cm->cm_flags & MPR_CM_FLAGS_USE_UIO) { 2565265236Sken error = bus_dmamap_load_uio(sc->buffer_dmat, cm->cm_dmamap, 2566265236Sken &cm->cm_uio, mpr_data_cb2, cm, 0); 2567265236Sken } else if (cm->cm_flags & MPR_CM_FLAGS_USE_CCB) { 2568265236Sken error = bus_dmamap_load_ccb(sc->buffer_dmat, cm->cm_dmamap, 2569265236Sken cm->cm_data, mpr_data_cb, cm, 0); 2570265236Sken } else if ((cm->cm_data != NULL) && (cm->cm_length != 0)) { 2571265236Sken error = bus_dmamap_load(sc->buffer_dmat, cm->cm_dmamap, 2572265236Sken cm->cm_data, cm->cm_length, mpr_data_cb, cm, 0); 2573265236Sken } else { 2574265236Sken /* Add a zero-length element as needed */ 2575265236Sken if (cm->cm_sge != NULL) 2576265236Sken mpr_add_dmaseg(cm, 0, 0, 0, 1); 2577265236Sken mpr_enqueue_request(sc, cm); 2578265236Sken } 2579265236Sken 2580265236Sken return (error); 2581265236Sken} 2582265236Sken 2583265236Sken/* 2584265236Sken * This is the routine to enqueue commands synchronously. An error of 2585265236Sken * EINPROGRESS from mpr_map_command() is ignored since the command will 2586265236Sken * be executed and enqueued automatically. Other errors come from msleep(). 2587265236Sken */ 2588265236Skenint 2589265236Skenmpr_wait_command(struct mpr_softc *sc, struct mpr_command *cm, int timeout, 2590265236Sken int sleep_flag) 2591265236Sken{ 2592265236Sken int error, rc; 2593265236Sken struct timeval cur_time, start_time; 2594265236Sken 2595265236Sken if (sc->mpr_flags & MPR_FLAGS_DIAGRESET) 2596265236Sken return EBUSY; 2597265236Sken 2598265236Sken cm->cm_complete = NULL; 2599265236Sken cm->cm_flags |= (MPR_CM_FLAGS_WAKEUP + MPR_CM_FLAGS_POLLED); 2600265236Sken error = mpr_map_command(sc, cm); 2601265236Sken if ((error != 0) && (error != EINPROGRESS)) 2602265236Sken return (error); 2603265236Sken 2604265236Sken // Check for context and wait for 50 mSec at a time until time has 2605265236Sken // expired or the command has finished. If msleep can't be used, need 2606265236Sken // to poll. 2607265236Sken#if __FreeBSD_version >= 1000029 2608265236Sken if (curthread->td_no_sleeping) 2609265236Sken#else //__FreeBSD_version < 1000029 2610265236Sken if (curthread->td_pflags & TDP_NOSLEEPING) 2611265236Sken#endif //__FreeBSD_version >= 1000029 2612265236Sken sleep_flag = NO_SLEEP; 2613265236Sken getmicrotime(&start_time); 2614265236Sken if (mtx_owned(&sc->mpr_mtx) && sleep_flag == CAN_SLEEP) { 2615265236Sken error = msleep(cm, &sc->mpr_mtx, 0, "mprwait", timeout*hz); 2616265236Sken } else { 2617265236Sken while ((cm->cm_flags & MPR_CM_FLAGS_COMPLETE) == 0) { 2618265236Sken mpr_intr_locked(sc); 2619265236Sken if (sleep_flag == CAN_SLEEP) 2620265236Sken pause("mprwait", hz/20); 2621265236Sken else 2622265236Sken DELAY(50000); 2623265236Sken 2624265236Sken getmicrotime(&cur_time); 2625265236Sken if ((cur_time.tv_sec - start_time.tv_sec) > timeout) { 2626265236Sken error = EWOULDBLOCK; 2627265236Sken break; 2628265236Sken } 2629265236Sken } 2630265236Sken } 2631265236Sken 2632265236Sken if (error == EWOULDBLOCK) { 2633265236Sken mpr_dprint(sc, MPR_FAULT, "Calling Reinit from %s\n", __func__); 2634265236Sken rc = mpr_reinit(sc); 2635265236Sken mpr_dprint(sc, MPR_FAULT, "Reinit %s\n", (rc == 0) ? "success" : 2636265236Sken "failed"); 2637265236Sken error = ETIMEDOUT; 2638265236Sken } 2639265236Sken return (error); 2640265236Sken} 2641265236Sken 2642265236Sken/* 2643265236Sken * This is the routine to enqueue a command synchonously and poll for 2644265236Sken * completion. Its use should be rare. 2645265236Sken */ 2646265236Skenint 2647265236Skenmpr_request_polled(struct mpr_softc *sc, struct mpr_command *cm) 2648265236Sken{ 2649265236Sken int error, timeout = 0, rc; 2650265236Sken struct timeval cur_time, start_time; 2651265236Sken 2652265236Sken error = 0; 2653265236Sken 2654265236Sken cm->cm_flags |= MPR_CM_FLAGS_POLLED; 2655265236Sken cm->cm_complete = NULL; 2656265236Sken mpr_map_command(sc, cm); 2657265236Sken 2658265236Sken getmicrotime(&start_time); 2659265236Sken while ((cm->cm_flags & MPR_CM_FLAGS_COMPLETE) == 0) { 2660265236Sken mpr_intr_locked(sc); 2661265236Sken 2662265236Sken if (mtx_owned(&sc->mpr_mtx)) 2663265236Sken msleep(&sc->msleep_fake_chan, &sc->mpr_mtx, 0, 2664265236Sken "mprpoll", hz/20); 2665265236Sken else 2666265236Sken pause("mprpoll", hz/20); 2667265236Sken 2668265236Sken /* 2669265236Sken * Check for real-time timeout and fail if more than 60 seconds. 2670265236Sken */ 2671265236Sken getmicrotime(&cur_time); 2672265236Sken timeout = cur_time.tv_sec - start_time.tv_sec; 2673265236Sken if (timeout > 60) { 2674265236Sken mpr_dprint(sc, MPR_FAULT, "polling failed\n"); 2675265236Sken error = ETIMEDOUT; 2676265236Sken break; 2677265236Sken } 2678265236Sken } 2679265236Sken 2680283661Sslm if (error) { 2681265236Sken mpr_dprint(sc, MPR_FAULT, "Calling Reinit from %s\n", __func__); 2682265236Sken rc = mpr_reinit(sc); 2683299265Sslm mpr_dprint(sc, MPR_FAULT, "Reinit %s\n", (rc == 0) ? "success" : 2684299265Sslm "failed"); 2685265236Sken } 2686265236Sken return (error); 2687265236Sken} 2688265236Sken 2689265236Sken/* 2690265236Sken * The MPT driver had a verbose interface for config pages. In this driver, 2691298955Spfg * reduce it to much simpler terms, similar to the Linux driver. 2692265236Sken */ 2693265236Skenint 2694265236Skenmpr_read_config_page(struct mpr_softc *sc, struct mpr_config_params *params) 2695265236Sken{ 2696265236Sken MPI2_CONFIG_REQUEST *req; 2697265236Sken struct mpr_command *cm; 2698265236Sken int error; 2699265236Sken 2700265236Sken if (sc->mpr_flags & MPR_FLAGS_BUSY) { 2701265236Sken return (EBUSY); 2702265236Sken } 2703265236Sken 2704265236Sken cm = mpr_alloc_command(sc); 2705265236Sken if (cm == NULL) { 2706265236Sken return (EBUSY); 2707265236Sken } 2708265236Sken 2709265236Sken req = (MPI2_CONFIG_REQUEST *)cm->cm_req; 2710265236Sken req->Function = MPI2_FUNCTION_CONFIG; 2711265236Sken req->Action = params->action; 2712265236Sken req->SGLFlags = 0; 2713265236Sken req->ChainOffset = 0; 2714265236Sken req->PageAddress = params->page_address; 2715265236Sken if (params->hdr.Struct.PageType == MPI2_CONFIG_PAGETYPE_EXTENDED) { 2716265236Sken MPI2_CONFIG_EXTENDED_PAGE_HEADER *hdr; 2717265236Sken 2718265236Sken hdr = ¶ms->hdr.Ext; 2719265236Sken req->ExtPageType = hdr->ExtPageType; 2720265236Sken req->ExtPageLength = hdr->ExtPageLength; 2721265236Sken req->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; 2722265236Sken req->Header.PageLength = 0; /* Must be set to zero */ 2723265236Sken req->Header.PageNumber = hdr->PageNumber; 2724265236Sken req->Header.PageVersion = hdr->PageVersion; 2725265236Sken } else { 2726265236Sken MPI2_CONFIG_PAGE_HEADER *hdr; 2727265236Sken 2728265236Sken hdr = ¶ms->hdr.Struct; 2729265236Sken req->Header.PageType = hdr->PageType; 2730265236Sken req->Header.PageNumber = hdr->PageNumber; 2731265236Sken req->Header.PageLength = hdr->PageLength; 2732265236Sken req->Header.PageVersion = hdr->PageVersion; 2733265236Sken } 2734265236Sken 2735265236Sken cm->cm_data = params->buffer; 2736265236Sken cm->cm_length = params->length; 2737283661Sslm if (cm->cm_data != NULL) { 2738283661Sslm cm->cm_sge = &req->PageBufferSGE; 2739283661Sslm cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); 2740283661Sslm cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE | MPR_CM_FLAGS_DATAIN; 2741283661Sslm } else 2742283661Sslm cm->cm_sge = NULL; 2743265236Sken cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 2744265236Sken 2745265236Sken cm->cm_complete_data = params; 2746265236Sken if (params->callback != NULL) { 2747265236Sken cm->cm_complete = mpr_config_complete; 2748265236Sken return (mpr_map_command(sc, cm)); 2749265236Sken } else { 2750265236Sken error = mpr_wait_command(sc, cm, 0, CAN_SLEEP); 2751265236Sken if (error) { 2752265236Sken mpr_dprint(sc, MPR_FAULT, 2753265236Sken "Error %d reading config page\n", error); 2754265236Sken mpr_free_command(sc, cm); 2755265236Sken return (error); 2756265236Sken } 2757265236Sken mpr_config_complete(sc, cm); 2758265236Sken } 2759265236Sken 2760265236Sken return (0); 2761265236Sken} 2762265236Sken 2763265236Skenint 2764265236Skenmpr_write_config_page(struct mpr_softc *sc, struct mpr_config_params *params) 2765265236Sken{ 2766265236Sken return (EINVAL); 2767265236Sken} 2768265236Sken 2769265236Skenstatic void 2770265236Skenmpr_config_complete(struct mpr_softc *sc, struct mpr_command *cm) 2771265236Sken{ 2772265236Sken MPI2_CONFIG_REPLY *reply; 2773265236Sken struct mpr_config_params *params; 2774265236Sken 2775265236Sken MPR_FUNCTRACE(sc); 2776265236Sken params = cm->cm_complete_data; 2777265236Sken 2778265236Sken if (cm->cm_data != NULL) { 2779265236Sken bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, 2780265236Sken BUS_DMASYNC_POSTREAD); 2781265236Sken bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap); 2782265236Sken } 2783265236Sken 2784265236Sken /* 2785265236Sken * XXX KDM need to do more error recovery? This results in the 2786265236Sken * device in question not getting probed. 2787265236Sken */ 2788265236Sken if ((cm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 2789265236Sken params->status = MPI2_IOCSTATUS_BUSY; 2790265236Sken goto done; 2791265236Sken } 2792265236Sken 2793265236Sken reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; 2794265236Sken if (reply == NULL) { 2795265236Sken params->status = MPI2_IOCSTATUS_BUSY; 2796265236Sken goto done; 2797265236Sken } 2798265236Sken params->status = reply->IOCStatus; 2799283661Sslm if (params->hdr.Struct.PageType == MPI2_CONFIG_PAGETYPE_EXTENDED) { 2800265236Sken params->hdr.Ext.ExtPageType = reply->ExtPageType; 2801265236Sken params->hdr.Ext.ExtPageLength = reply->ExtPageLength; 2802283661Sslm params->hdr.Ext.PageType = reply->Header.PageType; 2803283661Sslm params->hdr.Ext.PageNumber = reply->Header.PageNumber; 2804283661Sslm params->hdr.Ext.PageVersion = reply->Header.PageVersion; 2805265236Sken } else { 2806265236Sken params->hdr.Struct.PageType = reply->Header.PageType; 2807265236Sken params->hdr.Struct.PageNumber = reply->Header.PageNumber; 2808265236Sken params->hdr.Struct.PageLength = reply->Header.PageLength; 2809265236Sken params->hdr.Struct.PageVersion = reply->Header.PageVersion; 2810265236Sken } 2811265236Sken 2812265236Skendone: 2813265236Sken mpr_free_command(sc, cm); 2814265236Sken if (params->callback != NULL) 2815265236Sken params->callback(sc, params); 2816265236Sken 2817265236Sken return; 2818265236Sken} 2819