1212420Sken/*- 2212420Sken * Copyright (c) 2009 Yahoo! Inc. 3237683Sken * Copyright (c) 2012 LSI Corp. 4212420Sken * All rights reserved. 5212420Sken * 6212420Sken * Redistribution and use in source and binary forms, with or without 7212420Sken * modification, are permitted provided that the following conditions 8212420Sken * are met: 9212420Sken * 1. Redistributions of source code must retain the above copyright 10212420Sken * notice, this list of conditions and the following disclaimer. 11212420Sken * 2. Redistributions in binary form must reproduce the above copyright 12212420Sken * notice, this list of conditions and the following disclaimer in the 13212420Sken * documentation and/or other materials provided with the distribution. 14212420Sken * 15212420Sken * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16212420Sken * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17212420Sken * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18212420Sken * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19212420Sken * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20212420Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21212420Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22212420Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23212420Sken * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24212420Sken * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25212420Sken * SUCH DAMAGE. 26230592Sken * 27230592Sken * LSI MPT-Fusion Host Adapter FreeBSD 28230592Sken * 29230592Sken * $FreeBSD$ 30230592Sken */ 31212420Sken 32212420Sken#include <sys/cdefs.h> 33212420Sken__FBSDID("$FreeBSD$"); 34212420Sken 35212420Sken/* Communications core for LSI MPT2 */ 36212420Sken 37230592Sken/* TODO Move headers to mpsvar */ 38212420Sken#include <sys/types.h> 39212420Sken#include <sys/param.h> 40212420Sken#include <sys/systm.h> 41212420Sken#include <sys/kernel.h> 42212420Sken#include <sys/selinfo.h> 43212420Sken#include <sys/lock.h> 44212420Sken#include <sys/mutex.h> 45212420Sken#include <sys/module.h> 46212420Sken#include <sys/bus.h> 47212420Sken#include <sys/conf.h> 48212420Sken#include <sys/bio.h> 49212420Sken#include <sys/malloc.h> 50212420Sken#include <sys/uio.h> 51212420Sken#include <sys/sysctl.h> 52230592Sken#include <sys/queue.h> 53230592Sken#include <sys/kthread.h> 54253550Sken#include <sys/taskqueue.h> 55216363Sken#include <sys/endian.h> 56230592Sken#include <sys/eventhandler.h> 57212420Sken 58212420Sken#include <machine/bus.h> 59212420Sken#include <machine/resource.h> 60212420Sken#include <sys/rman.h> 61237683Sken#include <sys/proc.h> 62212420Sken 63230592Sken#include <dev/pci/pcivar.h> 64230592Sken 65253550Sken#include <cam/cam.h> 66212420Sken#include <cam/scsi/scsi_all.h> 67212420Sken 68212420Sken#include <dev/mps/mpi/mpi2_type.h> 69212420Sken#include <dev/mps/mpi/mpi2.h> 70212420Sken#include <dev/mps/mpi/mpi2_ioc.h> 71230592Sken#include <dev/mps/mpi/mpi2_sas.h> 72212420Sken#include <dev/mps/mpi/mpi2_cnfg.h> 73230592Sken#include <dev/mps/mpi/mpi2_init.h> 74230592Sken#include <dev/mps/mpi/mpi2_tool.h> 75230592Sken#include <dev/mps/mps_ioctl.h> 76212420Sken#include <dev/mps/mpsvar.h> 77212420Sken#include <dev/mps/mps_table.h> 78253550Sken#include <dev/mps/mps_sas.h> 79212420Sken 80237683Skenstatic int mps_diag_reset(struct mps_softc *sc, int sleep_flag); 81230592Skenstatic int mps_init_queues(struct mps_softc *sc); 82237683Skenstatic int mps_message_unit_reset(struct mps_softc *sc, int sleep_flag); 83230592Skenstatic int mps_transition_operational(struct mps_softc *sc); 84253550Skenstatic int mps_iocfacts_allocate(struct mps_softc *sc, uint8_t attaching); 85253550Skenstatic void mps_iocfacts_free(struct mps_softc *sc); 86212420Skenstatic void mps_startup(void *arg); 87212420Skenstatic int mps_send_iocinit(struct mps_softc *sc); 88253550Skenstatic int mps_alloc_queues(struct mps_softc *sc); 89253550Skenstatic int mps_alloc_replies(struct mps_softc *sc); 90253550Skenstatic int mps_alloc_requests(struct mps_softc *sc); 91212420Skenstatic int mps_attach_log(struct mps_softc *sc); 92253460Sscottlstatic __inline void mps_complete_command(struct mps_softc *sc, 93253460Sscottl struct mps_command *cm); 94230592Skenstatic void mps_dispatch_event(struct mps_softc *sc, uintptr_t data, 95230592Sken MPI2_EVENT_NOTIFICATION_REPLY *reply); 96212420Skenstatic void mps_config_complete(struct mps_softc *sc, struct mps_command *cm); 97212420Skenstatic void mps_periodic(void *); 98230592Skenstatic int mps_reregister_events(struct mps_softc *sc); 99230592Skenstatic void mps_enqueue_request(struct mps_softc *sc, struct mps_command *cm); 100253550Skenstatic int mps_get_iocfacts(struct mps_softc *sc, MPI2_IOC_FACTS_REPLY *facts); 101237683Skenstatic int mps_wait_db_ack(struct mps_softc *sc, int timeout, int sleep_flag); 102212420SkenSYSCTL_NODE(_hw, OID_AUTO, mps, CTLFLAG_RD, 0, "MPS Driver Parameters"); 103212420Sken 104212420SkenMALLOC_DEFINE(M_MPT2, "mps", "mpt2 driver memory"); 105212420Sken 106212420Sken/* 107212420Sken * Do a "Diagnostic Reset" aka a hard reset. This should get the chip out of 108212420Sken * any state and back to its initialization state machine. 109212420Sken */ 110212420Skenstatic char mpt2_reset_magic[] = { 0x00, 0x0f, 0x04, 0x0b, 0x02, 0x07, 0x0d }; 111212420Sken 112237683Sken/* Added this union to smoothly convert le64toh cm->cm_desc.Words. 113237683Sken * Compiler only support unint64_t to be passed as argument. 114237683Sken * Otherwise it will through below error 115237683Sken * "aggregate value used where an integer was expected" 116237683Sken */ 117237683Sken 118237683Skentypedef union _reply_descriptor { 119237683Sken u64 word; 120237683Sken struct { 121237683Sken u32 low; 122237683Sken u32 high; 123237683Sken } u; 124237683Sken}reply_descriptor,address_descriptor; 125237683Sken 126254117Sscottl/* Rate limit chain-fail messages to 1 per minute */ 127254117Sscottlstatic struct timeval mps_chainfail_interval = { 60, 0 }; 128254117Sscottl 129237683Sken/* 130237683Sken * sleep_flag can be either CAN_SLEEP or NO_SLEEP. 131237683Sken * If this function is called from process context, it can sleep 132237683Sken * and there is no harm to sleep, in case if this fuction is called 133237683Sken * from Interrupt handler, we can not sleep and need NO_SLEEP flag set. 134237683Sken * based on sleep flags driver will call either msleep, pause or DELAY. 135237683Sken * msleep and pause are of same variant, but pause is used when mps_mtx 136237683Sken * is not hold by driver. 137237683Sken * 138237683Sken */ 139212420Skenstatic int 140237683Skenmps_diag_reset(struct mps_softc *sc,int sleep_flag) 141212420Sken{ 142212420Sken uint32_t reg; 143212420Sken int i, error, tries = 0; 144212420Sken 145212420Sken mps_dprint(sc, MPS_TRACE, "%s\n", __func__); 146212420Sken 147212420Sken /* Clear any pending interrupts */ 148212420Sken mps_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); 149212420Sken 150237683Sken /*Force NO_SLEEP for threads prohibited to sleep 151237683Sken * e.a Thread from interrupt handler are prohibited to sleep. 152247588Sjhb */ 153247588Sjhb if (curthread->td_no_sleeping != 0) 154237683Sken sleep_flag = NO_SLEEP; 155237683Sken 156212420Sken /* Push the magic sequence */ 157212420Sken error = ETIMEDOUT; 158212420Sken while (tries++ < 20) { 159212420Sken for (i = 0; i < sizeof(mpt2_reset_magic); i++) 160212420Sken mps_regwrite(sc, MPI2_WRITE_SEQUENCE_OFFSET, 161212420Sken mpt2_reset_magic[i]); 162237683Sken /* wait 100 msec */ 163237683Sken if (mtx_owned(&sc->mps_mtx) && sleep_flag == CAN_SLEEP) 164253550Sken msleep(&sc->msleep_fake_chan, &sc->mps_mtx, 0, 165253550Sken "mpsdiag", hz/10); 166237683Sken else if (sleep_flag == CAN_SLEEP) 167237683Sken pause("mpsdiag", hz/10); 168237683Sken else 169237683Sken DELAY(100 * 1000); 170212420Sken 171212420Sken reg = mps_regread(sc, MPI2_HOST_DIAGNOSTIC_OFFSET); 172212420Sken if (reg & MPI2_DIAG_DIAG_WRITE_ENABLE) { 173212420Sken error = 0; 174212420Sken break; 175212420Sken } 176212420Sken } 177212420Sken if (error) 178212420Sken return (error); 179212420Sken 180212420Sken /* Send the actual reset. XXX need to refresh the reg? */ 181212420Sken mps_regwrite(sc, MPI2_HOST_DIAGNOSTIC_OFFSET, 182212420Sken reg | MPI2_DIAG_RESET_ADAPTER); 183212420Sken 184212420Sken /* Wait up to 300 seconds in 50ms intervals */ 185212420Sken error = ETIMEDOUT; 186212420Sken for (i = 0; i < 60000; i++) { 187237683Sken /* wait 50 msec */ 188237683Sken if (mtx_owned(&sc->mps_mtx) && sleep_flag == CAN_SLEEP) 189253550Sken msleep(&sc->msleep_fake_chan, &sc->mps_mtx, 0, 190253550Sken "mpsdiag", hz/20); 191237683Sken else if (sleep_flag == CAN_SLEEP) 192237683Sken pause("mpsdiag", hz/20); 193237683Sken else 194237683Sken DELAY(50 * 1000); 195212420Sken reg = mps_regread(sc, MPI2_DOORBELL_OFFSET); 196212420Sken if ((reg & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_RESET) { 197212420Sken error = 0; 198212420Sken break; 199212420Sken } 200212420Sken } 201212420Sken if (error) 202212420Sken return (error); 203212420Sken 204212420Sken mps_regwrite(sc, MPI2_WRITE_SEQUENCE_OFFSET, 0x0); 205212420Sken 206212420Sken return (0); 207212420Sken} 208212420Sken 209212420Skenstatic int 210237683Skenmps_message_unit_reset(struct mps_softc *sc, int sleep_flag) 211212420Sken{ 212212420Sken 213253460Sscottl MPS_FUNCTRACE(sc); 214212420Sken 215212420Sken mps_regwrite(sc, MPI2_DOORBELL_OFFSET, 216212420Sken MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET << 217212420Sken MPI2_DOORBELL_FUNCTION_SHIFT); 218212420Sken 219237683Sken if (mps_wait_db_ack(sc, 5, sleep_flag) != 0) { 220237683Sken mps_dprint(sc, MPS_FAULT, "Doorbell handshake failed : <%s>\n", 221237683Sken __func__); 222237683Sken return (ETIMEDOUT); 223237683Sken } 224237683Sken 225212420Sken return (0); 226212420Sken} 227212420Sken 228212420Skenstatic int 229212420Skenmps_transition_ready(struct mps_softc *sc) 230212420Sken{ 231212420Sken uint32_t reg, state; 232212420Sken int error, tries = 0; 233237683Sken int sleep_flags; 234212420Sken 235253460Sscottl MPS_FUNCTRACE(sc); 236237683Sken /* If we are in attach call, do not sleep */ 237237683Sken sleep_flags = (sc->mps_flags & MPS_FLAGS_ATTACH_DONE) 238237683Sken ? CAN_SLEEP:NO_SLEEP; 239212420Sken error = 0; 240212420Sken while (tries++ < 5) { 241212420Sken reg = mps_regread(sc, MPI2_DOORBELL_OFFSET); 242253460Sscottl mps_dprint(sc, MPS_INIT, "Doorbell= 0x%x\n", reg); 243212420Sken 244212420Sken /* 245212420Sken * Ensure the IOC is ready to talk. If it's not, try 246212420Sken * resetting it. 247212420Sken */ 248212420Sken if (reg & MPI2_DOORBELL_USED) { 249237683Sken mps_diag_reset(sc, sleep_flags); 250212420Sken DELAY(50000); 251212420Sken continue; 252212420Sken } 253212420Sken 254212420Sken /* Is the adapter owned by another peer? */ 255212420Sken if ((reg & MPI2_DOORBELL_WHO_INIT_MASK) == 256212420Sken (MPI2_WHOINIT_PCI_PEER << MPI2_DOORBELL_WHO_INIT_SHIFT)) { 257212420Sken device_printf(sc->mps_dev, "IOC is under the control " 258212420Sken "of another peer host, aborting initialization.\n"); 259212420Sken return (ENXIO); 260212420Sken } 261212420Sken 262212420Sken state = reg & MPI2_IOC_STATE_MASK; 263212420Sken if (state == MPI2_IOC_STATE_READY) { 264212420Sken /* Ready to go! */ 265212420Sken error = 0; 266212420Sken break; 267212420Sken } else if (state == MPI2_IOC_STATE_FAULT) { 268253460Sscottl mps_dprint(sc, MPS_FAULT, "IOC in fault state 0x%x, resetting\n", 269212420Sken state & MPI2_DOORBELL_FAULT_CODE_MASK); 270237683Sken mps_diag_reset(sc, sleep_flags); 271212420Sken } else if (state == MPI2_IOC_STATE_OPERATIONAL) { 272212420Sken /* Need to take ownership */ 273237683Sken mps_message_unit_reset(sc, sleep_flags); 274212420Sken } else if (state == MPI2_IOC_STATE_RESET) { 275212420Sken /* Wait a bit, IOC might be in transition */ 276212420Sken mps_dprint(sc, MPS_FAULT, 277212420Sken "IOC in unexpected reset state\n"); 278212420Sken } else { 279212420Sken mps_dprint(sc, MPS_FAULT, 280212420Sken "IOC in unknown state 0x%x\n", state); 281212420Sken error = EINVAL; 282212420Sken break; 283212420Sken } 284212420Sken 285212420Sken /* Wait 50ms for things to settle down. */ 286212420Sken DELAY(50000); 287212420Sken } 288212420Sken 289212420Sken if (error) 290212420Sken device_printf(sc->mps_dev, "Cannot transition IOC to ready\n"); 291212420Sken 292212420Sken return (error); 293212420Sken} 294212420Sken 295212420Skenstatic int 296212420Skenmps_transition_operational(struct mps_softc *sc) 297212420Sken{ 298212420Sken uint32_t reg, state; 299212420Sken int error; 300212420Sken 301253460Sscottl MPS_FUNCTRACE(sc); 302212420Sken 303212420Sken error = 0; 304212420Sken reg = mps_regread(sc, MPI2_DOORBELL_OFFSET); 305253460Sscottl mps_dprint(sc, MPS_INIT, "Doorbell= 0x%x\n", reg); 306212420Sken 307212420Sken state = reg & MPI2_IOC_STATE_MASK; 308212420Sken if (state != MPI2_IOC_STATE_READY) { 309230592Sken if ((error = mps_transition_ready(sc)) != 0) { 310230592Sken mps_dprint(sc, MPS_FAULT, 311230592Sken "%s failed to transition ready\n", __func__); 312212420Sken return (error); 313230592Sken } 314212420Sken } 315212420Sken 316212420Sken error = mps_send_iocinit(sc); 317212420Sken return (error); 318212420Sken} 319212420Sken 320253550Sken/* 321253550Sken * This is called during attach and when re-initializing due to a Diag Reset. 322253550Sken * IOC Facts is used to allocate many of the structures needed by the driver. 323253550Sken * If called from attach, de-allocation is not required because the driver has 324253550Sken * not allocated any structures yet, but if called from a Diag Reset, previously 325253550Sken * allocated structures based on IOC Facts will need to be freed and re- 326253550Sken * allocated bases on the latest IOC Facts. 327253550Sken */ 328253550Skenstatic int 329253550Skenmps_iocfacts_allocate(struct mps_softc *sc, uint8_t attaching) 330253550Sken{ 331253550Sken int error, i; 332253550Sken Mpi2IOCFactsReply_t saved_facts; 333253550Sken uint8_t saved_mode, reallocating; 334253550Sken struct mpssas_lun *lun, *lun_tmp; 335253550Sken struct mpssas_target *targ; 336253550Sken 337253550Sken mps_dprint(sc, MPS_TRACE, "%s\n", __func__); 338253550Sken 339253550Sken /* Save old IOC Facts and then only reallocate if Facts have changed */ 340253550Sken if (!attaching) { 341253550Sken bcopy(sc->facts, &saved_facts, sizeof(MPI2_IOC_FACTS_REPLY)); 342253550Sken } 343253550Sken 344253550Sken /* 345253550Sken * Get IOC Facts. In all cases throughout this function, panic if doing 346253550Sken * a re-initialization and only return the error if attaching so the OS 347253550Sken * can handle it. 348253550Sken */ 349253550Sken if ((error = mps_get_iocfacts(sc, sc->facts)) != 0) { 350253550Sken if (attaching) { 351253550Sken mps_dprint(sc, MPS_FAULT, "%s failed to get IOC Facts " 352253550Sken "with error %d\n", __func__, error); 353253550Sken return (error); 354253550Sken } else { 355253550Sken panic("%s failed to get IOC Facts with error %d\n", 356253550Sken __func__, error); 357253550Sken } 358253550Sken } 359253550Sken 360253550Sken mps_print_iocfacts(sc, sc->facts); 361253550Sken 362253550Sken snprintf(sc->fw_version, sizeof(sc->fw_version), 363253550Sken "%02d.%02d.%02d.%02d", 364253550Sken sc->facts->FWVersion.Struct.Major, 365253550Sken sc->facts->FWVersion.Struct.Minor, 366253550Sken sc->facts->FWVersion.Struct.Unit, 367253550Sken sc->facts->FWVersion.Struct.Dev); 368253550Sken 369253550Sken mps_printf(sc, "Firmware: %s, Driver: %s\n", sc->fw_version, 370253550Sken MPS_DRIVER_VERSION); 371253550Sken mps_printf(sc, "IOCCapabilities: %b\n", sc->facts->IOCCapabilities, 372253550Sken "\20" "\3ScsiTaskFull" "\4DiagTrace" "\5SnapBuf" "\6ExtBuf" 373253550Sken "\7EEDP" "\10BiDirTarg" "\11Multicast" "\14TransRetry" "\15IR" 374253550Sken "\16EventReplay" "\17RaidAccel" "\20MSIXIndex" "\21HostDisc"); 375253550Sken 376253550Sken /* 377253550Sken * If the chip doesn't support event replay then a hard reset will be 378253550Sken * required to trigger a full discovery. Do the reset here then 379253550Sken * retransition to Ready. A hard reset might have already been done, 380253550Sken * but it doesn't hurt to do it again. Only do this if attaching, not 381253550Sken * for a Diag Reset. 382253550Sken */ 383253550Sken if (attaching) { 384253550Sken if ((sc->facts->IOCCapabilities & 385253550Sken MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY) == 0) { 386253550Sken mps_diag_reset(sc, NO_SLEEP); 387253550Sken if ((error = mps_transition_ready(sc)) != 0) { 388253550Sken mps_dprint(sc, MPS_FAULT, "%s failed to " 389253550Sken "transition to ready with error %d\n", 390253550Sken __func__, error); 391253550Sken return (error); 392253550Sken } 393253550Sken } 394253550Sken } 395253550Sken 396253550Sken /* 397253550Sken * Set flag if IR Firmware is loaded. If the RAID Capability has 398253550Sken * changed from the previous IOC Facts, log a warning, but only if 399253550Sken * checking this after a Diag Reset and not during attach. 400253550Sken */ 401253550Sken saved_mode = sc->ir_firmware; 402253550Sken if (sc->facts->IOCCapabilities & 403253550Sken MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) 404253550Sken sc->ir_firmware = 1; 405253550Sken if (!attaching) { 406253550Sken if (sc->ir_firmware != saved_mode) { 407253550Sken mps_dprint(sc, MPS_FAULT, "%s new IR/IT mode in IOC " 408253550Sken "Facts does not match previous mode\n", __func__); 409253550Sken } 410253550Sken } 411253550Sken 412253550Sken /* Only deallocate and reallocate if relevant IOC Facts have changed */ 413253550Sken reallocating = FALSE; 414253550Sken if ((!attaching) && 415253550Sken ((saved_facts.MsgVersion != sc->facts->MsgVersion) || 416253550Sken (saved_facts.HeaderVersion != sc->facts->HeaderVersion) || 417253550Sken (saved_facts.MaxChainDepth != sc->facts->MaxChainDepth) || 418253550Sken (saved_facts.RequestCredit != sc->facts->RequestCredit) || 419253550Sken (saved_facts.ProductID != sc->facts->ProductID) || 420253550Sken (saved_facts.IOCCapabilities != sc->facts->IOCCapabilities) || 421253550Sken (saved_facts.IOCRequestFrameSize != 422253550Sken sc->facts->IOCRequestFrameSize) || 423253550Sken (saved_facts.MaxTargets != sc->facts->MaxTargets) || 424253550Sken (saved_facts.MaxSasExpanders != sc->facts->MaxSasExpanders) || 425253550Sken (saved_facts.MaxEnclosures != sc->facts->MaxEnclosures) || 426253550Sken (saved_facts.HighPriorityCredit != sc->facts->HighPriorityCredit) || 427253550Sken (saved_facts.MaxReplyDescriptorPostQueueDepth != 428253550Sken sc->facts->MaxReplyDescriptorPostQueueDepth) || 429253550Sken (saved_facts.ReplyFrameSize != sc->facts->ReplyFrameSize) || 430253550Sken (saved_facts.MaxVolumes != sc->facts->MaxVolumes) || 431253550Sken (saved_facts.MaxPersistentEntries != 432253550Sken sc->facts->MaxPersistentEntries))) { 433253550Sken reallocating = TRUE; 434253550Sken } 435253550Sken 436253550Sken /* 437253550Sken * Some things should be done if attaching or re-allocating after a Diag 438253550Sken * Reset, but are not needed after a Diag Reset if the FW has not 439253550Sken * changed. 440253550Sken */ 441253550Sken if (attaching || reallocating) { 442253550Sken /* 443253550Sken * Check if controller supports FW diag buffers and set flag to 444253550Sken * enable each type. 445253550Sken */ 446253550Sken if (sc->facts->IOCCapabilities & 447253550Sken MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) 448253550Sken sc->fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_TRACE]. 449253550Sken enabled = TRUE; 450253550Sken if (sc->facts->IOCCapabilities & 451253550Sken MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) 452253550Sken sc->fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_SNAPSHOT]. 453253550Sken enabled = TRUE; 454253550Sken if (sc->facts->IOCCapabilities & 455253550Sken MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) 456253550Sken sc->fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_EXTENDED]. 457253550Sken enabled = TRUE; 458253550Sken 459253550Sken /* 460253550Sken * Set flag if EEDP is supported and if TLR is supported. 461253550Sken */ 462253550Sken if (sc->facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_EEDP) 463253550Sken sc->eedp_enabled = TRUE; 464253550Sken if (sc->facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR) 465253550Sken sc->control_TLR = TRUE; 466253550Sken 467253550Sken /* 468253550Sken * Size the queues. Since the reply queues always need one free 469253550Sken * entry, we'll just deduct one reply message here. 470253550Sken */ 471253550Sken sc->num_reqs = MIN(MPS_REQ_FRAMES, sc->facts->RequestCredit); 472253550Sken sc->num_replies = MIN(MPS_REPLY_FRAMES + MPS_EVT_REPLY_FRAMES, 473253550Sken sc->facts->MaxReplyDescriptorPostQueueDepth) - 1; 474253550Sken 475253550Sken /* 476253550Sken * Initialize all Tail Queues 477253550Sken */ 478253550Sken TAILQ_INIT(&sc->req_list); 479253550Sken TAILQ_INIT(&sc->high_priority_req_list); 480253550Sken TAILQ_INIT(&sc->chain_list); 481253550Sken TAILQ_INIT(&sc->tm_list); 482253550Sken } 483253550Sken 484253550Sken /* 485253550Sken * If doing a Diag Reset and the FW is significantly different 486253550Sken * (reallocating will be set above in IOC Facts comparison), then all 487253550Sken * buffers based on the IOC Facts will need to be freed before they are 488253550Sken * reallocated. 489253550Sken */ 490253550Sken if (reallocating) { 491253550Sken mps_iocfacts_free(sc); 492253550Sken 493253550Sken /* 494253550Sken * The number of targets is based on IOC Facts, so free all of 495253550Sken * the allocated LUNs for each target and then the target buffer 496253550Sken * itself. 497253550Sken */ 498253550Sken for (i=0; i< saved_facts.MaxTargets; i++) { 499253550Sken targ = &sc->sassc->targets[i]; 500253550Sken SLIST_FOREACH_SAFE(lun, &targ->luns, lun_link, 501253550Sken lun_tmp) { 502253550Sken free(lun, M_MPT2); 503253550Sken } 504253550Sken } 505253550Sken free(sc->sassc->targets, M_MPT2); 506253550Sken 507253550Sken sc->sassc->targets = malloc(sizeof(struct mpssas_target) * 508253550Sken sc->facts->MaxTargets, M_MPT2, M_WAITOK|M_ZERO); 509253550Sken if (!sc->sassc->targets) { 510253550Sken panic("%s failed to alloc targets with error %d\n", 511253550Sken __func__, ENOMEM); 512253550Sken } 513253550Sken } 514253550Sken 515253550Sken /* 516253550Sken * Any deallocation has been completed. Now start reallocating 517253550Sken * if needed. Will only need to reallocate if attaching or if the new 518253550Sken * IOC Facts are different from the previous IOC Facts after a Diag 519253550Sken * Reset. Targets have already been allocated above if needed. 520253550Sken */ 521253550Sken if (attaching || reallocating) { 522253550Sken if (((error = mps_alloc_queues(sc)) != 0) || 523253550Sken ((error = mps_alloc_replies(sc)) != 0) || 524253550Sken ((error = mps_alloc_requests(sc)) != 0)) { 525253550Sken if (attaching ) { 526253550Sken mps_dprint(sc, MPS_FAULT, "%s failed to alloc " 527253550Sken "queues with error %d\n", __func__, error); 528253550Sken mps_free(sc); 529253550Sken return (error); 530253550Sken } else { 531253550Sken panic("%s failed to alloc queues with error " 532253550Sken "%d\n", __func__, error); 533253550Sken } 534253550Sken } 535253550Sken } 536253550Sken 537253550Sken /* Always initialize the queues */ 538253550Sken bzero(sc->free_queue, sc->fqdepth * 4); 539253550Sken mps_init_queues(sc); 540253550Sken 541253550Sken /* 542253550Sken * Always get the chip out of the reset state, but only panic if not 543253550Sken * attaching. If attaching and there is an error, that is handled by 544253550Sken * the OS. 545253550Sken */ 546253550Sken error = mps_transition_operational(sc); 547253550Sken if (error != 0) { 548253550Sken if (attaching) { 549253550Sken mps_printf(sc, "%s failed to transition to operational " 550253550Sken "with error %d\n", __func__, error); 551253550Sken mps_free(sc); 552253550Sken return (error); 553253550Sken } else { 554253550Sken panic("%s failed to transition to operational with " 555253550Sken "error %d\n", __func__, error); 556253550Sken } 557253550Sken } 558253550Sken 559253550Sken /* 560253550Sken * Finish the queue initialization. 561253550Sken * These are set here instead of in mps_init_queues() because the 562253550Sken * IOC resets these values during the state transition in 563253550Sken * mps_transition_operational(). The free index is set to 1 564253550Sken * because the corresponding index in the IOC is set to 0, and the 565253550Sken * IOC treats the queues as full if both are set to the same value. 566253550Sken * Hence the reason that the queue can't hold all of the possible 567253550Sken * replies. 568253550Sken */ 569253550Sken sc->replypostindex = 0; 570253550Sken mps_regwrite(sc, MPI2_REPLY_FREE_HOST_INDEX_OFFSET, sc->replyfreeindex); 571253550Sken mps_regwrite(sc, MPI2_REPLY_POST_HOST_INDEX_OFFSET, 0); 572253550Sken 573253550Sken /* 574253550Sken * Attach the subsystems so they can prepare their event masks. 575253550Sken */ 576253550Sken /* XXX Should be dynamic so that IM/IR and user modules can attach */ 577253550Sken if (attaching) { 578253550Sken if (((error = mps_attach_log(sc)) != 0) || 579253550Sken ((error = mps_attach_sas(sc)) != 0) || 580253550Sken ((error = mps_attach_user(sc)) != 0)) { 581253550Sken mps_printf(sc, "%s failed to attach all subsystems: " 582253550Sken "error %d\n", __func__, error); 583253550Sken mps_free(sc); 584253550Sken return (error); 585253550Sken } 586253550Sken 587253550Sken if ((error = mps_pci_setup_interrupts(sc)) != 0) { 588253550Sken mps_printf(sc, "%s failed to setup interrupts\n", 589253550Sken __func__); 590253550Sken mps_free(sc); 591253550Sken return (error); 592253550Sken } 593253550Sken } 594253550Sken 595253550Sken /* 596253550Sken * Set flag if this is a WD controller. This shouldn't ever change, but 597253550Sken * reset it after a Diag Reset, just in case. 598253550Sken */ 599253550Sken sc->WD_available = FALSE; 600253550Sken if (pci_get_device(sc->mps_dev) == MPI2_MFGPAGE_DEVID_SSS6200) 601253550Sken sc->WD_available = TRUE; 602253550Sken 603253550Sken return (error); 604253550Sken} 605253550Sken 606253550Sken/* 607253550Sken * This is called if memory is being free (during detach for example) and when 608253550Sken * buffers need to be reallocated due to a Diag Reset. 609253550Sken */ 610253550Skenstatic void 611253550Skenmps_iocfacts_free(struct mps_softc *sc) 612253550Sken{ 613253550Sken struct mps_command *cm; 614253550Sken int i; 615253550Sken 616253550Sken mps_dprint(sc, MPS_TRACE, "%s\n", __func__); 617253550Sken 618253550Sken if (sc->post_busaddr != 0) 619253550Sken bus_dmamap_unload(sc->queues_dmat, sc->queues_map); 620253550Sken if (sc->post_queue != NULL) 621253550Sken bus_dmamem_free(sc->queues_dmat, sc->post_queue, 622253550Sken sc->queues_map); 623253550Sken if (sc->queues_dmat != NULL) 624253550Sken bus_dma_tag_destroy(sc->queues_dmat); 625253550Sken 626253550Sken if (sc->chain_busaddr != 0) 627253550Sken bus_dmamap_unload(sc->chain_dmat, sc->chain_map); 628253550Sken if (sc->chain_frames != NULL) 629253550Sken bus_dmamem_free(sc->chain_dmat, sc->chain_frames, 630253550Sken sc->chain_map); 631253550Sken if (sc->chain_dmat != NULL) 632253550Sken bus_dma_tag_destroy(sc->chain_dmat); 633253550Sken 634253550Sken if (sc->sense_busaddr != 0) 635253550Sken bus_dmamap_unload(sc->sense_dmat, sc->sense_map); 636253550Sken if (sc->sense_frames != NULL) 637253550Sken bus_dmamem_free(sc->sense_dmat, sc->sense_frames, 638253550Sken sc->sense_map); 639253550Sken if (sc->sense_dmat != NULL) 640253550Sken bus_dma_tag_destroy(sc->sense_dmat); 641253550Sken 642253550Sken if (sc->reply_busaddr != 0) 643253550Sken bus_dmamap_unload(sc->reply_dmat, sc->reply_map); 644253550Sken if (sc->reply_frames != NULL) 645253550Sken bus_dmamem_free(sc->reply_dmat, sc->reply_frames, 646253550Sken sc->reply_map); 647253550Sken if (sc->reply_dmat != NULL) 648253550Sken bus_dma_tag_destroy(sc->reply_dmat); 649253550Sken 650253550Sken if (sc->req_busaddr != 0) 651253550Sken bus_dmamap_unload(sc->req_dmat, sc->req_map); 652253550Sken if (sc->req_frames != NULL) 653253550Sken bus_dmamem_free(sc->req_dmat, sc->req_frames, sc->req_map); 654253550Sken if (sc->req_dmat != NULL) 655253550Sken bus_dma_tag_destroy(sc->req_dmat); 656253550Sken 657253550Sken if (sc->chains != NULL) 658253550Sken free(sc->chains, M_MPT2); 659253550Sken if (sc->commands != NULL) { 660253550Sken for (i = 1; i < sc->num_reqs; i++) { 661253550Sken cm = &sc->commands[i]; 662253550Sken bus_dmamap_destroy(sc->buffer_dmat, cm->cm_dmamap); 663253550Sken } 664253550Sken free(sc->commands, M_MPT2); 665253550Sken } 666253550Sken if (sc->buffer_dmat != NULL) 667253550Sken bus_dma_tag_destroy(sc->buffer_dmat); 668253550Sken} 669253550Sken 670230592Sken/* 671230592Sken * The terms diag reset and hard reset are used interchangeably in the MPI 672230592Sken * docs to mean resetting the controller chip. In this code diag reset 673230592Sken * cleans everything up, and the hard reset function just sends the reset 674230592Sken * sequence to the chip. This should probably be refactored so that every 675230592Sken * subsystem gets a reset notification of some sort, and can clean up 676230592Sken * appropriately. 677230592Sken */ 678230592Skenint 679230592Skenmps_reinit(struct mps_softc *sc) 680230592Sken{ 681230592Sken int error; 682230592Sken 683253460Sscottl MPS_FUNCTRACE(sc); 684230592Sken 685230592Sken mtx_assert(&sc->mps_mtx, MA_OWNED); 686230592Sken 687230592Sken if (sc->mps_flags & MPS_FLAGS_DIAGRESET) { 688253460Sscottl mps_dprint(sc, MPS_INIT, "%s reset already in progress\n", 689253460Sscottl __func__); 690230592Sken return 0; 691230592Sken } 692230592Sken 693253460Sscottl mps_dprint(sc, MPS_INFO, "Reinitializing controller,\n"); 694230592Sken /* make sure the completion callbacks can recognize they're getting 695230592Sken * a NULL cm_reply due to a reset. 696230592Sken */ 697230592Sken sc->mps_flags |= MPS_FLAGS_DIAGRESET; 698230592Sken 699253550Sken /* 700253550Sken * Mask interrupts here. 701253550Sken */ 702253460Sscottl mps_dprint(sc, MPS_INIT, "%s mask interrupts\n", __func__); 703230592Sken mps_mask_intr(sc); 704230592Sken 705237683Sken error = mps_diag_reset(sc, CAN_SLEEP); 706230592Sken if (error != 0) { 707253460Sscottl /* XXXSL No need to panic here */ 708230592Sken panic("%s hard reset failed with error %d\n", 709230592Sken __func__, error); 710230592Sken } 711230592Sken 712230592Sken /* Restore the PCI state, including the MSI-X registers */ 713230592Sken mps_pci_restore(sc); 714230592Sken 715230592Sken /* Give the I/O subsystem special priority to get itself prepared */ 716230592Sken mpssas_handle_reinit(sc); 717230592Sken 718253550Sken /* 719253550Sken * Get IOC Facts and allocate all structures based on this information. 720253550Sken * The attach function will also call mps_iocfacts_allocate at startup. 721253550Sken * If relevant values have changed in IOC Facts, this function will free 722253550Sken * all of the memory based on IOC Facts and reallocate that memory. 723253550Sken */ 724253550Sken if ((error = mps_iocfacts_allocate(sc, FALSE)) != 0) { 725253550Sken panic("%s IOC Facts based allocation failed with error %d\n", 726230592Sken __func__, error); 727253550Sken } 728230592Sken 729253550Sken /* 730253550Sken * Mapping structures will be re-allocated after getting IOC Page8, so 731253550Sken * free these structures here. 732230592Sken */ 733253550Sken mps_mapping_exit(sc); 734230592Sken 735253550Sken /* 736253550Sken * The static page function currently read is IOC Page8. Others can be 737253550Sken * added in future. It's possible that the values in IOC Page8 have 738253550Sken * changed after a Diag Reset due to user modification, so always read 739253550Sken * these. Interrupts are masked, so unmask them before getting config 740253550Sken * pages. 741253550Sken */ 742230592Sken mps_unmask_intr(sc); 743253550Sken sc->mps_flags &= ~MPS_FLAGS_DIAGRESET; 744253550Sken mps_base_static_config_pages(sc); 745230592Sken 746253550Sken /* 747253550Sken * Some mapping info is based in IOC Page8 data, so re-initialize the 748253550Sken * mapping tables. 749253550Sken */ 750253550Sken mps_mapping_initialize(sc); 751230592Sken 752253550Sken /* 753253550Sken * Restart will reload the event masks clobbered by the reset, and 754230592Sken * then enable the port. 755230592Sken */ 756230592Sken mps_reregister_events(sc); 757230592Sken 758230592Sken /* the end of discovery will release the simq, so we're done. */ 759253460Sscottl mps_dprint(sc, MPS_INFO, "%s finished sc %p post %u free %u\n", 760253460Sscottl __func__, sc, sc->replypostindex, sc->replyfreeindex); 761230592Sken 762230592Sken return 0; 763230592Sken} 764230592Sken 765237683Sken/* Wait for the chip to ACK a word that we've put into its FIFO 766237683Sken * Wait for <timeout> seconds. In single loop wait for busy loop 767237683Sken * for 500 microseconds. 768237683Sken * Total is [ 0.5 * (2000 * <timeout>) ] in miliseconds. 769237683Sken * */ 770212420Skenstatic int 771237683Skenmps_wait_db_ack(struct mps_softc *sc, int timeout, int sleep_flag) 772212420Sken{ 773212420Sken 774237683Sken u32 cntdn, count; 775237683Sken u32 int_status; 776237683Sken u32 doorbell; 777237683Sken 778237683Sken count = 0; 779237683Sken cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout; 780237683Sken do { 781237683Sken int_status = mps_regread(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET); 782237683Sken if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) { 783253460Sscottl mps_dprint(sc, MPS_INIT, 784237683Sken "%s: successfull count(%d), timeout(%d)\n", 785237683Sken __func__, count, timeout); 786237683Sken return 0; 787237683Sken } else if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) { 788237683Sken doorbell = mps_regread(sc, MPI2_DOORBELL_OFFSET); 789237683Sken if ((doorbell & MPI2_IOC_STATE_MASK) == 790237683Sken MPI2_IOC_STATE_FAULT) { 791237683Sken mps_dprint(sc, MPS_FAULT, 792237683Sken "fault_state(0x%04x)!\n", doorbell); 793237683Sken return (EFAULT); 794237683Sken } 795237683Sken } else if (int_status == 0xFFFFFFFF) 796237683Sken goto out; 797237683Sken 798237683Sken /* If it can sleep, sleep for 1 milisecond, else busy loop for 799237683Sken * 0.5 milisecond */ 800237683Sken if (mtx_owned(&sc->mps_mtx) && sleep_flag == CAN_SLEEP) 801237683Sken msleep(&sc->msleep_fake_chan, &sc->mps_mtx, 0, 802237683Sken "mpsdba", hz/1000); 803237683Sken else if (sleep_flag == CAN_SLEEP) 804237683Sken pause("mpsdba", hz/1000); 805237683Sken else 806237683Sken DELAY(500); 807237683Sken count++; 808237683Sken } while (--cntdn); 809237683Sken 810237683Sken out: 811237683Sken mps_dprint(sc, MPS_FAULT, "%s: failed due to timeout count(%d), " 812237683Sken "int_status(%x)!\n", __func__, count, int_status); 813212420Sken return (ETIMEDOUT); 814237683Sken 815212420Sken} 816212420Sken 817212420Sken/* Wait for the chip to signal that the next word in its FIFO can be fetched */ 818212420Skenstatic int 819212420Skenmps_wait_db_int(struct mps_softc *sc) 820212420Sken{ 821212420Sken int retry; 822212420Sken 823212420Sken for (retry = 0; retry < MPS_DB_MAX_WAIT; retry++) { 824212420Sken if ((mps_regread(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET) & 825212420Sken MPI2_HIS_IOC2SYS_DB_STATUS) != 0) 826212420Sken return (0); 827212420Sken DELAY(2000); 828212420Sken } 829212420Sken return (ETIMEDOUT); 830212420Sken} 831212420Sken 832212420Sken/* Step through the synchronous command state machine, i.e. "Doorbell mode" */ 833212420Skenstatic int 834212420Skenmps_request_sync(struct mps_softc *sc, void *req, MPI2_DEFAULT_REPLY *reply, 835212420Sken int req_sz, int reply_sz, int timeout) 836212420Sken{ 837212420Sken uint32_t *data32; 838212420Sken uint16_t *data16; 839212420Sken int i, count, ioc_sz, residual; 840237683Sken int sleep_flags = CAN_SLEEP; 841247588Sjhb 842247588Sjhb if (curthread->td_no_sleeping != 0) 843237683Sken sleep_flags = NO_SLEEP; 844212420Sken 845212420Sken /* Step 1 */ 846212420Sken mps_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); 847212420Sken 848212420Sken /* Step 2 */ 849212420Sken if (mps_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_USED) 850212420Sken return (EBUSY); 851212420Sken 852212420Sken /* Step 3 853212420Sken * Announce that a message is coming through the doorbell. Messages 854212420Sken * are pushed at 32bit words, so round up if needed. 855212420Sken */ 856212420Sken count = (req_sz + 3) / 4; 857212420Sken mps_regwrite(sc, MPI2_DOORBELL_OFFSET, 858212420Sken (MPI2_FUNCTION_HANDSHAKE << MPI2_DOORBELL_FUNCTION_SHIFT) | 859212420Sken (count << MPI2_DOORBELL_ADD_DWORDS_SHIFT)); 860212420Sken 861212420Sken /* Step 4 */ 862212420Sken if (mps_wait_db_int(sc) || 863212420Sken (mps_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_USED) == 0) { 864212420Sken mps_dprint(sc, MPS_FAULT, "Doorbell failed to activate\n"); 865212420Sken return (ENXIO); 866212420Sken } 867212420Sken mps_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); 868237683Sken if (mps_wait_db_ack(sc, 5, sleep_flags) != 0) { 869212420Sken mps_dprint(sc, MPS_FAULT, "Doorbell handshake failed\n"); 870212420Sken return (ENXIO); 871212420Sken } 872212420Sken 873212420Sken /* Step 5 */ 874212420Sken /* Clock out the message data synchronously in 32-bit dwords*/ 875212420Sken data32 = (uint32_t *)req; 876212420Sken for (i = 0; i < count; i++) { 877237683Sken mps_regwrite(sc, MPI2_DOORBELL_OFFSET, htole32(data32[i])); 878237683Sken if (mps_wait_db_ack(sc, 5, sleep_flags) != 0) { 879212420Sken mps_dprint(sc, MPS_FAULT, 880212420Sken "Timeout while writing doorbell\n"); 881212420Sken return (ENXIO); 882212420Sken } 883212420Sken } 884212420Sken 885212420Sken /* Step 6 */ 886212420Sken /* Clock in the reply in 16-bit words. The total length of the 887212420Sken * message is always in the 4th byte, so clock out the first 2 words 888212420Sken * manually, then loop the rest. 889212420Sken */ 890212420Sken data16 = (uint16_t *)reply; 891212420Sken if (mps_wait_db_int(sc) != 0) { 892212420Sken mps_dprint(sc, MPS_FAULT, "Timeout reading doorbell 0\n"); 893212420Sken return (ENXIO); 894212420Sken } 895212420Sken data16[0] = 896212420Sken mps_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_DATA_MASK; 897212420Sken mps_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); 898212420Sken if (mps_wait_db_int(sc) != 0) { 899212420Sken mps_dprint(sc, MPS_FAULT, "Timeout reading doorbell 1\n"); 900212420Sken return (ENXIO); 901212420Sken } 902212420Sken data16[1] = 903212420Sken mps_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_DATA_MASK; 904212420Sken mps_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); 905212420Sken 906212420Sken /* Number of 32bit words in the message */ 907212420Sken ioc_sz = reply->MsgLength; 908212420Sken 909212420Sken /* 910212420Sken * Figure out how many 16bit words to clock in without overrunning. 911212420Sken * The precision loss with dividing reply_sz can safely be 912212420Sken * ignored because the messages can only be multiples of 32bits. 913212420Sken */ 914212420Sken residual = 0; 915212420Sken count = MIN((reply_sz / 4), ioc_sz) * 2; 916212420Sken if (count < ioc_sz * 2) { 917212420Sken residual = ioc_sz * 2 - count; 918253460Sscottl mps_dprint(sc, MPS_ERROR, "Driver error, throwing away %d " 919212420Sken "residual message words\n", residual); 920212420Sken } 921212420Sken 922212420Sken for (i = 2; i < count; i++) { 923212420Sken if (mps_wait_db_int(sc) != 0) { 924212420Sken mps_dprint(sc, MPS_FAULT, 925212420Sken "Timeout reading doorbell %d\n", i); 926212420Sken return (ENXIO); 927212420Sken } 928212420Sken data16[i] = mps_regread(sc, MPI2_DOORBELL_OFFSET) & 929212420Sken MPI2_DOORBELL_DATA_MASK; 930212420Sken mps_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); 931212420Sken } 932212420Sken 933212420Sken /* 934212420Sken * Pull out residual words that won't fit into the provided buffer. 935212420Sken * This keeps the chip from hanging due to a driver programming 936212420Sken * error. 937212420Sken */ 938212420Sken while (residual--) { 939212420Sken if (mps_wait_db_int(sc) != 0) { 940212420Sken mps_dprint(sc, MPS_FAULT, 941212420Sken "Timeout reading doorbell\n"); 942212420Sken return (ENXIO); 943212420Sken } 944212420Sken (void)mps_regread(sc, MPI2_DOORBELL_OFFSET); 945212420Sken mps_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); 946212420Sken } 947212420Sken 948212420Sken /* Step 7 */ 949212420Sken if (mps_wait_db_int(sc) != 0) { 950212420Sken mps_dprint(sc, MPS_FAULT, "Timeout waiting to exit doorbell\n"); 951212420Sken return (ENXIO); 952212420Sken } 953212420Sken if (mps_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_USED) 954212420Sken mps_dprint(sc, MPS_FAULT, "Warning, doorbell still active\n"); 955212420Sken mps_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); 956212420Sken 957212420Sken return (0); 958212420Sken} 959212420Sken 960230592Skenstatic void 961212420Skenmps_enqueue_request(struct mps_softc *sc, struct mps_command *cm) 962212420Sken{ 963237683Sken reply_descriptor rd; 964253460Sscottl MPS_FUNCTRACE(sc); 965253460Sscottl mps_dprint(sc, MPS_TRACE, "SMID %u cm %p ccb %p\n", 966230592Sken cm->cm_desc.Default.SMID, cm, cm->cm_ccb); 967212420Sken 968231240Sken if (sc->mps_flags & MPS_FLAGS_ATTACH_DONE && !(sc->mps_flags & MPS_FLAGS_SHUTDOWN)) 969218812Sken mtx_assert(&sc->mps_mtx, MA_OWNED); 970218812Sken 971230592Sken if (++sc->io_cmds_active > sc->io_cmds_highwater) 972230592Sken sc->io_cmds_highwater++; 973237683Sken rd.u.low = cm->cm_desc.Words.Low; 974237683Sken rd.u.high = cm->cm_desc.Words.High; 975237683Sken rd.word = htole64(rd.word); 976237683Sken /* TODO-We may need to make below regwrite atomic */ 977212420Sken mps_regwrite(sc, MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET, 978237683Sken rd.u.low); 979212420Sken mps_regwrite(sc, MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET, 980237683Sken rd.u.high); 981212420Sken} 982212420Sken 983212420Sken/* 984212420Sken * Just the FACTS, ma'am. 985212420Sken */ 986212420Skenstatic int 987212420Skenmps_get_iocfacts(struct mps_softc *sc, MPI2_IOC_FACTS_REPLY *facts) 988212420Sken{ 989212420Sken MPI2_DEFAULT_REPLY *reply; 990212420Sken MPI2_IOC_FACTS_REQUEST request; 991212420Sken int error, req_sz, reply_sz; 992212420Sken 993253460Sscottl MPS_FUNCTRACE(sc); 994212420Sken 995212420Sken req_sz = sizeof(MPI2_IOC_FACTS_REQUEST); 996212420Sken reply_sz = sizeof(MPI2_IOC_FACTS_REPLY); 997212420Sken reply = (MPI2_DEFAULT_REPLY *)facts; 998212420Sken 999212420Sken bzero(&request, req_sz); 1000212420Sken request.Function = MPI2_FUNCTION_IOC_FACTS; 1001212420Sken error = mps_request_sync(sc, &request, reply, req_sz, reply_sz, 5); 1002212420Sken 1003212420Sken return (error); 1004212420Sken} 1005212420Sken 1006212420Skenstatic int 1007212420Skenmps_send_iocinit(struct mps_softc *sc) 1008212420Sken{ 1009212420Sken MPI2_IOC_INIT_REQUEST init; 1010212420Sken MPI2_DEFAULT_REPLY reply; 1011212420Sken int req_sz, reply_sz, error; 1012253550Sken struct timeval now; 1013253550Sken uint64_t time_in_msec; 1014212420Sken 1015253460Sscottl MPS_FUNCTRACE(sc); 1016212420Sken 1017212420Sken req_sz = sizeof(MPI2_IOC_INIT_REQUEST); 1018212420Sken reply_sz = sizeof(MPI2_IOC_INIT_REPLY); 1019212420Sken bzero(&init, req_sz); 1020212420Sken bzero(&reply, reply_sz); 1021212420Sken 1022212420Sken /* 1023212420Sken * Fill in the init block. Note that most addresses are 1024212420Sken * deliberately in the lower 32bits of memory. This is a micro- 1025212420Sken * optimzation for PCI/PCIX, though it's not clear if it helps PCIe. 1026212420Sken */ 1027212420Sken init.Function = MPI2_FUNCTION_IOC_INIT; 1028212420Sken init.WhoInit = MPI2_WHOINIT_HOST_DRIVER; 1029237683Sken init.MsgVersion = htole16(MPI2_VERSION); 1030237683Sken init.HeaderVersion = htole16(MPI2_HEADER_VERSION); 1031237683Sken init.SystemRequestFrameSize = htole16(sc->facts->IOCRequestFrameSize); 1032237683Sken init.ReplyDescriptorPostQueueDepth = htole16(sc->pqdepth); 1033237683Sken init.ReplyFreeQueueDepth = htole16(sc->fqdepth); 1034212420Sken init.SenseBufferAddressHigh = 0; 1035212420Sken init.SystemReplyAddressHigh = 0; 1036212420Sken init.SystemRequestFrameBaseAddress.High = 0; 1037237683Sken init.SystemRequestFrameBaseAddress.Low = htole32((uint32_t)sc->req_busaddr); 1038212420Sken init.ReplyDescriptorPostQueueAddress.High = 0; 1039237683Sken init.ReplyDescriptorPostQueueAddress.Low = htole32((uint32_t)sc->post_busaddr); 1040212420Sken init.ReplyFreeQueueAddress.High = 0; 1041237683Sken init.ReplyFreeQueueAddress.Low = htole32((uint32_t)sc->free_busaddr); 1042253550Sken getmicrotime(&now); 1043253550Sken time_in_msec = (now.tv_sec * 1000 + now.tv_usec/1000); 1044253550Sken init.TimeStamp.High = htole32((time_in_msec >> 32) & 0xFFFFFFFF); 1045253550Sken init.TimeStamp.Low = htole32(time_in_msec & 0xFFFFFFFF); 1046212420Sken 1047212420Sken error = mps_request_sync(sc, &init, &reply, req_sz, reply_sz, 5); 1048212420Sken if ((reply.IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS) 1049212420Sken error = ENXIO; 1050212420Sken 1051253460Sscottl mps_dprint(sc, MPS_INIT, "IOCInit status= 0x%x\n", reply.IOCStatus); 1052212420Sken return (error); 1053212420Sken} 1054212420Sken 1055212420Skenvoid 1056212420Skenmps_memaddr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 1057212420Sken{ 1058212420Sken bus_addr_t *addr; 1059212420Sken 1060212420Sken addr = arg; 1061212420Sken *addr = segs[0].ds_addr; 1062212420Sken} 1063212420Sken 1064212420Skenstatic int 1065212420Skenmps_alloc_queues(struct mps_softc *sc) 1066212420Sken{ 1067212420Sken bus_addr_t queues_busaddr; 1068212420Sken uint8_t *queues; 1069212420Sken int qsize, fqsize, pqsize; 1070212420Sken 1071212420Sken /* 1072212420Sken * The reply free queue contains 4 byte entries in multiples of 16 and 1073212420Sken * aligned on a 16 byte boundary. There must always be an unused entry. 1074212420Sken * This queue supplies fresh reply frames for the firmware to use. 1075212420Sken * 1076212420Sken * The reply descriptor post queue contains 8 byte entries in 1077212420Sken * multiples of 16 and aligned on a 16 byte boundary. This queue 1078212420Sken * contains filled-in reply frames sent from the firmware to the host. 1079212420Sken * 1080212420Sken * These two queues are allocated together for simplicity. 1081212420Sken */ 1082212420Sken sc->fqdepth = roundup2((sc->num_replies + 1), 16); 1083212420Sken sc->pqdepth = roundup2((sc->num_replies + 1), 16); 1084212420Sken fqsize= sc->fqdepth * 4; 1085212420Sken pqsize = sc->pqdepth * 8; 1086212420Sken qsize = fqsize + pqsize; 1087212420Sken 1088212420Sken if (bus_dma_tag_create( sc->mps_parent_dmat, /* parent */ 1089212420Sken 16, 0, /* algnmnt, boundary */ 1090212420Sken BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 1091212420Sken BUS_SPACE_MAXADDR, /* highaddr */ 1092212420Sken NULL, NULL, /* filter, filterarg */ 1093212420Sken qsize, /* maxsize */ 1094212420Sken 1, /* nsegments */ 1095212420Sken qsize, /* maxsegsize */ 1096212420Sken 0, /* flags */ 1097212420Sken NULL, NULL, /* lockfunc, lockarg */ 1098212420Sken &sc->queues_dmat)) { 1099212420Sken device_printf(sc->mps_dev, "Cannot allocate queues DMA tag\n"); 1100212420Sken return (ENOMEM); 1101212420Sken } 1102212420Sken if (bus_dmamem_alloc(sc->queues_dmat, (void **)&queues, BUS_DMA_NOWAIT, 1103212420Sken &sc->queues_map)) { 1104212420Sken device_printf(sc->mps_dev, "Cannot allocate queues memory\n"); 1105212420Sken return (ENOMEM); 1106212420Sken } 1107212420Sken bzero(queues, qsize); 1108212420Sken bus_dmamap_load(sc->queues_dmat, sc->queues_map, queues, qsize, 1109212420Sken mps_memaddr_cb, &queues_busaddr, 0); 1110212420Sken 1111212420Sken sc->free_queue = (uint32_t *)queues; 1112212420Sken sc->free_busaddr = queues_busaddr; 1113212420Sken sc->post_queue = (MPI2_REPLY_DESCRIPTORS_UNION *)(queues + fqsize); 1114212420Sken sc->post_busaddr = queues_busaddr + fqsize; 1115212420Sken 1116212420Sken return (0); 1117212420Sken} 1118212420Sken 1119212420Skenstatic int 1120212420Skenmps_alloc_replies(struct mps_softc *sc) 1121212420Sken{ 1122216363Sken int rsize, num_replies; 1123212420Sken 1124216363Sken /* 1125216363Sken * sc->num_replies should be one less than sc->fqdepth. We need to 1126216363Sken * allocate space for sc->fqdepth replies, but only sc->num_replies 1127216363Sken * replies can be used at once. 1128216363Sken */ 1129216363Sken num_replies = max(sc->fqdepth, sc->num_replies); 1130216363Sken 1131216363Sken rsize = sc->facts->ReplyFrameSize * num_replies * 4; 1132212420Sken if (bus_dma_tag_create( sc->mps_parent_dmat, /* parent */ 1133212420Sken 4, 0, /* algnmnt, boundary */ 1134212420Sken BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 1135212420Sken BUS_SPACE_MAXADDR, /* highaddr */ 1136212420Sken NULL, NULL, /* filter, filterarg */ 1137212420Sken rsize, /* maxsize */ 1138212420Sken 1, /* nsegments */ 1139212420Sken rsize, /* maxsegsize */ 1140212420Sken 0, /* flags */ 1141212420Sken NULL, NULL, /* lockfunc, lockarg */ 1142212420Sken &sc->reply_dmat)) { 1143212420Sken device_printf(sc->mps_dev, "Cannot allocate replies DMA tag\n"); 1144212420Sken return (ENOMEM); 1145212420Sken } 1146212420Sken if (bus_dmamem_alloc(sc->reply_dmat, (void **)&sc->reply_frames, 1147212420Sken BUS_DMA_NOWAIT, &sc->reply_map)) { 1148212420Sken device_printf(sc->mps_dev, "Cannot allocate replies memory\n"); 1149212420Sken return (ENOMEM); 1150212420Sken } 1151212420Sken bzero(sc->reply_frames, rsize); 1152212420Sken bus_dmamap_load(sc->reply_dmat, sc->reply_map, sc->reply_frames, rsize, 1153212420Sken mps_memaddr_cb, &sc->reply_busaddr, 0); 1154212420Sken 1155212420Sken return (0); 1156212420Sken} 1157212420Sken 1158212420Skenstatic int 1159212420Skenmps_alloc_requests(struct mps_softc *sc) 1160212420Sken{ 1161212420Sken struct mps_command *cm; 1162212420Sken struct mps_chain *chain; 1163212420Sken int i, rsize, nsegs; 1164212420Sken 1165212420Sken rsize = sc->facts->IOCRequestFrameSize * sc->num_reqs * 4; 1166212420Sken if (bus_dma_tag_create( sc->mps_parent_dmat, /* parent */ 1167212420Sken 16, 0, /* algnmnt, boundary */ 1168212420Sken BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 1169212420Sken BUS_SPACE_MAXADDR, /* highaddr */ 1170212420Sken NULL, NULL, /* filter, filterarg */ 1171212420Sken rsize, /* maxsize */ 1172212420Sken 1, /* nsegments */ 1173212420Sken rsize, /* maxsegsize */ 1174212420Sken 0, /* flags */ 1175212420Sken NULL, NULL, /* lockfunc, lockarg */ 1176212420Sken &sc->req_dmat)) { 1177212420Sken device_printf(sc->mps_dev, "Cannot allocate request DMA tag\n"); 1178212420Sken return (ENOMEM); 1179212420Sken } 1180212420Sken if (bus_dmamem_alloc(sc->req_dmat, (void **)&sc->req_frames, 1181212420Sken BUS_DMA_NOWAIT, &sc->req_map)) { 1182212420Sken device_printf(sc->mps_dev, "Cannot allocate request memory\n"); 1183212420Sken return (ENOMEM); 1184212420Sken } 1185212420Sken bzero(sc->req_frames, rsize); 1186212420Sken bus_dmamap_load(sc->req_dmat, sc->req_map, sc->req_frames, rsize, 1187212420Sken mps_memaddr_cb, &sc->req_busaddr, 0); 1188212420Sken 1189230592Sken rsize = sc->facts->IOCRequestFrameSize * sc->max_chains * 4; 1190212420Sken if (bus_dma_tag_create( sc->mps_parent_dmat, /* parent */ 1191212420Sken 16, 0, /* algnmnt, boundary */ 1192212420Sken BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 1193212420Sken BUS_SPACE_MAXADDR, /* highaddr */ 1194212420Sken NULL, NULL, /* filter, filterarg */ 1195212420Sken rsize, /* maxsize */ 1196212420Sken 1, /* nsegments */ 1197212420Sken rsize, /* maxsegsize */ 1198212420Sken 0, /* flags */ 1199212420Sken NULL, NULL, /* lockfunc, lockarg */ 1200212420Sken &sc->chain_dmat)) { 1201212420Sken device_printf(sc->mps_dev, "Cannot allocate chain DMA tag\n"); 1202212420Sken return (ENOMEM); 1203212420Sken } 1204212420Sken if (bus_dmamem_alloc(sc->chain_dmat, (void **)&sc->chain_frames, 1205212420Sken BUS_DMA_NOWAIT, &sc->chain_map)) { 1206212420Sken device_printf(sc->mps_dev, "Cannot allocate chain memory\n"); 1207212420Sken return (ENOMEM); 1208212420Sken } 1209212420Sken bzero(sc->chain_frames, rsize); 1210212420Sken bus_dmamap_load(sc->chain_dmat, sc->chain_map, sc->chain_frames, rsize, 1211212420Sken mps_memaddr_cb, &sc->chain_busaddr, 0); 1212212420Sken 1213212420Sken rsize = MPS_SENSE_LEN * sc->num_reqs; 1214212420Sken if (bus_dma_tag_create( sc->mps_parent_dmat, /* parent */ 1215212420Sken 1, 0, /* algnmnt, boundary */ 1216212420Sken BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 1217212420Sken BUS_SPACE_MAXADDR, /* highaddr */ 1218212420Sken NULL, NULL, /* filter, filterarg */ 1219212420Sken rsize, /* maxsize */ 1220212420Sken 1, /* nsegments */ 1221212420Sken rsize, /* maxsegsize */ 1222212420Sken 0, /* flags */ 1223212420Sken NULL, NULL, /* lockfunc, lockarg */ 1224212420Sken &sc->sense_dmat)) { 1225212420Sken device_printf(sc->mps_dev, "Cannot allocate sense DMA tag\n"); 1226212420Sken return (ENOMEM); 1227212420Sken } 1228212420Sken if (bus_dmamem_alloc(sc->sense_dmat, (void **)&sc->sense_frames, 1229212420Sken BUS_DMA_NOWAIT, &sc->sense_map)) { 1230212420Sken device_printf(sc->mps_dev, "Cannot allocate sense memory\n"); 1231212420Sken return (ENOMEM); 1232212420Sken } 1233212420Sken bzero(sc->sense_frames, rsize); 1234212420Sken bus_dmamap_load(sc->sense_dmat, sc->sense_map, sc->sense_frames, rsize, 1235212420Sken mps_memaddr_cb, &sc->sense_busaddr, 0); 1236212420Sken 1237230592Sken sc->chains = malloc(sizeof(struct mps_chain) * sc->max_chains, M_MPT2, 1238230592Sken M_WAITOK | M_ZERO); 1239237683Sken if(!sc->chains) { 1240237683Sken device_printf(sc->mps_dev, 1241237683Sken "Cannot allocate chains memory %s %d\n", 1242237683Sken __func__, __LINE__); 1243237683Sken return (ENOMEM); 1244237683Sken } 1245230592Sken for (i = 0; i < sc->max_chains; i++) { 1246212420Sken chain = &sc->chains[i]; 1247212420Sken chain->chain = (MPI2_SGE_IO_UNION *)(sc->chain_frames + 1248212420Sken i * sc->facts->IOCRequestFrameSize * 4); 1249212420Sken chain->chain_busaddr = sc->chain_busaddr + 1250212420Sken i * sc->facts->IOCRequestFrameSize * 4; 1251212420Sken mps_free_chain(sc, chain); 1252218812Sken sc->chain_free_lowwater++; 1253212420Sken } 1254212420Sken 1255212420Sken /* XXX Need to pick a more precise value */ 1256212420Sken nsegs = (MAXPHYS / PAGE_SIZE) + 1; 1257212420Sken if (bus_dma_tag_create( sc->mps_parent_dmat, /* parent */ 1258212420Sken 1, 0, /* algnmnt, boundary */ 1259212420Sken BUS_SPACE_MAXADDR, /* lowaddr */ 1260212420Sken BUS_SPACE_MAXADDR, /* highaddr */ 1261212420Sken NULL, NULL, /* filter, filterarg */ 1262212420Sken BUS_SPACE_MAXSIZE_32BIT,/* maxsize */ 1263212420Sken nsegs, /* nsegments */ 1264238974Smav BUS_SPACE_MAXSIZE_24BIT,/* maxsegsize */ 1265212420Sken BUS_DMA_ALLOCNOW, /* flags */ 1266212420Sken busdma_lock_mutex, /* lockfunc */ 1267212420Sken &sc->mps_mtx, /* lockarg */ 1268212420Sken &sc->buffer_dmat)) { 1269230592Sken device_printf(sc->mps_dev, "Cannot allocate buffer DMA tag\n"); 1270212420Sken return (ENOMEM); 1271212420Sken } 1272212420Sken 1273212420Sken /* 1274212420Sken * SMID 0 cannot be used as a free command per the firmware spec. 1275212420Sken * Just drop that command instead of risking accounting bugs. 1276212420Sken */ 1277212420Sken sc->commands = malloc(sizeof(struct mps_command) * sc->num_reqs, 1278212420Sken M_MPT2, M_WAITOK | M_ZERO); 1279237683Sken if(!sc->commands) { 1280237683Sken device_printf(sc->mps_dev, "Cannot allocate memory %s %d\n", 1281237683Sken __func__, __LINE__); 1282237683Sken return (ENOMEM); 1283237683Sken } 1284212420Sken for (i = 1; i < sc->num_reqs; i++) { 1285212420Sken cm = &sc->commands[i]; 1286212420Sken cm->cm_req = sc->req_frames + 1287212420Sken i * sc->facts->IOCRequestFrameSize * 4; 1288212420Sken cm->cm_req_busaddr = sc->req_busaddr + 1289212420Sken i * sc->facts->IOCRequestFrameSize * 4; 1290212420Sken cm->cm_sense = &sc->sense_frames[i]; 1291212420Sken cm->cm_sense_busaddr = sc->sense_busaddr + i * MPS_SENSE_LEN; 1292212420Sken cm->cm_desc.Default.SMID = i; 1293212420Sken cm->cm_sc = sc; 1294212420Sken TAILQ_INIT(&cm->cm_chain_list); 1295230592Sken callout_init_mtx(&cm->cm_callout, &sc->mps_mtx, 0); 1296212420Sken 1297212420Sken /* XXX Is a failure here a critical problem? */ 1298212420Sken if (bus_dmamap_create(sc->buffer_dmat, 0, &cm->cm_dmamap) == 0) 1299230592Sken if (i <= sc->facts->HighPriorityCredit) 1300230592Sken mps_free_high_priority_command(sc, cm); 1301230592Sken else 1302230592Sken mps_free_command(sc, cm); 1303212420Sken else { 1304230592Sken panic("failed to allocate command %d\n", i); 1305212420Sken sc->num_reqs = i; 1306212420Sken break; 1307212420Sken } 1308212420Sken } 1309212420Sken 1310212420Sken return (0); 1311212420Sken} 1312212420Sken 1313212420Skenstatic int 1314212420Skenmps_init_queues(struct mps_softc *sc) 1315212420Sken{ 1316212420Sken int i; 1317212420Sken 1318212420Sken memset((uint8_t *)sc->post_queue, 0xff, sc->pqdepth * 8); 1319212420Sken 1320216363Sken /* 1321216363Sken * According to the spec, we need to use one less reply than we 1322216363Sken * have space for on the queue. So sc->num_replies (the number we 1323216363Sken * use) should be less than sc->fqdepth (allocated size). 1324216363Sken */ 1325212420Sken if (sc->num_replies >= sc->fqdepth) 1326212420Sken return (EINVAL); 1327212420Sken 1328216363Sken /* 1329216363Sken * Initialize all of the free queue entries. 1330216363Sken */ 1331216363Sken for (i = 0; i < sc->fqdepth; i++) 1332216363Sken sc->free_queue[i] = sc->reply_busaddr + (i * sc->facts->ReplyFrameSize * 4); 1333212420Sken sc->replyfreeindex = sc->num_replies; 1334212420Sken 1335212420Sken return (0); 1336212420Sken} 1337212420Sken 1338230592Sken/* Get the driver parameter tunables. Lowest priority are the driver defaults. 1339230592Sken * Next are the global settings, if they exist. Highest are the per-unit 1340230592Sken * settings, if they exist. 1341230592Sken */ 1342230592Skenstatic void 1343230592Skenmps_get_tunables(struct mps_softc *sc) 1344212420Sken{ 1345230592Sken char tmpstr[80]; 1346212420Sken 1347230592Sken /* XXX default to some debugging for now */ 1348253460Sscottl sc->mps_debug = MPS_INFO|MPS_FAULT; 1349230592Sken sc->disable_msix = 0; 1350230592Sken sc->disable_msi = 0; 1351230592Sken sc->max_chains = MPS_CHAIN_FRAMES; 1352230592Sken 1353212420Sken /* 1354230592Sken * Grab the global variables. 1355212420Sken */ 1356230592Sken TUNABLE_INT_FETCH("hw.mps.debug_level", &sc->mps_debug); 1357230592Sken TUNABLE_INT_FETCH("hw.mps.disable_msix", &sc->disable_msix); 1358230592Sken TUNABLE_INT_FETCH("hw.mps.disable_msi", &sc->disable_msi); 1359230592Sken TUNABLE_INT_FETCH("hw.mps.max_chains", &sc->max_chains); 1360230592Sken 1361230592Sken /* Grab the unit-instance variables */ 1362230592Sken snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.debug_level", 1363212420Sken device_get_unit(sc->mps_dev)); 1364212420Sken TUNABLE_INT_FETCH(tmpstr, &sc->mps_debug); 1365230592Sken 1366230592Sken snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.disable_msix", 1367213535Sken device_get_unit(sc->mps_dev)); 1368230592Sken TUNABLE_INT_FETCH(tmpstr, &sc->disable_msix); 1369212420Sken 1370230592Sken snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.disable_msi", 1371230592Sken device_get_unit(sc->mps_dev)); 1372230592Sken TUNABLE_INT_FETCH(tmpstr, &sc->disable_msi); 1373212420Sken 1374230592Sken snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.max_chains", 1375230592Sken device_get_unit(sc->mps_dev)); 1376230592Sken TUNABLE_INT_FETCH(tmpstr, &sc->max_chains); 1377254116Sscottl 1378254116Sscottl bzero(sc->exclude_ids, sizeof(sc->exclude_ids)); 1379254116Sscottl snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.exclude_ids", 1380254116Sscottl device_get_unit(sc->mps_dev)); 1381254116Sscottl TUNABLE_STR_FETCH(tmpstr, sc->exclude_ids, sizeof(sc->exclude_ids)); 1382230592Sken} 1383212420Sken 1384230592Skenstatic void 1385230592Skenmps_setup_sysctl(struct mps_softc *sc) 1386230592Sken{ 1387230592Sken struct sysctl_ctx_list *sysctl_ctx = NULL; 1388230592Sken struct sysctl_oid *sysctl_tree = NULL; 1389230592Sken char tmpstr[80], tmpstr2[80]; 1390230592Sken 1391212420Sken /* 1392212420Sken * Setup the sysctl variable so the user can change the debug level 1393212420Sken * on the fly. 1394212420Sken */ 1395212420Sken snprintf(tmpstr, sizeof(tmpstr), "MPS controller %d", 1396212420Sken device_get_unit(sc->mps_dev)); 1397212420Sken snprintf(tmpstr2, sizeof(tmpstr2), "%d", device_get_unit(sc->mps_dev)); 1398212420Sken 1399230592Sken sysctl_ctx = device_get_sysctl_ctx(sc->mps_dev); 1400230592Sken if (sysctl_ctx != NULL) 1401230592Sken sysctl_tree = device_get_sysctl_tree(sc->mps_dev); 1402212420Sken 1403230592Sken if (sysctl_tree == NULL) { 1404230592Sken sysctl_ctx_init(&sc->sysctl_ctx); 1405230592Sken sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx, 1406230592Sken SYSCTL_STATIC_CHILDREN(_hw_mps), OID_AUTO, tmpstr2, 1407230592Sken CTLFLAG_RD, 0, tmpstr); 1408230592Sken if (sc->sysctl_tree == NULL) 1409230592Sken return; 1410230592Sken sysctl_ctx = &sc->sysctl_ctx; 1411230592Sken sysctl_tree = sc->sysctl_tree; 1412230592Sken } 1413230592Sken 1414230592Sken SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1415212420Sken OID_AUTO, "debug_level", CTLFLAG_RW, &sc->mps_debug, 0, 1416212420Sken "mps debug level"); 1417212420Sken 1418230592Sken SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1419230592Sken OID_AUTO, "disable_msix", CTLFLAG_RD, &sc->disable_msix, 0, 1420230592Sken "Disable the use of MSI-X interrupts"); 1421213535Sken 1422230592Sken SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1423230592Sken OID_AUTO, "disable_msi", CTLFLAG_RD, &sc->disable_msi, 0, 1424230592Sken "Disable the use of MSI interrupts"); 1425230592Sken 1426230592Sken SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1427230592Sken OID_AUTO, "firmware_version", CTLFLAG_RW, &sc->fw_version, 1428230592Sken strlen(sc->fw_version), "firmware version"); 1429230592Sken 1430230592Sken SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1431230592Sken OID_AUTO, "driver_version", CTLFLAG_RW, MPS_DRIVER_VERSION, 1432230592Sken strlen(MPS_DRIVER_VERSION), "driver version"); 1433230592Sken 1434230592Sken SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1435218812Sken OID_AUTO, "io_cmds_active", CTLFLAG_RD, 1436218812Sken &sc->io_cmds_active, 0, "number of currently active commands"); 1437218812Sken 1438230592Sken SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1439218812Sken OID_AUTO, "io_cmds_highwater", CTLFLAG_RD, 1440218812Sken &sc->io_cmds_highwater, 0, "maximum active commands seen"); 1441218812Sken 1442230592Sken SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1443218812Sken OID_AUTO, "chain_free", CTLFLAG_RD, 1444218812Sken &sc->chain_free, 0, "number of free chain elements"); 1445218812Sken 1446230592Sken SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1447218812Sken OID_AUTO, "chain_free_lowwater", CTLFLAG_RD, 1448218812Sken &sc->chain_free_lowwater, 0,"lowest number of free chain elements"); 1449218812Sken 1450230592Sken SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1451230592Sken OID_AUTO, "max_chains", CTLFLAG_RD, 1452230592Sken &sc->max_chains, 0,"maximum chain frames that will be allocated"); 1453230592Sken 1454230592Sken#if __FreeBSD_version >= 900030 1455230592Sken SYSCTL_ADD_UQUAD(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), 1456218812Sken OID_AUTO, "chain_alloc_fail", CTLFLAG_RD, 1457218812Sken &sc->chain_alloc_fail, "chain allocation failures"); 1458230592Sken#endif //FreeBSD_version >= 900030 1459230592Sken} 1460218812Sken 1461230592Skenint 1462230592Skenmps_attach(struct mps_softc *sc) 1463230592Sken{ 1464253550Sken int error; 1465230592Sken 1466230592Sken mps_get_tunables(sc); 1467230592Sken 1468253460Sscottl MPS_FUNCTRACE(sc); 1469230592Sken 1470230592Sken mtx_init(&sc->mps_mtx, "MPT2SAS lock", NULL, MTX_DEF); 1471230592Sken callout_init_mtx(&sc->periodic, &sc->mps_mtx, 0); 1472230592Sken TAILQ_INIT(&sc->event_list); 1473254117Sscottl timevalclear(&sc->lastfail); 1474230592Sken 1475230592Sken if ((error = mps_transition_ready(sc)) != 0) { 1476230592Sken mps_printf(sc, "%s failed to transition ready\n", __func__); 1477212420Sken return (error); 1478230592Sken } 1479212420Sken 1480212420Sken sc->facts = malloc(sizeof(MPI2_IOC_FACTS_REPLY), M_MPT2, 1481212420Sken M_ZERO|M_NOWAIT); 1482237683Sken if(!sc->facts) { 1483237683Sken device_printf(sc->mps_dev, "Cannot allocate memory %s %d\n", 1484237683Sken __func__, __LINE__); 1485237683Sken return (ENOMEM); 1486237683Sken } 1487212420Sken 1488212420Sken /* 1489253550Sken * Get IOC Facts and allocate all structures based on this information. 1490253550Sken * A Diag Reset will also call mps_iocfacts_allocate and re-read the IOC 1491253550Sken * Facts. If relevant values have changed in IOC Facts, this function 1492253550Sken * will free all of the memory based on IOC Facts and reallocate that 1493253550Sken * memory. If this fails, any allocated memory should already be freed. 1494212420Sken */ 1495253550Sken if ((error = mps_iocfacts_allocate(sc, TRUE)) != 0) { 1496253550Sken mps_dprint(sc, MPS_FAULT, "%s IOC Facts based allocation " 1497253550Sken "failed with error %d\n", __func__, error); 1498212420Sken return (error); 1499212420Sken } 1500212420Sken 1501212420Sken /* Start the periodic watchdog check on the IOC Doorbell */ 1502212420Sken mps_periodic(sc); 1503212420Sken 1504212420Sken /* 1505212420Sken * The portenable will kick off discovery events that will drive the 1506212420Sken * rest of the initialization process. The CAM/SAS module will 1507212420Sken * hold up the boot sequence until discovery is complete. 1508212420Sken */ 1509212420Sken sc->mps_ich.ich_func = mps_startup; 1510212420Sken sc->mps_ich.ich_arg = sc; 1511212420Sken if (config_intrhook_establish(&sc->mps_ich) != 0) { 1512253460Sscottl mps_dprint(sc, MPS_ERROR, "Cannot establish MPS config hook\n"); 1513212420Sken error = EINVAL; 1514212420Sken } 1515212420Sken 1516230592Sken /* 1517230592Sken * Allow IR to shutdown gracefully when shutdown occurs. 1518230592Sken */ 1519230592Sken sc->shutdown_eh = EVENTHANDLER_REGISTER(shutdown_final, 1520230592Sken mpssas_ir_shutdown, sc, SHUTDOWN_PRI_DEFAULT); 1521230592Sken 1522230592Sken if (sc->shutdown_eh == NULL) 1523253460Sscottl mps_dprint(sc, MPS_ERROR, "shutdown event registration " 1524230592Sken "failed\n"); 1525230592Sken 1526230592Sken mps_setup_sysctl(sc); 1527230592Sken 1528218812Sken sc->mps_flags |= MPS_FLAGS_ATTACH_DONE; 1529218812Sken 1530212420Sken return (error); 1531212420Sken} 1532212420Sken 1533230592Sken/* Run through any late-start handlers. */ 1534212420Skenstatic void 1535212420Skenmps_startup(void *arg) 1536212420Sken{ 1537212420Sken struct mps_softc *sc; 1538212420Sken 1539212420Sken sc = (struct mps_softc *)arg; 1540212420Sken 1541212420Sken mps_lock(sc); 1542212420Sken mps_unmask_intr(sc); 1543253550Sken 1544230592Sken /* initialize device mapping tables */ 1545253550Sken mps_base_static_config_pages(sc); 1546230592Sken mps_mapping_initialize(sc); 1547230592Sken mpssas_startup(sc); 1548212420Sken mps_unlock(sc); 1549212420Sken} 1550212420Sken 1551212420Sken/* Periodic watchdog. Is called with the driver lock already held. */ 1552212420Skenstatic void 1553212420Skenmps_periodic(void *arg) 1554212420Sken{ 1555212420Sken struct mps_softc *sc; 1556212420Sken uint32_t db; 1557212420Sken 1558212420Sken sc = (struct mps_softc *)arg; 1559212420Sken if (sc->mps_flags & MPS_FLAGS_SHUTDOWN) 1560212420Sken return; 1561212420Sken 1562212420Sken db = mps_regread(sc, MPI2_DOORBELL_OFFSET); 1563212420Sken if ((db & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { 1564253460Sscottl mps_dprint(sc, MPS_FAULT, "IOC Fault 0x%08x, Resetting\n", db); 1565230592Sken mps_reinit(sc); 1566212420Sken } 1567212420Sken 1568212420Sken callout_reset(&sc->periodic, MPS_PERIODIC_DELAY * hz, mps_periodic, sc); 1569212420Sken} 1570212420Sken 1571212420Skenstatic void 1572212420Skenmps_log_evt_handler(struct mps_softc *sc, uintptr_t data, 1573212420Sken MPI2_EVENT_NOTIFICATION_REPLY *event) 1574212420Sken{ 1575212420Sken MPI2_EVENT_DATA_LOG_ENTRY_ADDED *entry; 1576212420Sken 1577212420Sken mps_print_event(sc, event); 1578212420Sken 1579212420Sken switch (event->Event) { 1580212420Sken case MPI2_EVENT_LOG_DATA: 1581253460Sscottl mps_dprint(sc, MPS_EVENT, "MPI2_EVENT_LOG_DATA:\n"); 1582253460Sscottl if (sc->mps_debug & MPS_EVENT) 1583253460Sscottl hexdump(event->EventData, event->EventDataLength, NULL, 0); 1584212420Sken break; 1585212420Sken case MPI2_EVENT_LOG_ENTRY_ADDED: 1586212420Sken entry = (MPI2_EVENT_DATA_LOG_ENTRY_ADDED *)event->EventData; 1587253460Sscottl mps_dprint(sc, MPS_EVENT, "MPI2_EVENT_LOG_ENTRY_ADDED event " 1588212420Sken "0x%x Sequence %d:\n", entry->LogEntryQualifier, 1589212420Sken entry->LogSequence); 1590212420Sken break; 1591212420Sken default: 1592212420Sken break; 1593212420Sken } 1594212420Sken return; 1595212420Sken} 1596212420Sken 1597212420Skenstatic int 1598212420Skenmps_attach_log(struct mps_softc *sc) 1599212420Sken{ 1600237683Sken u32 events[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS]; 1601212420Sken 1602212420Sken bzero(events, 16); 1603212420Sken setbit(events, MPI2_EVENT_LOG_DATA); 1604212420Sken setbit(events, MPI2_EVENT_LOG_ENTRY_ADDED); 1605212420Sken 1606212420Sken mps_register_events(sc, events, mps_log_evt_handler, NULL, 1607212420Sken &sc->mps_log_eh); 1608212420Sken 1609212420Sken return (0); 1610212420Sken} 1611212420Sken 1612212420Skenstatic int 1613212420Skenmps_detach_log(struct mps_softc *sc) 1614212420Sken{ 1615212420Sken 1616212420Sken if (sc->mps_log_eh != NULL) 1617212420Sken mps_deregister_events(sc, sc->mps_log_eh); 1618212420Sken return (0); 1619212420Sken} 1620212420Sken 1621212420Sken/* 1622212420Sken * Free all of the driver resources and detach submodules. Should be called 1623212420Sken * without the lock held. 1624212420Sken */ 1625212420Skenint 1626212420Skenmps_free(struct mps_softc *sc) 1627212420Sken{ 1628253550Sken int error; 1629212420Sken 1630212420Sken /* Turn off the watchdog */ 1631212420Sken mps_lock(sc); 1632212420Sken sc->mps_flags |= MPS_FLAGS_SHUTDOWN; 1633212420Sken mps_unlock(sc); 1634212420Sken /* Lock must not be held for this */ 1635212420Sken callout_drain(&sc->periodic); 1636212420Sken 1637212420Sken if (((error = mps_detach_log(sc)) != 0) || 1638212420Sken ((error = mps_detach_sas(sc)) != 0)) 1639212420Sken return (error); 1640212420Sken 1641231240Sken mps_detach_user(sc); 1642231240Sken 1643212420Sken /* Put the IOC back in the READY state. */ 1644212420Sken mps_lock(sc); 1645230592Sken if ((error = mps_transition_ready(sc)) != 0) { 1646212420Sken mps_unlock(sc); 1647212420Sken return (error); 1648212420Sken } 1649212420Sken mps_unlock(sc); 1650212420Sken 1651212420Sken if (sc->facts != NULL) 1652212420Sken free(sc->facts, M_MPT2); 1653212420Sken 1654253550Sken /* 1655253550Sken * Free all buffers that are based on IOC Facts. A Diag Reset may need 1656253550Sken * to free these buffers too. 1657253550Sken */ 1658253550Sken mps_iocfacts_free(sc); 1659212420Sken 1660212420Sken if (sc->sysctl_tree != NULL) 1661212420Sken sysctl_ctx_free(&sc->sysctl_ctx); 1662212420Sken 1663230592Sken /* Deregister the shutdown function */ 1664230592Sken if (sc->shutdown_eh != NULL) 1665230592Sken EVENTHANDLER_DEREGISTER(shutdown_final, sc->shutdown_eh); 1666230592Sken 1667212420Sken mtx_destroy(&sc->mps_mtx); 1668212420Sken 1669212420Sken return (0); 1670212420Sken} 1671212420Sken 1672218812Skenstatic __inline void 1673253460Sscottlmps_complete_command(struct mps_softc *sc, struct mps_command *cm) 1674218812Sken{ 1675253460Sscottl MPS_FUNCTRACE(sc); 1676253460Sscottl 1677253460Sscottl if (cm == NULL) { 1678253460Sscottl mps_dprint(sc, MPS_ERROR, "Completing NULL command\n"); 1679253460Sscottl return; 1680253460Sscottl } 1681253460Sscottl 1682218812Sken if (cm->cm_flags & MPS_CM_FLAGS_POLLED) 1683218812Sken cm->cm_flags |= MPS_CM_FLAGS_COMPLETE; 1684218812Sken 1685230592Sken if (cm->cm_complete != NULL) { 1686253460Sscottl mps_dprint(sc, MPS_TRACE, 1687230592Sken "%s cm %p calling cm_complete %p data %p reply %p\n", 1688230592Sken __func__, cm, cm->cm_complete, cm->cm_complete_data, 1689230592Sken cm->cm_reply); 1690253460Sscottl cm->cm_complete(sc, cm); 1691230592Sken } 1692218812Sken 1693218812Sken if (cm->cm_flags & MPS_CM_FLAGS_WAKEUP) { 1694253460Sscottl mps_dprint(sc, MPS_TRACE, "waking up %p\n", cm); 1695218812Sken wakeup(cm); 1696218812Sken } 1697230592Sken 1698230592Sken if (cm->cm_sc->io_cmds_active != 0) { 1699230592Sken cm->cm_sc->io_cmds_active--; 1700230592Sken } else { 1701253460Sscottl mps_dprint(sc, MPS_ERROR, "Warning: io_cmds_active is " 1702230592Sken "out of sync - resynching to 0\n"); 1703230592Sken } 1704218812Sken} 1705218812Sken 1706237683Sken 1707237683Skenstatic void 1708237683Skenmps_sas_log_info(struct mps_softc *sc , u32 log_info) 1709237683Sken{ 1710237683Sken union loginfo_type { 1711237683Sken u32 loginfo; 1712237683Sken struct { 1713237683Sken u32 subcode:16; 1714237683Sken u32 code:8; 1715237683Sken u32 originator:4; 1716237683Sken u32 bus_type:4; 1717237683Sken } dw; 1718237683Sken }; 1719237683Sken union loginfo_type sas_loginfo; 1720237683Sken char *originator_str = NULL; 1721237683Sken 1722237683Sken sas_loginfo.loginfo = log_info; 1723237683Sken if (sas_loginfo.dw.bus_type != 3 /*SAS*/) 1724237683Sken return; 1725237683Sken 1726237683Sken /* each nexus loss loginfo */ 1727237683Sken if (log_info == 0x31170000) 1728237683Sken return; 1729237683Sken 1730237683Sken /* eat the loginfos associated with task aborts */ 1731237683Sken if ((log_info == 30050000 || log_info == 1732237683Sken 0x31140000 || log_info == 0x31130000)) 1733237683Sken return; 1734237683Sken 1735237683Sken switch (sas_loginfo.dw.originator) { 1736237683Sken case 0: 1737237683Sken originator_str = "IOP"; 1738237683Sken break; 1739237683Sken case 1: 1740237683Sken originator_str = "PL"; 1741237683Sken break; 1742237683Sken case 2: 1743237683Sken originator_str = "IR"; 1744237683Sken break; 1745237683Sken} 1746237683Sken 1747253460Sscottl mps_dprint(sc, MPS_LOG, "log_info(0x%08x): originator(%s), " 1748237683Sken "code(0x%02x), sub_code(0x%04x)\n", log_info, 1749237683Sken originator_str, sas_loginfo.dw.code, 1750237683Sken sas_loginfo.dw.subcode); 1751237683Sken} 1752237683Sken 1753237683Skenstatic void 1754237683Skenmps_display_reply_info(struct mps_softc *sc, uint8_t *reply) 1755237683Sken{ 1756237683Sken MPI2DefaultReply_t *mpi_reply; 1757237683Sken u16 sc_status; 1758237683Sken 1759237683Sken mpi_reply = (MPI2DefaultReply_t*)reply; 1760237683Sken sc_status = le16toh(mpi_reply->IOCStatus); 1761237683Sken if (sc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) 1762237683Sken mps_sas_log_info(sc, le32toh(mpi_reply->IOCLogInfo)); 1763237683Sken} 1764212420Skenvoid 1765212420Skenmps_intr(void *data) 1766212420Sken{ 1767212420Sken struct mps_softc *sc; 1768212420Sken uint32_t status; 1769212420Sken 1770212420Sken sc = (struct mps_softc *)data; 1771212420Sken mps_dprint(sc, MPS_TRACE, "%s\n", __func__); 1772212420Sken 1773212420Sken /* 1774212420Sken * Check interrupt status register to flush the bus. This is 1775212420Sken * needed for both INTx interrupts and driver-driven polling 1776212420Sken */ 1777212420Sken status = mps_regread(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET); 1778212420Sken if ((status & MPI2_HIS_REPLY_DESCRIPTOR_INTERRUPT) == 0) 1779212420Sken return; 1780212420Sken 1781212420Sken mps_lock(sc); 1782212420Sken mps_intr_locked(data); 1783212420Sken mps_unlock(sc); 1784212420Sken return; 1785212420Sken} 1786212420Sken 1787212420Sken/* 1788212420Sken * In theory, MSI/MSIX interrupts shouldn't need to read any registers on the 1789212420Sken * chip. Hopefully this theory is correct. 1790212420Sken */ 1791212420Skenvoid 1792212420Skenmps_intr_msi(void *data) 1793212420Sken{ 1794212420Sken struct mps_softc *sc; 1795212420Sken 1796212420Sken sc = (struct mps_softc *)data; 1797230592Sken mps_dprint(sc, MPS_TRACE, "%s\n", __func__); 1798212420Sken mps_lock(sc); 1799212420Sken mps_intr_locked(data); 1800212420Sken mps_unlock(sc); 1801212420Sken return; 1802212420Sken} 1803212420Sken 1804212420Sken/* 1805212420Sken * The locking is overly broad and simplistic, but easy to deal with for now. 1806212420Sken */ 1807212420Skenvoid 1808212420Skenmps_intr_locked(void *data) 1809212420Sken{ 1810212420Sken MPI2_REPLY_DESCRIPTORS_UNION *desc; 1811212420Sken struct mps_softc *sc; 1812212420Sken struct mps_command *cm = NULL; 1813212420Sken uint8_t flags; 1814212420Sken u_int pq; 1815230592Sken MPI2_DIAG_RELEASE_REPLY *rel_rep; 1816230592Sken mps_fw_diagnostic_buffer_t *pBuffer; 1817212420Sken 1818212420Sken sc = (struct mps_softc *)data; 1819212420Sken 1820212420Sken pq = sc->replypostindex; 1821230592Sken mps_dprint(sc, MPS_TRACE, 1822230592Sken "%s sc %p starting with replypostindex %u\n", 1823230592Sken __func__, sc, sc->replypostindex); 1824212420Sken 1825212420Sken for ( ;; ) { 1826212420Sken cm = NULL; 1827230592Sken desc = &sc->post_queue[sc->replypostindex]; 1828212420Sken flags = desc->Default.ReplyFlags & 1829212420Sken MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; 1830216363Sken if ((flags == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) 1831237683Sken || (le32toh(desc->Words.High) == 0xffffffff)) 1832212420Sken break; 1833212420Sken 1834230592Sken /* increment the replypostindex now, so that event handlers 1835230592Sken * and cm completion handlers which decide to do a diag 1836230592Sken * reset can zero it without it getting incremented again 1837230592Sken * afterwards, and we break out of this loop on the next 1838230592Sken * iteration since the reply post queue has been cleared to 1839230592Sken * 0xFF and all descriptors look unused (which they are). 1840230592Sken */ 1841230592Sken if (++sc->replypostindex >= sc->pqdepth) 1842230592Sken sc->replypostindex = 0; 1843230592Sken 1844212420Sken switch (flags) { 1845212420Sken case MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS: 1846237683Sken cm = &sc->commands[le16toh(desc->SCSIIOSuccess.SMID)]; 1847212420Sken cm->cm_reply = NULL; 1848212420Sken break; 1849212420Sken case MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY: 1850212420Sken { 1851212420Sken uint32_t baddr; 1852212420Sken uint8_t *reply; 1853212420Sken 1854216363Sken /* 1855216363Sken * Re-compose the reply address from the address 1856216363Sken * sent back from the chip. The ReplyFrameAddress 1857216363Sken * is the lower 32 bits of the physical address of 1858216363Sken * particular reply frame. Convert that address to 1859216363Sken * host format, and then use that to provide the 1860216363Sken * offset against the virtual address base 1861216363Sken * (sc->reply_frames). 1862216363Sken */ 1863216363Sken baddr = le32toh(desc->AddressReply.ReplyFrameAddress); 1864212420Sken reply = sc->reply_frames + 1865216363Sken (baddr - ((uint32_t)sc->reply_busaddr)); 1866216363Sken /* 1867216363Sken * Make sure the reply we got back is in a valid 1868216363Sken * range. If not, go ahead and panic here, since 1869216363Sken * we'll probably panic as soon as we deference the 1870216363Sken * reply pointer anyway. 1871216363Sken */ 1872216363Sken if ((reply < sc->reply_frames) 1873216363Sken || (reply > (sc->reply_frames + 1874216363Sken (sc->fqdepth * sc->facts->ReplyFrameSize * 4)))) { 1875216363Sken printf("%s: WARNING: reply %p out of range!\n", 1876216363Sken __func__, reply); 1877216363Sken printf("%s: reply_frames %p, fqdepth %d, " 1878216363Sken "frame size %d\n", __func__, 1879216363Sken sc->reply_frames, sc->fqdepth, 1880216363Sken sc->facts->ReplyFrameSize * 4); 1881216363Sken printf("%s: baddr %#x,\n", __func__, baddr); 1882237683Sken /* LSI-TODO. See Linux Code. Need Gracefull exit*/ 1883216363Sken panic("Reply address out of range"); 1884216363Sken } 1885237683Sken if (le16toh(desc->AddressReply.SMID) == 0) { 1886230592Sken if (((MPI2_DEFAULT_REPLY *)reply)->Function == 1887230592Sken MPI2_FUNCTION_DIAG_BUFFER_POST) { 1888230592Sken /* 1889230592Sken * If SMID is 0 for Diag Buffer Post, 1890230592Sken * this implies that the reply is due to 1891230592Sken * a release function with a status that 1892230592Sken * the buffer has been released. Set 1893230592Sken * the buffer flags accordingly. 1894230592Sken */ 1895230592Sken rel_rep = 1896230592Sken (MPI2_DIAG_RELEASE_REPLY *)reply; 1897237683Sken if (le16toh(rel_rep->IOCStatus) == 1898230592Sken MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED) 1899230592Sken { 1900230592Sken pBuffer = 1901230592Sken &sc->fw_diag_buffer_list[ 1902230592Sken rel_rep->BufferType]; 1903230592Sken pBuffer->valid_data = TRUE; 1904230592Sken pBuffer->owned_by_firmware = 1905230592Sken FALSE; 1906230592Sken pBuffer->immediate = FALSE; 1907230592Sken } 1908230592Sken } else 1909230592Sken mps_dispatch_event(sc, baddr, 1910230592Sken (MPI2_EVENT_NOTIFICATION_REPLY *) 1911230592Sken reply); 1912212420Sken } else { 1913237683Sken cm = &sc->commands[le16toh(desc->AddressReply.SMID)]; 1914212420Sken cm->cm_reply = reply; 1915212420Sken cm->cm_reply_data = 1916237683Sken le32toh(desc->AddressReply.ReplyFrameAddress); 1917212420Sken } 1918212420Sken break; 1919212420Sken } 1920212420Sken case MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS: 1921212420Sken case MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER: 1922212420Sken case MPI2_RPY_DESCRIPT_FLAGS_RAID_ACCELERATOR_SUCCESS: 1923212420Sken default: 1924212420Sken /* Unhandled */ 1925253460Sscottl mps_dprint(sc, MPS_ERROR, "Unhandled reply 0x%x\n", 1926212420Sken desc->Default.ReplyFlags); 1927212420Sken cm = NULL; 1928212420Sken break; 1929212420Sken } 1930237683Sken 1931212420Sken 1932237683Sken if (cm != NULL) { 1933237683Sken // Print Error reply frame 1934237683Sken if (cm->cm_reply) 1935237683Sken mps_display_reply_info(sc,cm->cm_reply); 1936253460Sscottl mps_complete_command(sc, cm); 1937237683Sken } 1938212420Sken 1939212420Sken desc->Words.Low = 0xffffffff; 1940212420Sken desc->Words.High = 0xffffffff; 1941212420Sken } 1942212420Sken 1943212420Sken if (pq != sc->replypostindex) { 1944230592Sken mps_dprint(sc, MPS_TRACE, 1945230592Sken "%s sc %p writing postindex %d\n", 1946230592Sken __func__, sc, sc->replypostindex); 1947230592Sken mps_regwrite(sc, MPI2_REPLY_POST_HOST_INDEX_OFFSET, sc->replypostindex); 1948212420Sken } 1949212420Sken 1950212420Sken return; 1951212420Sken} 1952212420Sken 1953212420Skenstatic void 1954212420Skenmps_dispatch_event(struct mps_softc *sc, uintptr_t data, 1955212420Sken MPI2_EVENT_NOTIFICATION_REPLY *reply) 1956212420Sken{ 1957212420Sken struct mps_event_handle *eh; 1958216227Skevlo int event, handled = 0; 1959212420Sken 1960237683Sken event = le16toh(reply->Event); 1961212420Sken TAILQ_FOREACH(eh, &sc->event_list, eh_list) { 1962212420Sken if (isset(eh->mask, event)) { 1963212420Sken eh->callback(sc, data, reply); 1964212420Sken handled++; 1965212420Sken } 1966212420Sken } 1967212420Sken 1968212420Sken if (handled == 0) 1969253460Sscottl mps_dprint(sc, MPS_EVENT, "Unhandled event 0x%x\n", le16toh(event)); 1970230592Sken 1971230592Sken /* 1972230592Sken * This is the only place that the event/reply should be freed. 1973230592Sken * Anything wanting to hold onto the event data should have 1974230592Sken * already copied it into their own storage. 1975230592Sken */ 1976230592Sken mps_free_reply(sc, data); 1977212420Sken} 1978212420Sken 1979230592Skenstatic void 1980230592Skenmps_reregister_events_complete(struct mps_softc *sc, struct mps_command *cm) 1981230592Sken{ 1982230592Sken mps_dprint(sc, MPS_TRACE, "%s\n", __func__); 1983230592Sken 1984230592Sken if (cm->cm_reply) 1985230592Sken mps_print_event(sc, 1986230592Sken (MPI2_EVENT_NOTIFICATION_REPLY *)cm->cm_reply); 1987230592Sken 1988230592Sken mps_free_command(sc, cm); 1989230592Sken 1990230592Sken /* next, send a port enable */ 1991230592Sken mpssas_startup(sc); 1992230592Sken} 1993230592Sken 1994212420Sken/* 1995212420Sken * For both register_events and update_events, the caller supplies a bitmap 1996212420Sken * of events that it _wants_. These functions then turn that into a bitmask 1997212420Sken * suitable for the controller. 1998212420Sken */ 1999212420Skenint 2000237683Skenmps_register_events(struct mps_softc *sc, u32 *mask, 2001212420Sken mps_evt_callback_t *cb, void *data, struct mps_event_handle **handle) 2002212420Sken{ 2003212420Sken struct mps_event_handle *eh; 2004212420Sken int error = 0; 2005212420Sken 2006212420Sken eh = malloc(sizeof(struct mps_event_handle), M_MPT2, M_WAITOK|M_ZERO); 2007237683Sken if(!eh) { 2008237683Sken device_printf(sc->mps_dev, "Cannot allocate memory %s %d\n", 2009237683Sken __func__, __LINE__); 2010237683Sken return (ENOMEM); 2011237683Sken } 2012212420Sken eh->callback = cb; 2013212420Sken eh->data = data; 2014212420Sken TAILQ_INSERT_TAIL(&sc->event_list, eh, eh_list); 2015212420Sken if (mask != NULL) 2016212420Sken error = mps_update_events(sc, eh, mask); 2017212420Sken *handle = eh; 2018212420Sken 2019212420Sken return (error); 2020212420Sken} 2021212420Sken 2022212420Skenint 2023212420Skenmps_update_events(struct mps_softc *sc, struct mps_event_handle *handle, 2024237683Sken u32 *mask) 2025212420Sken{ 2026212420Sken MPI2_EVENT_NOTIFICATION_REQUEST *evtreq; 2027212420Sken MPI2_EVENT_NOTIFICATION_REPLY *reply; 2028212420Sken struct mps_command *cm; 2029212420Sken int error, i; 2030212420Sken 2031212420Sken mps_dprint(sc, MPS_TRACE, "%s\n", __func__); 2032212420Sken 2033212420Sken if ((mask != NULL) && (handle != NULL)) 2034237683Sken bcopy(mask, &handle->mask[0], sizeof(u32) * 2035237683Sken MPI2_EVENT_NOTIFY_EVENTMASK_WORDS); 2036237683Sken 2037237683Sken for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) 2038237683Sken sc->event_mask[i] = -1; 2039212420Sken 2040237683Sken for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) 2041237683Sken sc->event_mask[i] &= ~handle->mask[i]; 2042212420Sken 2043237683Sken 2044212420Sken if ((cm = mps_alloc_command(sc)) == NULL) 2045212420Sken return (EBUSY); 2046212420Sken evtreq = (MPI2_EVENT_NOTIFICATION_REQUEST *)cm->cm_req; 2047212420Sken evtreq->Function = MPI2_FUNCTION_EVENT_NOTIFICATION; 2048212420Sken evtreq->MsgFlags = 0; 2049212420Sken evtreq->SASBroadcastPrimitiveMasks = 0; 2050212420Sken#ifdef MPS_DEBUG_ALL_EVENTS 2051212420Sken { 2052212420Sken u_char fullmask[16]; 2053212420Sken memset(fullmask, 0x00, 16); 2054237683Sken bcopy(fullmask, &evtreq->EventMasks[0], sizeof(u32) * 2055237683Sken MPI2_EVENT_NOTIFY_EVENTMASK_WORDS); 2056212420Sken } 2057212420Sken#else 2058237683Sken for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) 2059237683Sken evtreq->EventMasks[i] = 2060237683Sken htole32(sc->event_mask[i]); 2061212420Sken#endif 2062212420Sken cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 2063212420Sken cm->cm_data = NULL; 2064212420Sken 2065212420Sken error = mps_request_polled(sc, cm); 2066212420Sken reply = (MPI2_EVENT_NOTIFICATION_REPLY *)cm->cm_reply; 2067230592Sken if ((reply == NULL) || 2068230592Sken (reply->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS) 2069212420Sken error = ENXIO; 2070212420Sken mps_print_event(sc, reply); 2071230592Sken mps_dprint(sc, MPS_TRACE, "%s finished error %d\n", __func__, error); 2072212420Sken 2073212420Sken mps_free_command(sc, cm); 2074212420Sken return (error); 2075212420Sken} 2076212420Sken 2077230592Skenstatic int 2078230592Skenmps_reregister_events(struct mps_softc *sc) 2079230592Sken{ 2080230592Sken MPI2_EVENT_NOTIFICATION_REQUEST *evtreq; 2081230592Sken struct mps_command *cm; 2082230592Sken struct mps_event_handle *eh; 2083230592Sken int error, i; 2084230592Sken 2085230592Sken mps_dprint(sc, MPS_TRACE, "%s\n", __func__); 2086230592Sken 2087230592Sken /* first, reregister events */ 2088230592Sken 2089253550Sken for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) 2090237683Sken sc->event_mask[i] = -1; 2091230592Sken 2092230592Sken TAILQ_FOREACH(eh, &sc->event_list, eh_list) { 2093237683Sken for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) 2094230592Sken sc->event_mask[i] &= ~eh->mask[i]; 2095230592Sken } 2096230592Sken 2097230592Sken if ((cm = mps_alloc_command(sc)) == NULL) 2098230592Sken return (EBUSY); 2099230592Sken evtreq = (MPI2_EVENT_NOTIFICATION_REQUEST *)cm->cm_req; 2100230592Sken evtreq->Function = MPI2_FUNCTION_EVENT_NOTIFICATION; 2101230592Sken evtreq->MsgFlags = 0; 2102230592Sken evtreq->SASBroadcastPrimitiveMasks = 0; 2103230592Sken#ifdef MPS_DEBUG_ALL_EVENTS 2104230592Sken { 2105230592Sken u_char fullmask[16]; 2106230592Sken memset(fullmask, 0x00, 16); 2107237683Sken bcopy(fullmask, &evtreq->EventMasks[0], sizeof(u32) * 2108237683Sken MPI2_EVENT_NOTIFY_EVENTMASK_WORDS); 2109230592Sken } 2110230592Sken#else 2111237683Sken for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) 2112237683Sken evtreq->EventMasks[i] = 2113237683Sken htole32(sc->event_mask[i]); 2114230592Sken#endif 2115230592Sken cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 2116230592Sken cm->cm_data = NULL; 2117230592Sken cm->cm_complete = mps_reregister_events_complete; 2118230592Sken 2119230592Sken error = mps_map_command(sc, cm); 2120230592Sken 2121253550Sken mps_dprint(sc, MPS_TRACE, "%s finished with error %d\n", __func__, 2122253550Sken error); 2123230592Sken return (error); 2124230592Sken} 2125230592Sken 2126237683Skenvoid 2127212420Skenmps_deregister_events(struct mps_softc *sc, struct mps_event_handle *handle) 2128212420Sken{ 2129212420Sken 2130212420Sken TAILQ_REMOVE(&sc->event_list, handle, eh_list); 2131212420Sken free(handle, M_MPT2); 2132212420Sken} 2133212420Sken 2134213839Smdf/* 2135213839Smdf * Add a chain element as the next SGE for the specified command. 2136213839Smdf * Reset cm_sge and cm_sgesize to indicate all the available space. 2137213839Smdf */ 2138213839Smdfstatic int 2139213839Smdfmps_add_chain(struct mps_command *cm) 2140212420Sken{ 2141212420Sken MPI2_SGE_CHAIN32 *sgc; 2142212420Sken struct mps_chain *chain; 2143213839Smdf int space; 2144212420Sken 2145213839Smdf if (cm->cm_sglsize < MPS_SGC_SIZE) 2146213839Smdf panic("MPS: Need SGE Error Code\n"); 2147212420Sken 2148213839Smdf chain = mps_alloc_chain(cm->cm_sc); 2149213839Smdf if (chain == NULL) 2150213839Smdf return (ENOBUFS); 2151212420Sken 2152213839Smdf space = (int)cm->cm_sc->facts->IOCRequestFrameSize * 4; 2153213839Smdf 2154212420Sken /* 2155213839Smdf * Note: a double-linked list is used to make it easier to 2156213839Smdf * walk for debugging. 2157212420Sken */ 2158213839Smdf TAILQ_INSERT_TAIL(&cm->cm_chain_list, chain, chain_link); 2159212420Sken 2160213839Smdf sgc = (MPI2_SGE_CHAIN32 *)&cm->cm_sge->MpiChain; 2161237683Sken sgc->Length = htole16(space); 2162213839Smdf sgc->NextChainOffset = 0; 2163237683Sken /* TODO Looks like bug in Setting sgc->Flags. 2164237683Sken * sgc->Flags = ( MPI2_SGE_FLAGS_CHAIN_ELEMENT | MPI2_SGE_FLAGS_64_BIT_ADDRESSING | 2165237683Sken * MPI2_SGE_FLAGS_SYSTEM_ADDRESS) << MPI2_SGE_FLAGS_SHIFT 2166237683Sken * This is fine.. because we are not using simple element. In case of 2167237683Sken * MPI2_SGE_CHAIN32, we have seperate Length and Flags feild. 2168237683Sken */ 2169213839Smdf sgc->Flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT; 2170237683Sken sgc->Address = htole32(chain->chain_busaddr); 2171213839Smdf 2172213839Smdf cm->cm_sge = (MPI2_SGE_IO_UNION *)&chain->chain->MpiSimple; 2173213839Smdf cm->cm_sglsize = space; 2174213839Smdf return (0); 2175213839Smdf} 2176213839Smdf 2177213839Smdf/* 2178213839Smdf * Add one scatter-gather element (chain, simple, transaction context) 2179213839Smdf * to the scatter-gather list for a command. Maintain cm_sglsize and 2180213839Smdf * cm_sge as the remaining size and pointer to the next SGE to fill 2181213839Smdf * in, respectively. 2182213839Smdf */ 2183213839Smdfint 2184213839Smdfmps_push_sge(struct mps_command *cm, void *sgep, size_t len, int segsleft) 2185213839Smdf{ 2186213839Smdf MPI2_SGE_TRANSACTION_UNION *tc = sgep; 2187213839Smdf MPI2_SGE_SIMPLE64 *sge = sgep; 2188213839Smdf int error, type; 2189230592Sken uint32_t saved_buf_len, saved_address_low, saved_address_high; 2190213839Smdf 2191213839Smdf type = (tc->Flags & MPI2_SGE_FLAGS_ELEMENT_MASK); 2192213839Smdf 2193213839Smdf#ifdef INVARIANTS 2194213839Smdf switch (type) { 2195213839Smdf case MPI2_SGE_FLAGS_TRANSACTION_ELEMENT: { 2196213839Smdf if (len != tc->DetailsLength + 4) 2197213839Smdf panic("TC %p length %u or %zu?", tc, 2198213839Smdf tc->DetailsLength + 4, len); 2199213839Smdf } 2200213839Smdf break; 2201213839Smdf case MPI2_SGE_FLAGS_CHAIN_ELEMENT: 2202213839Smdf /* Driver only uses 32-bit chain elements */ 2203213839Smdf if (len != MPS_SGC_SIZE) 2204213839Smdf panic("CHAIN %p length %u or %zu?", sgep, 2205213839Smdf MPS_SGC_SIZE, len); 2206213839Smdf break; 2207213839Smdf case MPI2_SGE_FLAGS_SIMPLE_ELEMENT: 2208213839Smdf /* Driver only uses 64-bit SGE simple elements */ 2209213839Smdf if (len != MPS_SGE64_SIZE) 2210213839Smdf panic("SGE simple %p length %u or %zu?", sge, 2211213839Smdf MPS_SGE64_SIZE, len); 2212238974Smav if (((le32toh(sge->FlagsLength) >> MPI2_SGE_FLAGS_SHIFT) & 2213213839Smdf MPI2_SGE_FLAGS_ADDRESS_SIZE) == 0) 2214238974Smav panic("SGE simple %p not marked 64-bit?", sge); 2215213839Smdf 2216213839Smdf break; 2217213839Smdf default: 2218213839Smdf panic("Unexpected SGE %p, flags %02x", tc, tc->Flags); 2219213839Smdf } 2220213839Smdf#endif 2221213839Smdf 2222212420Sken /* 2223212420Sken * case 1: 1 more segment, enough room for it 2224212420Sken * case 2: 2 more segments, enough room for both 2225212420Sken * case 3: >=2 more segments, only enough room for 1 and a chain 2226212420Sken * case 4: >=1 more segment, enough room for only a chain 2227212420Sken * case 5: >=1 more segment, no room for anything (error) 2228213839Smdf */ 2229213839Smdf 2230213839Smdf /* 2231213839Smdf * There should be room for at least a chain element, or this 2232213839Smdf * code is buggy. Case (5). 2233212420Sken */ 2234213839Smdf if (cm->cm_sglsize < MPS_SGC_SIZE) 2235213839Smdf panic("MPS: Need SGE Error Code\n"); 2236212420Sken 2237213839Smdf if (segsleft >= 2 && 2238213839Smdf cm->cm_sglsize < len + MPS_SGC_SIZE + MPS_SGE64_SIZE) { 2239213839Smdf /* 2240213839Smdf * There are 2 or more segments left to add, and only 2241213839Smdf * enough room for 1 and a chain. Case (3). 2242213839Smdf * 2243213839Smdf * Mark as last element in this chain if necessary. 2244213839Smdf */ 2245213839Smdf if (type == MPI2_SGE_FLAGS_SIMPLE_ELEMENT) { 2246238974Smav sge->FlagsLength |= htole32( 2247238974Smav MPI2_SGE_FLAGS_LAST_ELEMENT << MPI2_SGE_FLAGS_SHIFT); 2248212420Sken } 2249212420Sken 2250212420Sken /* 2251213839Smdf * Add the item then a chain. Do the chain now, 2252213839Smdf * rather than on the next iteration, to simplify 2253213839Smdf * understanding the code. 2254212420Sken */ 2255213839Smdf cm->cm_sglsize -= len; 2256213839Smdf bcopy(sgep, cm->cm_sge, len); 2257213839Smdf cm->cm_sge = (MPI2_SGE_IO_UNION *)((uintptr_t)cm->cm_sge + len); 2258213839Smdf return (mps_add_chain(cm)); 2259213839Smdf } 2260212420Sken 2261213839Smdf if (segsleft >= 1 && cm->cm_sglsize < len + MPS_SGC_SIZE) { 2262213839Smdf /* 2263213839Smdf * 1 or more segment, enough room for only a chain. 2264213839Smdf * Hope the previous element wasn't a Simple entry 2265213839Smdf * that needed to be marked with 2266213839Smdf * MPI2_SGE_FLAGS_LAST_ELEMENT. Case (4). 2267213839Smdf */ 2268213839Smdf if ((error = mps_add_chain(cm)) != 0) 2269213839Smdf return (error); 2270213839Smdf } 2271212420Sken 2272213839Smdf#ifdef INVARIANTS 2273213839Smdf /* Case 1: 1 more segment, enough room for it. */ 2274213839Smdf if (segsleft == 1 && cm->cm_sglsize < len) 2275213839Smdf panic("1 seg left and no room? %u versus %zu", 2276213839Smdf cm->cm_sglsize, len); 2277212420Sken 2278213839Smdf /* Case 2: 2 more segments, enough room for both */ 2279213839Smdf if (segsleft == 2 && cm->cm_sglsize < len + MPS_SGE64_SIZE) 2280213839Smdf panic("2 segs left and no room? %u versus %zu", 2281213839Smdf cm->cm_sglsize, len); 2282213839Smdf#endif 2283212420Sken 2284213839Smdf if (segsleft == 1 && type == MPI2_SGE_FLAGS_SIMPLE_ELEMENT) { 2285213839Smdf /* 2286230592Sken * If this is a bi-directional request, need to account for that 2287230592Sken * here. Save the pre-filled sge values. These will be used 2288230592Sken * either for the 2nd SGL or for a single direction SGL. If 2289230592Sken * cm_out_len is non-zero, this is a bi-directional request, so 2290230592Sken * fill in the OUT SGL first, then the IN SGL, otherwise just 2291230592Sken * fill in the IN SGL. Note that at this time, when filling in 2292230592Sken * 2 SGL's for a bi-directional request, they both use the same 2293230592Sken * DMA buffer (same cm command). 2294213839Smdf */ 2295238974Smav saved_buf_len = le32toh(sge->FlagsLength) & 0x00FFFFFF; 2296230592Sken saved_address_low = sge->Address.Low; 2297230592Sken saved_address_high = sge->Address.High; 2298230592Sken if (cm->cm_out_len) { 2299238974Smav sge->FlagsLength = htole32(cm->cm_out_len | 2300230592Sken ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT | 2301230592Sken MPI2_SGE_FLAGS_END_OF_BUFFER | 2302230592Sken MPI2_SGE_FLAGS_HOST_TO_IOC | 2303230592Sken MPI2_SGE_FLAGS_64_BIT_ADDRESSING) << 2304238974Smav MPI2_SGE_FLAGS_SHIFT)); 2305230592Sken cm->cm_sglsize -= len; 2306230592Sken bcopy(sgep, cm->cm_sge, len); 2307230592Sken cm->cm_sge = (MPI2_SGE_IO_UNION *)((uintptr_t)cm->cm_sge 2308230592Sken + len); 2309230592Sken } 2310238974Smav saved_buf_len |= 2311230592Sken ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT | 2312213839Smdf MPI2_SGE_FLAGS_END_OF_BUFFER | 2313230592Sken MPI2_SGE_FLAGS_LAST_ELEMENT | 2314230592Sken MPI2_SGE_FLAGS_END_OF_LIST | 2315230592Sken MPI2_SGE_FLAGS_64_BIT_ADDRESSING) << 2316230592Sken MPI2_SGE_FLAGS_SHIFT); 2317230592Sken if (cm->cm_flags & MPS_CM_FLAGS_DATAIN) { 2318238974Smav saved_buf_len |= 2319230592Sken ((uint32_t)(MPI2_SGE_FLAGS_IOC_TO_HOST) << 2320230592Sken MPI2_SGE_FLAGS_SHIFT); 2321230592Sken } else { 2322238974Smav saved_buf_len |= 2323230592Sken ((uint32_t)(MPI2_SGE_FLAGS_HOST_TO_IOC) << 2324230592Sken MPI2_SGE_FLAGS_SHIFT); 2325230592Sken } 2326238974Smav sge->FlagsLength = htole32(saved_buf_len); 2327230592Sken sge->Address.Low = saved_address_low; 2328230592Sken sge->Address.High = saved_address_high; 2329213839Smdf } 2330212420Sken 2331213839Smdf cm->cm_sglsize -= len; 2332213839Smdf bcopy(sgep, cm->cm_sge, len); 2333213839Smdf cm->cm_sge = (MPI2_SGE_IO_UNION *)((uintptr_t)cm->cm_sge + len); 2334213839Smdf return (0); 2335213839Smdf} 2336212420Sken 2337213839Smdf/* 2338213839Smdf * Add one dma segment to the scatter-gather list for a command. 2339213839Smdf */ 2340213839Smdfint 2341213839Smdfmps_add_dmaseg(struct mps_command *cm, vm_paddr_t pa, size_t len, u_int flags, 2342213839Smdf int segsleft) 2343213839Smdf{ 2344213839Smdf MPI2_SGE_SIMPLE64 sge; 2345212420Sken 2346213839Smdf /* 2347230592Sken * This driver always uses 64-bit address elements for simplicity. 2348213839Smdf */ 2349238974Smav bzero(&sge, sizeof(sge)); 2350230592Sken flags |= MPI2_SGE_FLAGS_SIMPLE_ELEMENT | 2351230592Sken MPI2_SGE_FLAGS_64_BIT_ADDRESSING; 2352238974Smav sge.FlagsLength = htole32(len | (flags << MPI2_SGE_FLAGS_SHIFT)); 2353213839Smdf mps_from_u64(pa, &sge.Address); 2354212420Sken 2355213839Smdf return (mps_push_sge(cm, &sge, sizeof sge, segsleft)); 2356213839Smdf} 2357213839Smdf 2358213839Smdfstatic void 2359213839Smdfmps_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 2360213839Smdf{ 2361213839Smdf struct mps_softc *sc; 2362213839Smdf struct mps_command *cm; 2363213839Smdf u_int i, dir, sflags; 2364213839Smdf 2365213839Smdf cm = (struct mps_command *)arg; 2366213839Smdf sc = cm->cm_sc; 2367213839Smdf 2368213839Smdf /* 2369216088Sken * In this case, just print out a warning and let the chip tell the 2370216088Sken * user they did the wrong thing. 2371213839Smdf */ 2372216088Sken if ((cm->cm_max_segs != 0) && (nsegs > cm->cm_max_segs)) { 2373253460Sscottl mps_dprint(sc, MPS_ERROR, 2374253460Sscottl "%s: warning: busdma returned %d segments, " 2375216088Sken "more than the %d allowed\n", __func__, nsegs, 2376216088Sken cm->cm_max_segs); 2377216088Sken } 2378216088Sken 2379216088Sken /* 2380230592Sken * Set up DMA direction flags. Bi-directional requests are also handled 2381230592Sken * here. In that case, both direction flags will be set. 2382216088Sken */ 2383213839Smdf sflags = 0; 2384216088Sken if (cm->cm_flags & MPS_CM_FLAGS_SMP_PASS) { 2385216088Sken /* 2386216088Sken * We have to add a special case for SMP passthrough, there 2387216088Sken * is no easy way to generically handle it. The first 2388216088Sken * S/G element is used for the command (therefore the 2389216088Sken * direction bit needs to be set). The second one is used 2390216088Sken * for the reply. We'll leave it to the caller to make 2391216088Sken * sure we only have two buffers. 2392216088Sken */ 2393216088Sken /* 2394216088Sken * Even though the busdma man page says it doesn't make 2395216088Sken * sense to have both direction flags, it does in this case. 2396216088Sken * We have one s/g element being accessed in each direction. 2397216088Sken */ 2398216088Sken dir = BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD; 2399216088Sken 2400216088Sken /* 2401216088Sken * Set the direction flag on the first buffer in the SMP 2402216088Sken * passthrough request. We'll clear it for the second one. 2403216088Sken */ 2404216088Sken sflags |= MPI2_SGE_FLAGS_DIRECTION | 2405216088Sken MPI2_SGE_FLAGS_END_OF_BUFFER; 2406216088Sken } else if (cm->cm_flags & MPS_CM_FLAGS_DATAOUT) { 2407230592Sken sflags |= MPI2_SGE_FLAGS_HOST_TO_IOC; 2408213839Smdf dir = BUS_DMASYNC_PREWRITE; 2409213839Smdf } else 2410213839Smdf dir = BUS_DMASYNC_PREREAD; 2411213839Smdf 2412213839Smdf for (i = 0; i < nsegs; i++) { 2413230592Sken if ((cm->cm_flags & MPS_CM_FLAGS_SMP_PASS) && (i != 0)) { 2414216088Sken sflags &= ~MPI2_SGE_FLAGS_DIRECTION; 2415216088Sken } 2416213839Smdf error = mps_add_dmaseg(cm, segs[i].ds_addr, segs[i].ds_len, 2417213839Smdf sflags, nsegs - i); 2418213839Smdf if (error != 0) { 2419213839Smdf /* Resource shortage, roll back! */ 2420254117Sscottl if (ratecheck(&sc->lastfail, &mps_chainfail_interval)) 2421254117Sscottl mps_dprint(sc, MPS_INFO, "Out of chain frames, " 2422254117Sscottl "consider increasing hw.mps.max_chains.\n"); 2423218812Sken cm->cm_flags |= MPS_CM_FLAGS_CHAIN_FAILED; 2424253460Sscottl mps_complete_command(sc, cm); 2425213839Smdf return; 2426213839Smdf } 2427212420Sken } 2428212420Sken 2429212420Sken bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir); 2430212420Sken mps_enqueue_request(sc, cm); 2431212420Sken 2432212420Sken return; 2433212420Sken} 2434212420Sken 2435216088Skenstatic void 2436216088Skenmps_data_cb2(void *arg, bus_dma_segment_t *segs, int nsegs, bus_size_t mapsize, 2437216088Sken int error) 2438216088Sken{ 2439216088Sken mps_data_cb(arg, segs, nsegs, error); 2440216088Sken} 2441216088Sken 2442213535Sken/* 2443230592Sken * This is the routine to enqueue commands ansynchronously. 2444213535Sken * Note that the only error path here is from bus_dmamap_load(), which can 2445230592Sken * return EINPROGRESS if it is waiting for resources. Other than this, it's 2446230592Sken * assumed that if you have a command in-hand, then you have enough credits 2447230592Sken * to use it. 2448213535Sken */ 2449212420Skenint 2450212420Skenmps_map_command(struct mps_softc *sc, struct mps_command *cm) 2451212420Sken{ 2452212420Sken int error = 0; 2453212420Sken 2454216088Sken if (cm->cm_flags & MPS_CM_FLAGS_USE_UIO) { 2455216088Sken error = bus_dmamap_load_uio(sc->buffer_dmat, cm->cm_dmamap, 2456216088Sken &cm->cm_uio, mps_data_cb2, cm, 0); 2457246713Skib } else if (cm->cm_flags & MPS_CM_FLAGS_USE_CCB) { 2458246713Skib error = bus_dmamap_load_ccb(sc->buffer_dmat, cm->cm_dmamap, 2459246713Skib cm->cm_data, mps_data_cb, cm, 0); 2460216088Sken } else if ((cm->cm_data != NULL) && (cm->cm_length != 0)) { 2461212420Sken error = bus_dmamap_load(sc->buffer_dmat, cm->cm_dmamap, 2462212420Sken cm->cm_data, cm->cm_length, mps_data_cb, cm, 0); 2463212420Sken } else { 2464212420Sken /* Add a zero-length element as needed */ 2465238974Smav if (cm->cm_sge != NULL) 2466238974Smav mps_add_dmaseg(cm, 0, 0, 0, 1); 2467230592Sken mps_enqueue_request(sc, cm); 2468212420Sken } 2469212420Sken 2470212420Sken return (error); 2471212420Sken} 2472212420Sken 2473212420Sken/* 2474230592Sken * This is the routine to enqueue commands synchronously. An error of 2475230592Sken * EINPROGRESS from mps_map_command() is ignored since the command will 2476230592Sken * be executed and enqueued automatically. Other errors come from msleep(). 2477230592Sken */ 2478230592Skenint 2479253550Skenmps_wait_command(struct mps_softc *sc, struct mps_command *cm, int timeout, 2480253550Sken int sleep_flag) 2481230592Sken{ 2482237683Sken int error, rc; 2483253550Sken struct timeval cur_time, start_time; 2484230592Sken 2485253550Sken if (sc->mps_flags & MPS_FLAGS_DIAGRESET) 2486237683Sken return EBUSY; 2487230592Sken 2488230592Sken cm->cm_complete = NULL; 2489253550Sken cm->cm_flags |= (MPS_CM_FLAGS_WAKEUP + MPS_CM_FLAGS_POLLED); 2490230592Sken error = mps_map_command(sc, cm); 2491230592Sken if ((error != 0) && (error != EINPROGRESS)) 2492230592Sken return (error); 2493253550Sken 2494253550Sken // Check for context and wait for 50 mSec at a time until time has 2495253550Sken // expired or the command has finished. If msleep can't be used, need 2496253550Sken // to poll. 2497253550Sken if (curthread->td_no_sleeping != 0) 2498253550Sken sleep_flag = NO_SLEEP; 2499253550Sken getmicrotime(&start_time); 2500253550Sken if (mtx_owned(&sc->mps_mtx) && sleep_flag == CAN_SLEEP) { 2501253550Sken error = msleep(cm, &sc->mps_mtx, 0, "mpswait", timeout*hz); 2502253550Sken } else { 2503253550Sken while ((cm->cm_flags & MPS_CM_FLAGS_COMPLETE) == 0) { 2504253550Sken mps_intr_locked(sc); 2505253550Sken if (sleep_flag == CAN_SLEEP) 2506253550Sken pause("mpswait", hz/20); 2507253550Sken else 2508253550Sken DELAY(50000); 2509253550Sken 2510253550Sken getmicrotime(&cur_time); 2511253550Sken if ((cur_time.tv_sec - start_time.tv_sec) > timeout) { 2512253550Sken error = EWOULDBLOCK; 2513253550Sken break; 2514253550Sken } 2515253550Sken } 2516253550Sken } 2517253550Sken 2518237683Sken if (error == EWOULDBLOCK) { 2519237683Sken mps_dprint(sc, MPS_FAULT, "Calling Reinit from %s\n", __func__); 2520237683Sken rc = mps_reinit(sc); 2521253550Sken mps_dprint(sc, MPS_FAULT, "Reinit %s\n", (rc == 0) ? "success" : 2522253550Sken "failed"); 2523230592Sken error = ETIMEDOUT; 2524237683Sken } 2525230592Sken return (error); 2526230592Sken} 2527230592Sken 2528230592Sken/* 2529230592Sken * This is the routine to enqueue a command synchonously and poll for 2530230592Sken * completion. Its use should be rare. 2531230592Sken */ 2532230592Skenint 2533230592Skenmps_request_polled(struct mps_softc *sc, struct mps_command *cm) 2534230592Sken{ 2535237683Sken int error, timeout = 0, rc; 2536230592Sken 2537230592Sken error = 0; 2538230592Sken 2539230592Sken cm->cm_flags |= MPS_CM_FLAGS_POLLED; 2540230592Sken cm->cm_complete = NULL; 2541230592Sken mps_map_command(sc, cm); 2542230592Sken 2543230592Sken while ((cm->cm_flags & MPS_CM_FLAGS_COMPLETE) == 0) { 2544230592Sken mps_intr_locked(sc); 2545237683Sken 2546230592Sken DELAY(50 * 1000); 2547230592Sken if (timeout++ > 1000) { 2548230592Sken mps_dprint(sc, MPS_FAULT, "polling failed\n"); 2549230592Sken error = ETIMEDOUT; 2550230592Sken break; 2551230592Sken } 2552230592Sken } 2553237683Sken 2554237683Sken if (error) { 2555237683Sken mps_dprint(sc, MPS_FAULT, "Calling Reinit from %s\n", __func__); 2556237683Sken rc = mps_reinit(sc); 2557237683Sken mps_dprint(sc, MPS_FAULT, "Reinit %s\n", 2558237683Sken (rc == 0) ? "success" : "failed"); 2559237683Sken } 2560230592Sken 2561230592Sken return (error); 2562230592Sken} 2563230592Sken 2564230592Sken/* 2565212420Sken * The MPT driver had a verbose interface for config pages. In this driver, 2566212420Sken * reduce it to much simplier terms, similar to the Linux driver. 2567212420Sken */ 2568212420Skenint 2569212420Skenmps_read_config_page(struct mps_softc *sc, struct mps_config_params *params) 2570212420Sken{ 2571212420Sken MPI2_CONFIG_REQUEST *req; 2572212420Sken struct mps_command *cm; 2573212420Sken int error; 2574212420Sken 2575212420Sken if (sc->mps_flags & MPS_FLAGS_BUSY) { 2576212420Sken return (EBUSY); 2577212420Sken } 2578212420Sken 2579212420Sken cm = mps_alloc_command(sc); 2580212420Sken if (cm == NULL) { 2581212420Sken return (EBUSY); 2582212420Sken } 2583212420Sken 2584212420Sken req = (MPI2_CONFIG_REQUEST *)cm->cm_req; 2585212420Sken req->Function = MPI2_FUNCTION_CONFIG; 2586212420Sken req->Action = params->action; 2587212420Sken req->SGLFlags = 0; 2588212420Sken req->ChainOffset = 0; 2589212420Sken req->PageAddress = params->page_address; 2590251396Sasomers if (params->hdr.Struct.PageType == MPI2_CONFIG_PAGETYPE_EXTENDED) { 2591212420Sken MPI2_CONFIG_EXTENDED_PAGE_HEADER *hdr; 2592212420Sken 2593212420Sken hdr = ¶ms->hdr.Ext; 2594212420Sken req->ExtPageType = hdr->ExtPageType; 2595212420Sken req->ExtPageLength = hdr->ExtPageLength; 2596212420Sken req->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; 2597212420Sken req->Header.PageLength = 0; /* Must be set to zero */ 2598212420Sken req->Header.PageNumber = hdr->PageNumber; 2599212420Sken req->Header.PageVersion = hdr->PageVersion; 2600212420Sken } else { 2601212420Sken MPI2_CONFIG_PAGE_HEADER *hdr; 2602212420Sken 2603212420Sken hdr = ¶ms->hdr.Struct; 2604212420Sken req->Header.PageType = hdr->PageType; 2605212420Sken req->Header.PageNumber = hdr->PageNumber; 2606212420Sken req->Header.PageLength = hdr->PageLength; 2607212420Sken req->Header.PageVersion = hdr->PageVersion; 2608212420Sken } 2609212420Sken 2610212420Sken cm->cm_data = params->buffer; 2611212420Sken cm->cm_length = params->length; 2612212420Sken cm->cm_sge = &req->PageBufferSGE; 2613212420Sken cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); 2614212420Sken cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN; 2615212420Sken cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 2616212420Sken 2617213743Smdf cm->cm_complete_data = params; 2618212420Sken if (params->callback != NULL) { 2619212420Sken cm->cm_complete = mps_config_complete; 2620212420Sken return (mps_map_command(sc, cm)); 2621212420Sken } else { 2622253550Sken error = mps_wait_command(sc, cm, 0, CAN_SLEEP); 2623230592Sken if (error) { 2624230592Sken mps_dprint(sc, MPS_FAULT, 2625230592Sken "Error %d reading config page\n", error); 2626230592Sken mps_free_command(sc, cm); 2627212420Sken return (error); 2628230592Sken } 2629212420Sken mps_config_complete(sc, cm); 2630212420Sken } 2631212420Sken 2632212420Sken return (0); 2633212420Sken} 2634212420Sken 2635212420Skenint 2636212420Skenmps_write_config_page(struct mps_softc *sc, struct mps_config_params *params) 2637212420Sken{ 2638212420Sken return (EINVAL); 2639212420Sken} 2640212420Sken 2641212420Skenstatic void 2642212420Skenmps_config_complete(struct mps_softc *sc, struct mps_command *cm) 2643212420Sken{ 2644212420Sken MPI2_CONFIG_REPLY *reply; 2645212420Sken struct mps_config_params *params; 2646212420Sken 2647253460Sscottl MPS_FUNCTRACE(sc); 2648212420Sken params = cm->cm_complete_data; 2649212420Sken 2650212420Sken if (cm->cm_data != NULL) { 2651212420Sken bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, 2652212420Sken BUS_DMASYNC_POSTREAD); 2653212420Sken bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap); 2654212420Sken } 2655212420Sken 2656218812Sken /* 2657218812Sken * XXX KDM need to do more error recovery? This results in the 2658218812Sken * device in question not getting probed. 2659218812Sken */ 2660218812Sken if ((cm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) { 2661218812Sken params->status = MPI2_IOCSTATUS_BUSY; 2662230592Sken goto done; 2663218812Sken } 2664218812Sken 2665212420Sken reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; 2666230592Sken if (reply == NULL) { 2667230592Sken params->status = MPI2_IOCSTATUS_BUSY; 2668230592Sken goto done; 2669230592Sken } 2670212420Sken params->status = reply->IOCStatus; 2671212420Sken if (params->hdr.Ext.ExtPageType != 0) { 2672212420Sken params->hdr.Ext.ExtPageType = reply->ExtPageType; 2673212420Sken params->hdr.Ext.ExtPageLength = reply->ExtPageLength; 2674212420Sken } else { 2675212420Sken params->hdr.Struct.PageType = reply->Header.PageType; 2676212420Sken params->hdr.Struct.PageNumber = reply->Header.PageNumber; 2677212420Sken params->hdr.Struct.PageLength = reply->Header.PageLength; 2678212420Sken params->hdr.Struct.PageVersion = reply->Header.PageVersion; 2679212420Sken } 2680212420Sken 2681230592Skendone: 2682212420Sken mps_free_command(sc, cm); 2683212420Sken if (params->callback != NULL) 2684212420Sken params->callback(sc, params); 2685212420Sken 2686212420Sken return; 2687212420Sken} 2688