1227068Sambrisko /*- 2227068Sambrisko * Redistribution and use in source and binary forms, with or without 3227068Sambrisko * modification, are permitted provided that the following conditions 4227068Sambrisko * are met: 5227068Sambrisko * 6227068Sambrisko * Copyright 1994-2009 The FreeBSD Project. 7227068Sambrisko * All rights reserved. 8227068Sambrisko * 9227068Sambrisko * 1. Redistributions of source code must retain the above copyright 10227068Sambrisko * notice, this list of conditions and the following disclaimer. 11227068Sambrisko * 2. Redistributions in binary form must reproduce the above copyright 12227068Sambrisko * notice, this list of conditions and the following disclaimer in the 13227068Sambrisko * documentation and/or other materials provided with the distribution. 14227068Sambrisko * 15227068Sambrisko * THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT``AS IS'' AND 16227068Sambrisko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 17227068Sambrisko * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18227068Sambrisko * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR 19227068Sambrisko * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20227068Sambrisko * EXEMPLARY,OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21227068Sambrisko * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22227068Sambrisko * PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY THEORY 23227068Sambrisko * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24227068Sambrisko * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25227068Sambrisko * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26227068Sambrisko * 27227068Sambrisko * The views and conclusions contained in the software and documentation 28227068Sambrisko * are those of the authors and should not be interpreted as representing 29227068Sambrisko * official policies,either expressed or implied, of the FreeBSD Project. 30227068Sambrisko */ 31227068Sambrisko 32227068Sambrisko 33227068Sambrisko#include <sys/cdefs.h> 34233711Sambrisko__FBSDID("$FreeBSD$"); 35227068Sambrisko 36227068Sambrisko#include "opt_mfi.h" 37227068Sambrisko 38227068Sambrisko#include <sys/param.h> 39227068Sambrisko#include <sys/types.h> 40227068Sambrisko#include <sys/kernel.h> 41227068Sambrisko#include <sys/selinfo.h> 42227068Sambrisko#include <sys/bus.h> 43227068Sambrisko#include <sys/conf.h> 44227068Sambrisko#include <sys/bio.h> 45227068Sambrisko#include <sys/ioccom.h> 46227068Sambrisko#include <sys/eventhandler.h> 47227068Sambrisko#include <sys/callout.h> 48227068Sambrisko#include <sys/uio.h> 49227068Sambrisko#include <machine/bus.h> 50233711Sambrisko#include <sys/sysctl.h> 51227068Sambrisko#include <sys/systm.h> 52227068Sambrisko#include <sys/malloc.h> 53227068Sambrisko 54227068Sambrisko#include <dev/mfi/mfireg.h> 55227068Sambrisko#include <dev/mfi/mfi_ioctl.h> 56227068Sambrisko#include <dev/mfi/mfivar.h> 57227068Sambrisko 58247369Ssmhstruct mfi_cmd_tbolt *mfi_tbolt_get_cmd(struct mfi_softc *sc, struct mfi_command *); 59227068Sambriskounion mfi_mpi2_request_descriptor * 60227068Sambriskomfi_tbolt_get_request_descriptor(struct mfi_softc *sc, uint16_t index); 61227068Sambriskovoid mfi_tbolt_complete_cmd(struct mfi_softc *sc); 62227068Sambriskoint mfi_tbolt_build_io(struct mfi_softc *sc, struct mfi_command *mfi_cmd, 63227068Sambrisko struct mfi_cmd_tbolt *cmd); 64227068Sambriskounion mfi_mpi2_request_descriptor *mfi_tbolt_build_mpt_cmd(struct mfi_softc 65227068Sambrisko *sc, struct mfi_command *cmd); 66227068Sambriskouint8_t 67227068Sambriskomfi_build_mpt_pass_thru(struct mfi_softc *sc, struct mfi_command *mfi_cmd); 68227068Sambriskounion mfi_mpi2_request_descriptor *mfi_build_and_issue_cmd(struct mfi_softc 69227068Sambrisko *sc, struct mfi_command *mfi_cmd); 70227068Sambriskovoid mfi_tbolt_build_ldio(struct mfi_softc *sc, struct mfi_command *mfi_cmd, 71227068Sambrisko struct mfi_cmd_tbolt *cmd); 72227068Sambriskostatic int mfi_tbolt_make_sgl(struct mfi_softc *sc, struct mfi_command 73227068Sambrisko *mfi_cmd, pMpi25IeeeSgeChain64_t sgl_ptr, struct mfi_cmd_tbolt *cmd); 74227068Sambriskovoid 75227068Sambriskomap_tbolt_cmd_status(struct mfi_command *mfi_cmd, uint8_t status, 76227068Sambrisko uint8_t ext_status); 77227068Sambriskostatic void mfi_issue_pending_cmds_again (struct mfi_softc *sc); 78227068Sambriskostatic void mfi_kill_hba (struct mfi_softc *sc); 79227068Sambriskostatic void mfi_process_fw_state_chg_isr(void *arg); 80235014Sambriskostatic void mfi_sync_map_complete(struct mfi_command *); 81235014Sambriskostatic void mfi_queue_map_sync(struct mfi_softc *sc); 82227068Sambrisko 83227068Sambrisko#define MFI_FUSION_ENABLE_INTERRUPT_MASK (0x00000008) 84227068Sambrisko 85247369Ssmh 86247369Ssmhextern int mfi_polled_cmd_timeout; 87247369Ssmhstatic int mfi_fw_reset_test = 0; 88247369Ssmh#ifdef MFI_DEBUG 89247369SsmhTUNABLE_INT("hw.mfi.fw_reset_test", &mfi_fw_reset_test); 90247369SsmhSYSCTL_INT(_hw_mfi, OID_AUTO, fw_reset_test, CTLFLAG_RWTUN, &mfi_fw_reset_test, 91247369Ssmh 0, "Force a firmware reset condition"); 92247369Ssmh#endif 93247369Ssmh 94227068Sambriskovoid 95227068Sambriskomfi_tbolt_enable_intr_ppc(struct mfi_softc *sc) 96227068Sambrisko{ 97227068Sambrisko MFI_WRITE4(sc, MFI_OMSK, ~MFI_FUSION_ENABLE_INTERRUPT_MASK); 98227068Sambrisko MFI_READ4(sc, MFI_OMSK); 99227068Sambrisko} 100227068Sambrisko 101227068Sambriskovoid 102227068Sambriskomfi_tbolt_disable_intr_ppc(struct mfi_softc *sc) 103227068Sambrisko{ 104227068Sambrisko MFI_WRITE4(sc, MFI_OMSK, 0xFFFFFFFF); 105227068Sambrisko MFI_READ4(sc, MFI_OMSK); 106227068Sambrisko} 107227068Sambrisko 108227068Sambriskoint32_t 109227068Sambriskomfi_tbolt_read_fw_status_ppc(struct mfi_softc *sc) 110227068Sambrisko{ 111227068Sambrisko return MFI_READ4(sc, MFI_OSP0); 112227068Sambrisko} 113227068Sambrisko 114227068Sambriskoint32_t 115227068Sambriskomfi_tbolt_check_clear_intr_ppc(struct mfi_softc *sc) 116227068Sambrisko{ 117227068Sambrisko int32_t status, mfi_status = 0; 118227068Sambrisko 119227068Sambrisko status = MFI_READ4(sc, MFI_OSTS); 120227068Sambrisko 121233711Sambrisko if (status & 1) { 122227068Sambrisko MFI_WRITE4(sc, MFI_OSTS, status); 123227068Sambrisko MFI_READ4(sc, MFI_OSTS); 124233711Sambrisko if (status & MFI_STATE_CHANGE_INTERRUPT) { 125227068Sambrisko mfi_status |= MFI_FIRMWARE_STATE_CHANGE; 126227068Sambrisko } 127227068Sambrisko 128227068Sambrisko return mfi_status; 129227068Sambrisko } 130233711Sambrisko if (!(status & MFI_FUSION_ENABLE_INTERRUPT_MASK)) 131227068Sambrisko return 1; 132227068Sambrisko 133227068Sambrisko MFI_READ4(sc, MFI_OSTS); 134227068Sambrisko return 0; 135227068Sambrisko} 136227068Sambrisko 137227068Sambrisko 138227068Sambriskovoid 139233711Sambriskomfi_tbolt_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add, 140227068Sambrisko uint32_t frame_cnt) 141227068Sambrisko{ 142227068Sambrisko bus_add |= (MFI_REQ_DESCRIPT_FLAGS_MFA 143227068Sambrisko << MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 144233711Sambrisko MFI_WRITE4(sc, MFI_IQPL, (uint32_t)bus_add); 145233711Sambrisko MFI_WRITE4(sc, MFI_IQPH, (uint32_t)((uint64_t)bus_add >> 32)); 146227068Sambrisko} 147227068Sambrisko 148235016Sambrisko/* 149227068Sambrisko * mfi_tbolt_adp_reset - For controller reset 150227068Sambrisko * @regs: MFI register set 151227068Sambrisko */ 152235016Sambriskoint 153235016Sambriskomfi_tbolt_adp_reset(struct mfi_softc *sc) 154227068Sambrisko{ 155233711Sambrisko int retry = 0, i = 0; 156233711Sambrisko int HostDiag; 157227068Sambrisko 158233711Sambrisko MFI_WRITE4(sc, MFI_WSR, 0xF); 159233711Sambrisko MFI_WRITE4(sc, MFI_WSR, 4); 160233711Sambrisko MFI_WRITE4(sc, MFI_WSR, 0xB); 161233711Sambrisko MFI_WRITE4(sc, MFI_WSR, 2); 162233711Sambrisko MFI_WRITE4(sc, MFI_WSR, 7); 163233711Sambrisko MFI_WRITE4(sc, MFI_WSR, 0xD); 164227068Sambrisko 165233711Sambrisko for (i = 0; i < 10000; i++) ; 166227068Sambrisko 167233711Sambrisko HostDiag = (uint32_t)MFI_READ4(sc, MFI_HDR); 168227068Sambrisko 169233711Sambrisko while (!( HostDiag & DIAG_WRITE_ENABLE)) { 170233711Sambrisko for (i = 0; i < 1000; i++); 171233711Sambrisko HostDiag = (uint32_t)MFI_READ4(sc, MFI_HDR); 172247369Ssmh device_printf(sc->mfi_dev, "ADP_RESET_TBOLT: retry time=%d, " 173247369Ssmh "hostdiag=%#x\n", retry, HostDiag); 174227068Sambrisko 175233711Sambrisko if (retry++ >= 100) 176233711Sambrisko return 1; 177233711Sambrisko } 178227068Sambrisko 179247369Ssmh device_printf(sc->mfi_dev, "ADP_RESET_TBOLT: HostDiag=%#x\n", HostDiag); 180227068Sambrisko 181233711Sambrisko MFI_WRITE4(sc, MFI_HDR, (HostDiag | DIAG_RESET_ADAPTER)); 182227068Sambrisko 183233711Sambrisko for (i=0; i < 10; i++) { 184233711Sambrisko for (i = 0; i < 10000; i++); 185233711Sambrisko } 186227068Sambrisko 187233711Sambrisko HostDiag = (uint32_t)MFI_READ4(sc, MFI_RSR); 188233711Sambrisko while (HostDiag & DIAG_RESET_ADAPTER) { 189233711Sambrisko for (i = 0; i < 1000; i++) ; 190233711Sambrisko HostDiag = (uint32_t)MFI_READ4(sc, MFI_RSR); 191247369Ssmh device_printf(sc->mfi_dev, "ADP_RESET_TBOLT: retry time=%d, " 192247369Ssmh "hostdiag=%#x\n", retry, HostDiag); 193227068Sambrisko 194233711Sambrisko if (retry++ >= 1000) 195233711Sambrisko return 1; 196233711Sambrisko } 197233711Sambrisko return 0; 198227068Sambrisko} 199227068Sambrisko 200227068Sambrisko/* 201235016Sambrisko * This routine initialize Thunderbolt specific device information 202227068Sambrisko */ 203235016Sambriskovoid 204235016Sambriskomfi_tbolt_init_globals(struct mfi_softc *sc) 205227068Sambrisko{ 206227068Sambrisko /* Initialize single reply size and Message size */ 207227068Sambrisko sc->reply_size = MEGASAS_THUNDERBOLT_REPLY_SIZE; 208227068Sambrisko sc->raid_io_msg_size = MEGASAS_THUNDERBOLT_NEW_MSG_SIZE; 209227068Sambrisko 210227068Sambrisko /* 211227068Sambrisko * Calculating how many SGEs allowed in a allocated main message 212227068Sambrisko * (size of the Message - Raid SCSI IO message size(except SGE)) 213227068Sambrisko * / size of SGE 214227068Sambrisko * (0x100 - (0x90 - 0x10)) / 0x10 = 8 215227068Sambrisko */ 216227068Sambrisko sc->max_SGEs_in_main_message = 217227068Sambrisko (uint8_t)((sc->raid_io_msg_size 218227068Sambrisko - (sizeof(struct mfi_mpi2_request_raid_scsi_io) 219227068Sambrisko - sizeof(MPI2_SGE_IO_UNION))) / sizeof(MPI2_SGE_IO_UNION)); 220227068Sambrisko /* 221227068Sambrisko * (Command frame size allocaed in SRB ext - Raid SCSI IO message size) 222227068Sambrisko * / size of SGL ; 223227068Sambrisko * (1280 - 256) / 16 = 64 224227068Sambrisko */ 225227068Sambrisko sc->max_SGEs_in_chain_message = (MR_COMMAND_SIZE 226227068Sambrisko - sc->raid_io_msg_size) / sizeof(MPI2_SGE_IO_UNION); 227227068Sambrisko /* 228227068Sambrisko * (0x08-1) + 0x40 = 0x47 - 0x01 = 0x46 one is left for command 229227068Sambrisko * colscing 230227068Sambrisko */ 231227068Sambrisko sc->mfi_max_sge = (sc->max_SGEs_in_main_message - 1) 232227068Sambrisko + sc->max_SGEs_in_chain_message - 1; 233227068Sambrisko /* 234227068Sambrisko * This is the offset in number of 4 * 32bit words to the next chain 235227068Sambrisko * (0x100 - 0x10)/0x10 = 0xF(15) 236227068Sambrisko */ 237227068Sambrisko sc->chain_offset_value_for_main_message = (sc->raid_io_msg_size 238227068Sambrisko - sizeof(MPI2_SGE_IO_UNION))/16; 239227068Sambrisko sc->chain_offset_value_for_mpt_ptmsg 240227068Sambrisko = offsetof(struct mfi_mpi2_request_raid_scsi_io, SGL)/16; 241227068Sambrisko sc->mfi_cmd_pool_tbolt = NULL; 242227068Sambrisko sc->request_desc_pool = NULL; 243227068Sambrisko} 244227068Sambrisko 245227068Sambrisko/* 246235016Sambrisko * This function calculates the memory requirement for Thunderbolt 247235016Sambrisko * controller, returns the total required memory in bytes 248227068Sambrisko */ 249227068Sambrisko 250235016Sambriskouint32_t 251235016Sambriskomfi_tbolt_get_memory_requirement(struct mfi_softc *sc) 252227068Sambrisko{ 253227068Sambrisko uint32_t size; 254233711Sambrisko size = MEGASAS_THUNDERBOLT_MSG_ALLIGNMENT; /* for Alignment */ 255227068Sambrisko size += sc->raid_io_msg_size * (sc->mfi_max_fw_cmds + 1); 256227068Sambrisko size += sc->reply_size * sc->mfi_max_fw_cmds; 257233711Sambrisko /* this is for SGL's */ 258227068Sambrisko size += MEGASAS_MAX_SZ_CHAIN_FRAME * sc->mfi_max_fw_cmds; 259227068Sambrisko return size; 260227068Sambrisko} 261227068Sambrisko 262227068Sambrisko/* 263227068Sambrisko * Description: 264227068Sambrisko * This function will prepare message pools for the Thunderbolt controller 265227068Sambrisko * Arguments: 266227068Sambrisko * DevExt - HBA miniport driver's adapter data storage structure 267227068Sambrisko * pMemLocation - start of the memory allocated for Thunderbolt. 268227068Sambrisko * Return Value: 269227068Sambrisko * TRUE if successful 270227068Sambrisko * FALSE if failed 271227068Sambrisko */ 272235016Sambriskoint 273235016Sambriskomfi_tbolt_init_desc_pool(struct mfi_softc *sc, uint8_t* mem_location, 274227068Sambrisko uint32_t tbolt_contg_length) 275227068Sambrisko{ 276227068Sambrisko uint32_t offset = 0; 277227068Sambrisko uint8_t *addr = mem_location; 278227068Sambrisko 279227068Sambrisko /* Request Descriptor Base physical Address */ 280227068Sambrisko 281227068Sambrisko /* For Request Decriptors Virtual Memory */ 282227068Sambrisko /* Initialise the aligned IO Frames Virtual Memory Pointer */ 283233711Sambrisko if (((uintptr_t)addr) & (0xFF)) { 284227068Sambrisko addr = &addr[sc->raid_io_msg_size]; 285227068Sambrisko addr = (uint8_t *)((uintptr_t)addr & (~0xFF)); 286227068Sambrisko sc->request_message_pool_align = addr; 287227068Sambrisko } else 288227068Sambrisko sc->request_message_pool_align = addr; 289227068Sambrisko 290227068Sambrisko offset = sc->request_message_pool_align - sc->request_message_pool; 291227068Sambrisko sc->request_msg_busaddr = sc->mfi_tb_busaddr + offset; 292227068Sambrisko 293227068Sambrisko /* DJA XXX should this be bus dma ??? */ 294227068Sambrisko /* Skip request message pool */ 295227068Sambrisko addr = &addr[sc->raid_io_msg_size * (sc->mfi_max_fw_cmds + 1)]; 296227068Sambrisko /* Reply Frame Pool is initialized */ 297227068Sambrisko sc->reply_frame_pool = (struct mfi_mpi2_reply_header *) addr; 298233711Sambrisko if (((uintptr_t)addr) & (0xFF)) { 299227068Sambrisko addr = &addr[sc->reply_size]; 300227068Sambrisko addr = (uint8_t *)((uintptr_t)addr & (~0xFF)); 301227068Sambrisko } 302227068Sambrisko sc->reply_frame_pool_align 303227068Sambrisko = (struct mfi_mpi2_reply_header *)addr; 304227068Sambrisko 305227068Sambrisko offset = (uintptr_t)sc->reply_frame_pool_align 306227068Sambrisko - (uintptr_t)sc->request_message_pool; 307227068Sambrisko sc->reply_frame_busaddr = sc->mfi_tb_busaddr + offset; 308227068Sambrisko 309227068Sambrisko /* Skip Reply Frame Pool */ 310227068Sambrisko addr += sc->reply_size * sc->mfi_max_fw_cmds; 311227068Sambrisko sc->reply_pool_limit = addr; 312227068Sambrisko 313227068Sambrisko /* initializing reply address to 0xFFFFFFFF */ 314227068Sambrisko memset((uint8_t *)sc->reply_frame_pool, 0xFF, 315227068Sambrisko (sc->reply_size * sc->mfi_max_fw_cmds)); 316227068Sambrisko 317227068Sambrisko offset = sc->reply_size * sc->mfi_max_fw_cmds; 318227068Sambrisko sc->sg_frame_busaddr = sc->reply_frame_busaddr + offset; 319227068Sambrisko /* initialize the last_reply_idx to 0 */ 320227068Sambrisko sc->last_reply_idx = 0; 321247369Ssmh MFI_WRITE4(sc, MFI_RFPI, sc->mfi_max_fw_cmds - 1); 322247369Ssmh MFI_WRITE4(sc, MFI_RPI, sc->last_reply_idx); 323227068Sambrisko offset = (sc->sg_frame_busaddr + (MEGASAS_MAX_SZ_CHAIN_FRAME * 324227068Sambrisko sc->mfi_max_fw_cmds)) - sc->mfi_tb_busaddr; 325233711Sambrisko if (offset > tbolt_contg_length) 326233711Sambrisko device_printf(sc->mfi_dev, "Error:Initialized more than " 327227068Sambrisko "allocated\n"); 328227068Sambrisko return 0; 329227068Sambrisko} 330227068Sambrisko 331227068Sambrisko/* 332235016Sambrisko * This routine prepare and issue INIT2 frame to the Firmware 333227068Sambrisko */ 334227068Sambrisko 335227068Sambriskoint 336227068Sambriskomfi_tbolt_init_MFI_queue(struct mfi_softc *sc) 337227068Sambrisko{ 338227068Sambrisko struct MPI2_IOC_INIT_REQUEST *mpi2IocInit; 339247369Ssmh struct mfi_init_frame *mfi_init; 340227068Sambrisko uintptr_t offset = 0; 341233711Sambrisko bus_addr_t phyAddress; 342227068Sambrisko MFI_ADDRESS *mfiAddressTemp; 343247369Ssmh struct mfi_command *cm, cmd_tmp; 344227068Sambrisko int error; 345227068Sambrisko 346247369Ssmh mtx_assert(&sc->mfi_io_lock, MA_OWNED); 347247369Ssmh 348227068Sambrisko /* Check if initialization is already completed */ 349233711Sambrisko if (sc->MFA_enabled) { 350247369Ssmh device_printf(sc->mfi_dev, "tbolt_init already initialised!\n"); 351227068Sambrisko return 1; 352227068Sambrisko } 353227068Sambrisko 354227068Sambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) { 355247369Ssmh device_printf(sc->mfi_dev, "tbolt_init failed to get command " 356247369Ssmh " entry!\n"); 357227068Sambrisko return (EBUSY); 358227068Sambrisko } 359247369Ssmh 360247369Ssmh cmd_tmp.cm_frame = cm->cm_frame; 361247369Ssmh cmd_tmp.cm_frame_busaddr = cm->cm_frame_busaddr; 362247369Ssmh cmd_tmp.cm_dmamap = cm->cm_dmamap; 363247369Ssmh 364227068Sambrisko cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_tb_init); 365227068Sambrisko cm->cm_frame_busaddr = sc->mfi_tb_init_busaddr; 366227068Sambrisko cm->cm_dmamap = sc->mfi_tb_init_dmamap; 367227068Sambrisko cm->cm_frame->header.context = 0; 368227068Sambrisko 369227068Sambrisko /* 370227068Sambrisko * Abuse the SG list area of the frame to hold the init_qinfo 371227068Sambrisko * object; 372227068Sambrisko */ 373227068Sambrisko mfi_init = &cm->cm_frame->init; 374227068Sambrisko 375247369Ssmh mpi2IocInit = (struct MPI2_IOC_INIT_REQUEST *)sc->mfi_tb_ioc_init_desc; 376227068Sambrisko bzero(mpi2IocInit, sizeof(struct MPI2_IOC_INIT_REQUEST)); 377227068Sambrisko mpi2IocInit->Function = MPI2_FUNCTION_IOC_INIT; 378227068Sambrisko mpi2IocInit->WhoInit = MPI2_WHOINIT_HOST_DRIVER; 379227068Sambrisko 380227068Sambrisko /* set MsgVersion and HeaderVersion host driver was built with */ 381227068Sambrisko mpi2IocInit->MsgVersion = MPI2_VERSION; 382227068Sambrisko mpi2IocInit->HeaderVersion = MPI2_HEADER_VERSION; 383227068Sambrisko mpi2IocInit->SystemRequestFrameSize = sc->raid_io_msg_size/4; 384227068Sambrisko mpi2IocInit->ReplyDescriptorPostQueueDepth 385227068Sambrisko = (uint16_t)sc->mfi_max_fw_cmds; 386227068Sambrisko mpi2IocInit->ReplyFreeQueueDepth = 0; /* Not supported by MR. */ 387227068Sambrisko 388227068Sambrisko /* Get physical address of reply frame pool */ 389227068Sambrisko offset = (uintptr_t) sc->reply_frame_pool_align 390227068Sambrisko - (uintptr_t)sc->request_message_pool; 391227068Sambrisko phyAddress = sc->mfi_tb_busaddr + offset; 392227068Sambrisko mfiAddressTemp = 393227068Sambrisko (MFI_ADDRESS *)&mpi2IocInit->ReplyDescriptorPostQueueAddress; 394233711Sambrisko mfiAddressTemp->u.addressLow = (uint32_t)phyAddress; 395233711Sambrisko mfiAddressTemp->u.addressHigh = (uint32_t)((uint64_t)phyAddress >> 32); 396227068Sambrisko 397227068Sambrisko /* Get physical address of request message pool */ 398227068Sambrisko offset = sc->request_message_pool_align - sc->request_message_pool; 399227068Sambrisko phyAddress = sc->mfi_tb_busaddr + offset; 400227068Sambrisko mfiAddressTemp = (MFI_ADDRESS *)&mpi2IocInit->SystemRequestFrameBaseAddress; 401233711Sambrisko mfiAddressTemp->u.addressLow = (uint32_t)phyAddress; 402233711Sambrisko mfiAddressTemp->u.addressHigh = (uint32_t)((uint64_t)phyAddress >> 32); 403233711Sambrisko mpi2IocInit->ReplyFreeQueueAddress = 0; /* Not supported by MR. */ 404227068Sambrisko mpi2IocInit->TimeStamp = time_uptime; 405227068Sambrisko 406227068Sambrisko if (sc->verbuf) { 407227068Sambrisko snprintf((char *)sc->verbuf, strlen(MEGASAS_VERSION) + 2, "%s\n", 408227068Sambrisko MEGASAS_VERSION); 409233711Sambrisko mfi_init->driver_ver_lo = (uint32_t)sc->verbuf_h_busaddr; 410233711Sambrisko mfi_init->driver_ver_hi = 411233711Sambrisko (uint32_t)((uint64_t)sc->verbuf_h_busaddr >> 32); 412227068Sambrisko } 413227068Sambrisko /* Get the physical address of the mpi2 ioc init command */ 414227068Sambrisko phyAddress = sc->mfi_tb_ioc_init_busaddr; 415233711Sambrisko mfi_init->qinfo_new_addr_lo = (uint32_t)phyAddress; 416233711Sambrisko mfi_init->qinfo_new_addr_hi = (uint32_t)((uint64_t)phyAddress >> 32); 417227068Sambrisko mfi_init->header.flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE; 418227068Sambrisko 419227068Sambrisko mfi_init->header.cmd = MFI_CMD_INIT; 420227068Sambrisko mfi_init->header.data_len = sizeof(struct MPI2_IOC_INIT_REQUEST); 421227068Sambrisko mfi_init->header.cmd_status = MFI_STAT_INVALID_STATUS; 422227068Sambrisko 423227068Sambrisko cm->cm_data = NULL; 424227068Sambrisko cm->cm_flags |= MFI_CMD_POLLED; 425227068Sambrisko cm->cm_timestamp = time_uptime; 426227068Sambrisko if ((error = mfi_mapcmd(sc, cm)) != 0) { 427227068Sambrisko device_printf(sc->mfi_dev, "failed to send IOC init2 " 428227068Sambrisko "command %d at %lx\n", error, (long)cm->cm_frame_busaddr); 429247369Ssmh goto out; 430227068Sambrisko } 431227068Sambrisko 432247369Ssmh if (mfi_init->header.cmd_status == MFI_STAT_OK) { 433227068Sambrisko sc->MFA_enabled = 1; 434247369Ssmh } else { 435247369Ssmh device_printf(sc->mfi_dev, "Init command Failed %#x\n", 436227068Sambrisko mfi_init->header.cmd_status); 437247369Ssmh error = mfi_init->header.cmd_status; 438247369Ssmh goto out; 439227068Sambrisko } 440227068Sambrisko 441247369Ssmhout: 442247369Ssmh cm->cm_frame = cmd_tmp.cm_frame; 443247369Ssmh cm->cm_frame_busaddr = cmd_tmp.cm_frame_busaddr; 444247369Ssmh cm->cm_dmamap = cmd_tmp.cm_dmamap; 445247369Ssmh mfi_release_command(cm); 446227068Sambrisko 447247369Ssmh return (error); 448247369Ssmh 449227068Sambrisko} 450227068Sambrisko 451235016Sambriskoint 452235016Sambriskomfi_tbolt_alloc_cmd(struct mfi_softc *sc) 453227068Sambrisko{ 454227068Sambrisko struct mfi_cmd_tbolt *cmd; 455233711Sambrisko bus_addr_t io_req_base_phys; 456227068Sambrisko uint8_t *io_req_base; 457233711Sambrisko int i = 0, j = 0, offset = 0; 458227068Sambrisko 459227068Sambrisko /* 460227068Sambrisko * sc->mfi_cmd_pool_tbolt is an array of struct mfi_cmd_tbolt pointers. 461227068Sambrisko * Allocate the dynamic array first and then allocate individual 462227068Sambrisko * commands. 463227068Sambrisko */ 464227068Sambrisko sc->request_desc_pool = malloc(sizeof( 465227068Sambrisko union mfi_mpi2_request_descriptor) * sc->mfi_max_fw_cmds, 466227068Sambrisko M_MFIBUF, M_NOWAIT|M_ZERO); 467247369Ssmh 468247369Ssmh if (sc->request_desc_pool == NULL) { 469247369Ssmh device_printf(sc->mfi_dev, "Could not alloc " 470247369Ssmh "memory for request_desc_pool\n"); 471247369Ssmh return (ENOMEM); 472247369Ssmh } 473247369Ssmh 474227068Sambrisko sc->mfi_cmd_pool_tbolt = malloc(sizeof(struct mfi_cmd_tbolt*) 475227068Sambrisko * sc->mfi_max_fw_cmds, M_MFIBUF, M_NOWAIT|M_ZERO); 476227068Sambrisko 477247369Ssmh if (sc->mfi_cmd_pool_tbolt == NULL) { 478247369Ssmh free(sc->request_desc_pool, M_MFIBUF); 479247369Ssmh device_printf(sc->mfi_dev, "Could not alloc " 480247369Ssmh "memory for cmd_pool_tbolt\n"); 481247369Ssmh return (ENOMEM); 482227068Sambrisko } 483227068Sambrisko 484227068Sambrisko for (i = 0; i < sc->mfi_max_fw_cmds; i++) { 485227068Sambrisko sc->mfi_cmd_pool_tbolt[i] = malloc(sizeof( 486227068Sambrisko struct mfi_cmd_tbolt),M_MFIBUF, M_NOWAIT|M_ZERO); 487227068Sambrisko 488227068Sambrisko if (!sc->mfi_cmd_pool_tbolt[i]) { 489247369Ssmh device_printf(sc->mfi_dev, "Could not alloc " 490247369Ssmh "cmd_pool_tbolt entry\n"); 491227068Sambrisko 492227068Sambrisko for (j = 0; j < i; j++) 493227068Sambrisko free(sc->mfi_cmd_pool_tbolt[j], M_MFIBUF); 494227068Sambrisko 495247369Ssmh free(sc->request_desc_pool, M_MFIBUF); 496247369Ssmh sc->request_desc_pool = NULL; 497227068Sambrisko free(sc->mfi_cmd_pool_tbolt, M_MFIBUF); 498227068Sambrisko sc->mfi_cmd_pool_tbolt = NULL; 499247369Ssmh 500247369Ssmh return (ENOMEM); 501227068Sambrisko } 502227068Sambrisko } 503227068Sambrisko 504227068Sambrisko /* 505227068Sambrisko * The first 256 bytes (SMID 0) is not used. Don't add to the cmd 506247369Ssmh * list 507227068Sambrisko */ 508227068Sambrisko io_req_base = sc->request_message_pool_align 509227068Sambrisko + MEGASAS_THUNDERBOLT_NEW_MSG_SIZE; 510227068Sambrisko io_req_base_phys = sc->request_msg_busaddr 511227068Sambrisko + MEGASAS_THUNDERBOLT_NEW_MSG_SIZE; 512227068Sambrisko 513227068Sambrisko /* 514227068Sambrisko * Add all the commands to command pool (instance->cmd_pool) 515227068Sambrisko */ 516227068Sambrisko /* SMID 0 is reserved. Set SMID/index from 1 */ 517227068Sambrisko 518227068Sambrisko for (i = 0; i < sc->mfi_max_fw_cmds; i++) { 519227068Sambrisko cmd = sc->mfi_cmd_pool_tbolt[i]; 520227068Sambrisko offset = MEGASAS_THUNDERBOLT_NEW_MSG_SIZE * i; 521227068Sambrisko cmd->index = i + 1; 522227068Sambrisko cmd->request_desc = (union mfi_mpi2_request_descriptor *) 523227068Sambrisko (sc->request_desc_pool + i); 524227068Sambrisko cmd->io_request = (struct mfi_mpi2_request_raid_scsi_io *) 525227068Sambrisko (io_req_base + offset); 526227068Sambrisko cmd->io_request_phys_addr = io_req_base_phys + offset; 527227068Sambrisko cmd->sg_frame = (MPI2_SGE_IO_UNION *)(sc->reply_pool_limit 528227068Sambrisko + i * MEGASAS_MAX_SZ_CHAIN_FRAME); 529227068Sambrisko cmd->sg_frame_phys_addr = sc->sg_frame_busaddr + i 530227068Sambrisko * MEGASAS_MAX_SZ_CHAIN_FRAME; 531242681Sambrisko cmd->sync_cmd_idx = sc->mfi_max_fw_cmds; 532227068Sambrisko 533227068Sambrisko TAILQ_INSERT_TAIL(&(sc->mfi_cmd_tbolt_tqh), cmd, next); 534227068Sambrisko } 535227068Sambrisko return 0; 536227068Sambrisko} 537227068Sambrisko 538235016Sambriskoint 539235016Sambriskomfi_tbolt_reset(struct mfi_softc *sc) 540227068Sambrisko{ 541227068Sambrisko uint32_t fw_state; 542227068Sambrisko 543227068Sambrisko mtx_lock(&sc->mfi_io_lock); 544233711Sambrisko if (sc->hw_crit_error) { 545233711Sambrisko device_printf(sc->mfi_dev, "HW CRITICAL ERROR\n"); 546227068Sambrisko mtx_unlock(&sc->mfi_io_lock); 547227068Sambrisko return 1; 548227068Sambrisko } 549227068Sambrisko 550233711Sambrisko if (sc->mfi_flags & MFI_FLAGS_TBOLT) { 551227068Sambrisko fw_state = sc->mfi_read_fw_status(sc); 552247369Ssmh if ((fw_state & MFI_FWSTATE_FAULT) == MFI_FWSTATE_FAULT || 553247369Ssmh mfi_fw_reset_test) { 554233711Sambrisko if ((sc->disableOnlineCtrlReset == 0) 555233711Sambrisko && (sc->adpreset == 0)) { 556233711Sambrisko device_printf(sc->mfi_dev, "Adapter RESET " 557227068Sambrisko "condition is detected\n"); 558227068Sambrisko sc->adpreset = 1; 559227068Sambrisko sc->issuepend_done = 0; 560227068Sambrisko sc->MFA_enabled = 0; 561227068Sambrisko sc->last_reply_idx = 0; 562227068Sambrisko mfi_process_fw_state_chg_isr((void *) sc); 563227068Sambrisko } 564227068Sambrisko mtx_unlock(&sc->mfi_io_lock); 565227068Sambrisko return 0; 566227068Sambrisko } 567227068Sambrisko } 568227068Sambrisko mtx_unlock(&sc->mfi_io_lock); 569227068Sambrisko return 1; 570227068Sambrisko} 571227068Sambrisko 572227068Sambrisko/* 573227068Sambrisko * mfi_intr_tbolt - isr entry point 574227068Sambrisko */ 575235016Sambriskovoid 576235016Sambriskomfi_intr_tbolt(void *arg) 577227068Sambrisko{ 578227068Sambrisko struct mfi_softc *sc = (struct mfi_softc *)arg; 579227068Sambrisko 580233711Sambrisko if (sc->mfi_check_clear_intr(sc) == 1) { 581227068Sambrisko return; 582227068Sambrisko } 583233711Sambrisko if (sc->mfi_detaching) 584227068Sambrisko return; 585227068Sambrisko mtx_lock(&sc->mfi_io_lock); 586227068Sambrisko mfi_tbolt_complete_cmd(sc); 587247369Ssmh sc->mfi_flags &= ~MFI_FLAGS_QFRZN; 588227068Sambrisko mfi_startio(sc); 589227068Sambrisko mtx_unlock(&sc->mfi_io_lock); 590227068Sambrisko return; 591227068Sambrisko} 592227068Sambrisko 593235016Sambrisko/* 594227068Sambrisko * map_cmd_status - Maps FW cmd status to OS cmd status 595227068Sambrisko * @cmd : Pointer to cmd 596227068Sambrisko * @status : status of cmd returned by FW 597227068Sambrisko * @ext_status : ext status of cmd returned by FW 598227068Sambrisko */ 599227068Sambrisko 600227068Sambriskovoid 601227068Sambriskomap_tbolt_cmd_status(struct mfi_command *mfi_cmd, uint8_t status, 602227068Sambrisko uint8_t ext_status) 603227068Sambrisko{ 604227068Sambrisko switch (status) { 605247369Ssmh case MFI_STAT_OK: 606247369Ssmh mfi_cmd->cm_frame->header.cmd_status = MFI_STAT_OK; 607247369Ssmh mfi_cmd->cm_frame->dcmd.header.cmd_status = MFI_STAT_OK; 608247369Ssmh mfi_cmd->cm_error = MFI_STAT_OK; 609247369Ssmh break; 610227068Sambrisko 611247369Ssmh case MFI_STAT_SCSI_IO_FAILED: 612247369Ssmh case MFI_STAT_LD_INIT_IN_PROGRESS: 613247369Ssmh mfi_cmd->cm_frame->header.cmd_status = status; 614247369Ssmh mfi_cmd->cm_frame->header.scsi_status = ext_status; 615247369Ssmh mfi_cmd->cm_frame->dcmd.header.cmd_status = status; 616247369Ssmh mfi_cmd->cm_frame->dcmd.header.scsi_status 617247369Ssmh = ext_status; 618247369Ssmh break; 619227068Sambrisko 620247369Ssmh case MFI_STAT_SCSI_DONE_WITH_ERROR: 621247369Ssmh mfi_cmd->cm_frame->header.cmd_status = ext_status; 622247369Ssmh mfi_cmd->cm_frame->dcmd.header.cmd_status = ext_status; 623247369Ssmh break; 624227068Sambrisko 625247369Ssmh case MFI_STAT_LD_OFFLINE: 626247369Ssmh case MFI_STAT_DEVICE_NOT_FOUND: 627247369Ssmh mfi_cmd->cm_frame->header.cmd_status = status; 628247369Ssmh mfi_cmd->cm_frame->dcmd.header.cmd_status = status; 629247369Ssmh break; 630227068Sambrisko 631247369Ssmh default: 632247369Ssmh mfi_cmd->cm_frame->header.cmd_status = status; 633247369Ssmh mfi_cmd->cm_frame->dcmd.header.cmd_status = status; 634247369Ssmh break; 635247369Ssmh } 636227068Sambrisko} 637227068Sambrisko 638235016Sambrisko/* 639233711Sambrisko * mfi_tbolt_return_cmd - Return a cmd to free command pool 640233711Sambrisko * @instance: Adapter soft state 641247369Ssmh * @tbolt_cmd: Tbolt command packet to be returned to free command pool 642247369Ssmh * @mfi_cmd: Oning MFI command packe 643233711Sambrisko */ 644247369Ssmhvoid 645247369Ssmhmfi_tbolt_return_cmd(struct mfi_softc *sc, struct mfi_cmd_tbolt *tbolt_cmd, 646247369Ssmh struct mfi_command *mfi_cmd) 647233711Sambrisko{ 648233711Sambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED); 649227068Sambrisko 650247369Ssmh mfi_cmd->cm_flags &= ~MFI_CMD_TBOLT; 651247369Ssmh mfi_cmd->cm_extra_frames = 0; 652247369Ssmh tbolt_cmd->sync_cmd_idx = sc->mfi_max_fw_cmds; 653247369Ssmh 654247369Ssmh TAILQ_INSERT_TAIL(&sc->mfi_cmd_tbolt_tqh, tbolt_cmd, next); 655233711Sambrisko} 656227068Sambrisko 657235014Sambriskovoid 658235014Sambriskomfi_tbolt_complete_cmd(struct mfi_softc *sc) 659227068Sambrisko{ 660227068Sambrisko struct mfi_mpi2_reply_header *desc, *reply_desc; 661247369Ssmh struct mfi_command *cmd_mfi; /* For MFA Cmds */ 662227068Sambrisko struct mfi_cmd_tbolt *cmd_tbolt; 663227068Sambrisko uint16_t smid; 664227068Sambrisko uint8_t reply_descript_type; 665227068Sambrisko struct mfi_mpi2_request_raid_scsi_io *scsi_io_req; 666227068Sambrisko uint32_t status, extStatus; 667227068Sambrisko uint16_t num_completed; 668227068Sambrisko union desc_value val; 669247369Ssmh mtx_assert(&sc->mfi_io_lock, MA_OWNED); 670227068Sambrisko 671227068Sambrisko desc = (struct mfi_mpi2_reply_header *) 672227068Sambrisko ((uintptr_t)sc->reply_frame_pool_align 673227068Sambrisko + sc->last_reply_idx * sc->reply_size); 674227068Sambrisko reply_desc = desc; 675227068Sambrisko 676247369Ssmh if (reply_desc == NULL) { 677227068Sambrisko device_printf(sc->mfi_dev, "reply desc is NULL!!\n"); 678247369Ssmh return; 679247369Ssmh } 680227068Sambrisko 681227068Sambrisko reply_descript_type = reply_desc->ReplyFlags 682227068Sambrisko & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; 683227068Sambrisko if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) 684227068Sambrisko return; 685227068Sambrisko 686227068Sambrisko num_completed = 0; 687227068Sambrisko val.word = ((union mfi_mpi2_reply_descriptor *)desc)->words; 688227068Sambrisko 689227068Sambrisko /* Read Reply descriptor */ 690227068Sambrisko while ((val.u.low != 0xFFFFFFFF) && (val.u.high != 0xFFFFFFFF)) { 691227068Sambrisko smid = reply_desc->SMID; 692247369Ssmh if (smid == 0 || smid > sc->mfi_max_fw_cmds) { 693247369Ssmh device_printf(sc->mfi_dev, "smid is %d cannot " 694247369Ssmh "proceed - skipping\n", smid); 695247369Ssmh goto next; 696227068Sambrisko } 697227068Sambrisko cmd_tbolt = sc->mfi_cmd_pool_tbolt[smid - 1]; 698247369Ssmh if (cmd_tbolt->sync_cmd_idx == sc->mfi_max_fw_cmds) { 699247369Ssmh device_printf(sc->mfi_dev, "cmd_tbolt %p " 700247369Ssmh "has invalid sync_cmd_idx=%d - skipping\n", 701247369Ssmh cmd_tbolt, cmd_tbolt->sync_cmd_idx); 702247369Ssmh goto next; 703247369Ssmh } 704227068Sambrisko cmd_mfi = &sc->mfi_commands[cmd_tbolt->sync_cmd_idx]; 705227068Sambrisko scsi_io_req = cmd_tbolt->io_request; 706227068Sambrisko 707227068Sambrisko status = cmd_mfi->cm_frame->dcmd.header.cmd_status; 708227068Sambrisko extStatus = cmd_mfi->cm_frame->dcmd.header.scsi_status; 709235014Sambrisko map_tbolt_cmd_status(cmd_mfi, status, extStatus); 710227068Sambrisko 711247369Ssmh /* mfi_tbolt_return_cmd is handled by mfi complete / return */ 712247369Ssmh if ((cmd_mfi->cm_flags & MFI_CMD_SCSI) != 0 && 713242681Sambrisko (cmd_mfi->cm_flags & MFI_CMD_POLLED) != 0) { 714242681Sambrisko /* polled LD/SYSPD IO command */ 715242681Sambrisko /* XXX mark okay for now DJA */ 716242681Sambrisko cmd_mfi->cm_frame->header.cmd_status = MFI_STAT_OK; 717247369Ssmh 718242681Sambrisko } else { 719242681Sambrisko /* remove command from busy queue if not polled */ 720247369Ssmh if ((cmd_mfi->cm_flags & MFI_ON_MFIQ_BUSY) != 0) 721247369Ssmh mfi_remove_busy(cmd_mfi); 722242681Sambrisko 723242681Sambrisko /* complete the command */ 724242681Sambrisko mfi_complete(sc, cmd_mfi); 725227068Sambrisko } 726227068Sambrisko 727247369Ssmhnext: 728227068Sambrisko sc->last_reply_idx++; 729227068Sambrisko if (sc->last_reply_idx >= sc->mfi_max_fw_cmds) { 730227068Sambrisko MFI_WRITE4(sc, MFI_RPI, sc->last_reply_idx); 731227068Sambrisko sc->last_reply_idx = 0; 732227068Sambrisko } 733247369Ssmh 734247369Ssmh /* Set it back to all 0xfff */ 735227068Sambrisko ((union mfi_mpi2_reply_descriptor*)desc)->words = 736227068Sambrisko ~((uint64_t)0x00); 737227068Sambrisko 738227068Sambrisko num_completed++; 739227068Sambrisko 740227068Sambrisko /* Get the next reply descriptor */ 741227068Sambrisko desc = (struct mfi_mpi2_reply_header *) 742227068Sambrisko ((uintptr_t)sc->reply_frame_pool_align 743227068Sambrisko + sc->last_reply_idx * sc->reply_size); 744227068Sambrisko reply_desc = desc; 745227068Sambrisko val.word = ((union mfi_mpi2_reply_descriptor*)desc)->words; 746227068Sambrisko reply_descript_type = reply_desc->ReplyFlags 747227068Sambrisko & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; 748233711Sambrisko if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) 749227068Sambrisko break; 750227068Sambrisko } 751227068Sambrisko 752227068Sambrisko if (!num_completed) 753227068Sambrisko return; 754227068Sambrisko 755227068Sambrisko /* update replyIndex to FW */ 756233711Sambrisko if (sc->last_reply_idx) 757227068Sambrisko MFI_WRITE4(sc, MFI_RPI, sc->last_reply_idx); 758227068Sambrisko 759227068Sambrisko return; 760227068Sambrisko} 761227068Sambrisko 762235016Sambrisko/* 763227068Sambrisko * mfi_get_cmd - Get a command from the free pool 764227068Sambrisko * @instance: Adapter soft state 765227068Sambrisko * 766227068Sambrisko * Returns a free command from the pool 767227068Sambrisko */ 768227068Sambrisko 769235016Sambriskostruct mfi_cmd_tbolt * 770247369Ssmhmfi_tbolt_get_cmd(struct mfi_softc *sc, struct mfi_command *mfi_cmd) 771227068Sambrisko{ 772227068Sambrisko struct mfi_cmd_tbolt *cmd = NULL; 773227068Sambrisko 774227068Sambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED); 775227068Sambrisko 776247369Ssmh if ((cmd = TAILQ_FIRST(&sc->mfi_cmd_tbolt_tqh)) == NULL) 777247369Ssmh return (NULL); 778227068Sambrisko TAILQ_REMOVE(&sc->mfi_cmd_tbolt_tqh, cmd, next); 779227068Sambrisko memset((uint8_t *)cmd->sg_frame, 0, MEGASAS_MAX_SZ_CHAIN_FRAME); 780227068Sambrisko memset((uint8_t *)cmd->io_request, 0, 781227068Sambrisko MEGASAS_THUNDERBOLT_NEW_MSG_SIZE); 782247369Ssmh 783247369Ssmh cmd->sync_cmd_idx = mfi_cmd->cm_index; 784247369Ssmh mfi_cmd->cm_extra_frames = cmd->index; /* Frame count used as SMID */ 785247369Ssmh mfi_cmd->cm_flags |= MFI_CMD_TBOLT; 786247369Ssmh 787227068Sambrisko return cmd; 788227068Sambrisko} 789227068Sambrisko 790227068Sambriskounion mfi_mpi2_request_descriptor * 791227068Sambriskomfi_tbolt_get_request_descriptor(struct mfi_softc *sc, uint16_t index) 792227068Sambrisko{ 793227068Sambrisko uint8_t *p; 794227068Sambrisko 795227068Sambrisko if (index >= sc->mfi_max_fw_cmds) { 796227068Sambrisko device_printf(sc->mfi_dev, "Invalid SMID (0x%x)request " 797227068Sambrisko "for descriptor\n", index); 798227068Sambrisko return NULL; 799227068Sambrisko } 800227068Sambrisko p = sc->request_desc_pool + sizeof(union mfi_mpi2_request_descriptor) 801227068Sambrisko * index; 802227068Sambrisko memset(p, 0, sizeof(union mfi_mpi2_request_descriptor)); 803227068Sambrisko return (union mfi_mpi2_request_descriptor *)p; 804227068Sambrisko} 805227068Sambrisko 806227068Sambrisko 807233711Sambrisko/* Used to build IOCTL cmd */ 808227068Sambriskouint8_t 809227068Sambriskomfi_build_mpt_pass_thru(struct mfi_softc *sc, struct mfi_command *mfi_cmd) 810227068Sambrisko{ 811227068Sambrisko MPI25_IEEE_SGE_CHAIN64 *mpi25_ieee_chain; 812227068Sambrisko struct mfi_mpi2_request_raid_scsi_io *io_req; 813227068Sambrisko struct mfi_cmd_tbolt *cmd; 814227068Sambrisko 815247369Ssmh cmd = mfi_tbolt_get_cmd(sc, mfi_cmd); 816227068Sambrisko if (!cmd) 817227068Sambrisko return EBUSY; 818227068Sambrisko io_req = cmd->io_request; 819227068Sambrisko mpi25_ieee_chain = (MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL.IeeeChain; 820227068Sambrisko 821227068Sambrisko io_req->Function = MPI2_FUNCTION_PASSTHRU_IO_REQUEST; 822227068Sambrisko io_req->SGLOffset0 = offsetof(struct mfi_mpi2_request_raid_scsi_io, 823227068Sambrisko SGL) / 4; 824227068Sambrisko io_req->ChainOffset = sc->chain_offset_value_for_mpt_ptmsg; 825227068Sambrisko 826227068Sambrisko mpi25_ieee_chain->Address = mfi_cmd->cm_frame_busaddr; 827227068Sambrisko 828227068Sambrisko /* 829227068Sambrisko In MFI pass thru, nextChainOffset will always be zero to 830227068Sambrisko indicate the end of the chain. 831227068Sambrisko */ 832227068Sambrisko mpi25_ieee_chain->Flags= MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT 833227068Sambrisko | MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR; 834227068Sambrisko 835227068Sambrisko /* setting the length to the maximum length */ 836227068Sambrisko mpi25_ieee_chain->Length = 1024; 837227068Sambrisko 838227068Sambrisko return 0; 839227068Sambrisko} 840227068Sambrisko 841227068Sambriskovoid 842227068Sambriskomfi_tbolt_build_ldio(struct mfi_softc *sc, struct mfi_command *mfi_cmd, 843227068Sambrisko struct mfi_cmd_tbolt *cmd) 844227068Sambrisko{ 845227068Sambrisko uint32_t start_lba_lo = 0, start_lba_hi = 0, device_id; 846227068Sambrisko struct mfi_mpi2_request_raid_scsi_io *io_request; 847227068Sambrisko struct IO_REQUEST_INFO io_info; 848227068Sambrisko 849227068Sambrisko device_id = mfi_cmd->cm_frame->io.header.target_id; 850227068Sambrisko io_request = cmd->io_request; 851227068Sambrisko io_request->RaidContext.TargetID = device_id; 852227068Sambrisko io_request->RaidContext.Status = 0; 853262967Smarkj io_request->RaidContext.exStatus = 0; 854262967Smarkj io_request->RaidContext.regLockFlags = 0; 855227068Sambrisko 856227068Sambrisko start_lba_lo = mfi_cmd->cm_frame->io.lba_lo; 857227068Sambrisko start_lba_hi = mfi_cmd->cm_frame->io.lba_hi; 858227068Sambrisko 859227068Sambrisko memset(&io_info, 0, sizeof(struct IO_REQUEST_INFO)); 860227068Sambrisko io_info.ldStartBlock = ((uint64_t)start_lba_hi << 32) | start_lba_lo; 861227068Sambrisko io_info.numBlocks = mfi_cmd->cm_frame->io.header.data_len; 862227068Sambrisko io_info.ldTgtId = device_id; 863227068Sambrisko if ((mfi_cmd->cm_frame->header.flags & MFI_FRAME_DIR_READ) == 864227068Sambrisko MFI_FRAME_DIR_READ) 865227068Sambrisko io_info.isRead = 1; 866227068Sambrisko 867242681Sambrisko io_request->RaidContext.timeoutValue 868242681Sambrisko = MFI_FUSION_FP_DEFAULT_TIMEOUT; 869242681Sambrisko io_request->Function = MPI2_FUNCTION_LD_IO_REQUEST; 870242681Sambrisko io_request->DevHandle = device_id; 871242681Sambrisko cmd->request_desc->header.RequestFlags 872242681Sambrisko = (MFI_REQ_DESCRIPT_FLAGS_LD_IO 873242681Sambrisko << MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 874233711Sambrisko if ((io_request->IoFlags == 6) && (io_info.numBlocks == 0)) 875227068Sambrisko io_request->RaidContext.RegLockLength = 0x100; 876227068Sambrisko io_request->DataLength = mfi_cmd->cm_frame->io.header.data_len 877227068Sambrisko * MFI_SECTOR_LEN; 878227068Sambrisko} 879227068Sambrisko 880235016Sambriskoint 881235016Sambriskomfi_tbolt_build_io(struct mfi_softc *sc, struct mfi_command *mfi_cmd, 882235016Sambrisko struct mfi_cmd_tbolt *cmd) 883227068Sambrisko{ 884242681Sambrisko struct mfi_mpi2_request_raid_scsi_io *io_request; 885227068Sambrisko uint32_t sge_count; 886242681Sambrisko uint8_t cdb_len; 887242681Sambrisko int readop; 888242681Sambrisko u_int64_t lba; 889227068Sambrisko 890242681Sambrisko io_request = cmd->io_request; 891242681Sambrisko if (!(mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_READ 892242681Sambrisko || mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)) 893242681Sambrisko return 1; 894227068Sambrisko 895242681Sambrisko mfi_tbolt_build_ldio(sc, mfi_cmd, cmd); 896227068Sambrisko 897242681Sambrisko /* Convert to SCSI command CDB */ 898242681Sambrisko bzero(io_request->CDB.CDB32, sizeof(io_request->CDB.CDB32)); 899242681Sambrisko if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE) 900242681Sambrisko readop = 0; 901242681Sambrisko else 902242681Sambrisko readop = 1; 903227068Sambrisko 904242681Sambrisko lba = mfi_cmd->cm_frame->io.lba_hi; 905242681Sambrisko lba = (lba << 32) + mfi_cmd->cm_frame->io.lba_lo; 906242681Sambrisko cdb_len = mfi_build_cdb(readop, 0, lba, 907242681Sambrisko mfi_cmd->cm_frame->io.header.data_len, io_request->CDB.CDB32); 908242681Sambrisko 909242681Sambrisko /* Just the CDB length, rest of the Flags are zero */ 910227068Sambrisko io_request->IoFlags = cdb_len; 911227068Sambrisko 912227068Sambrisko /* 913227068Sambrisko * Construct SGL 914227068Sambrisko */ 915227068Sambrisko sge_count = mfi_tbolt_make_sgl(sc, mfi_cmd, 916227068Sambrisko (pMpi25IeeeSgeChain64_t) &io_request->SGL, cmd); 917227068Sambrisko if (sge_count > sc->mfi_max_sge) { 918227068Sambrisko device_printf(sc->mfi_dev, "Error. sge_count (0x%x) exceeds " 919227068Sambrisko "max (0x%x) allowed\n", sge_count, sc->mfi_max_sge); 920227068Sambrisko return 1; 921227068Sambrisko } 922227068Sambrisko io_request->RaidContext.numSGE = sge_count; 923227068Sambrisko io_request->SGLFlags = MPI2_SGE_FLAGS_64_BIT_ADDRESSING; 924227068Sambrisko 925227068Sambrisko if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE) 926227068Sambrisko io_request->Control = MPI2_SCSIIO_CONTROL_WRITE; 927227068Sambrisko else 928227068Sambrisko io_request->Control = MPI2_SCSIIO_CONTROL_READ; 929227068Sambrisko 930227068Sambrisko io_request->SGLOffset0 = offsetof( 931227068Sambrisko struct mfi_mpi2_request_raid_scsi_io, SGL)/4; 932227068Sambrisko 933227068Sambrisko io_request->SenseBufferLowAddress = mfi_cmd->cm_sense_busaddr; 934227068Sambrisko io_request->SenseBufferLength = MFI_SENSE_LEN; 935242681Sambrisko io_request->RaidContext.Status = MFI_STAT_INVALID_STATUS; 936242681Sambrisko io_request->RaidContext.exStatus = MFI_STAT_INVALID_STATUS; 937242681Sambrisko 938227068Sambrisko return 0; 939227068Sambrisko} 940227068Sambrisko 941227068Sambrisko 942227068Sambriskostatic int 943227068Sambriskomfi_tbolt_make_sgl(struct mfi_softc *sc, struct mfi_command *mfi_cmd, 944233711Sambrisko pMpi25IeeeSgeChain64_t sgl_ptr, struct mfi_cmd_tbolt *cmd) 945227068Sambrisko{ 946233711Sambrisko uint8_t i, sg_processed, sg_to_process; 947227068Sambrisko uint8_t sge_count, sge_idx; 948227068Sambrisko union mfi_sgl *os_sgl; 949262967Smarkj pMpi25IeeeSgeChain64_t sgl_end; 950227068Sambrisko 951227068Sambrisko /* 952227068Sambrisko * Return 0 if there is no data transfer 953227068Sambrisko */ 954227068Sambrisko if (!mfi_cmd->cm_sg || !mfi_cmd->cm_len) { 955227068Sambrisko device_printf(sc->mfi_dev, "Buffer empty \n"); 956227068Sambrisko return 0; 957227068Sambrisko } 958227068Sambrisko os_sgl = mfi_cmd->cm_sg; 959227068Sambrisko sge_count = mfi_cmd->cm_frame->header.sg_count; 960227068Sambrisko 961227068Sambrisko if (sge_count > sc->mfi_max_sge) { 962227068Sambrisko device_printf(sc->mfi_dev, "sgl ptr %p sg_cnt %d \n", 963233711Sambrisko os_sgl, sge_count); 964227068Sambrisko return sge_count; 965227068Sambrisko } 966227068Sambrisko 967227068Sambrisko if (sge_count > sc->max_SGEs_in_main_message) 968227068Sambrisko /* One element to store the chain info */ 969227068Sambrisko sge_idx = sc->max_SGEs_in_main_message - 1; 970227068Sambrisko else 971227068Sambrisko sge_idx = sge_count; 972227068Sambrisko 973262967Smarkj if (sc->mfi_flags & (MFI_FLAGS_INVADER | MFI_FLAGS_FURY)) { 974262967Smarkj sgl_end = sgl_ptr + (sc->max_SGEs_in_main_message - 1); 975262967Smarkj sgl_end->Flags = 0; 976262967Smarkj } 977262967Smarkj 978227068Sambrisko for (i = 0; i < sge_idx; i++) { 979227068Sambrisko /* 980233711Sambrisko * For 32bit BSD we are getting 32 bit SGL's from OS 981233711Sambrisko * but FW only take 64 bit SGL's so copying from 32 bit 982233711Sambrisko * SGL's to 64. 983233711Sambrisko */ 984227068Sambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY) { 985227068Sambrisko sgl_ptr->Length = os_sgl->sg_skinny[i].len; 986227068Sambrisko sgl_ptr->Address = os_sgl->sg_skinny[i].addr; 987227068Sambrisko } else { 988227068Sambrisko sgl_ptr->Length = os_sgl->sg32[i].len; 989233711Sambrisko sgl_ptr->Address = os_sgl->sg32[i].addr; 990227068Sambrisko } 991262967Smarkj if (i == sge_count - 1 && 992262967Smarkj (sc->mfi_flags & (MFI_FLAGS_INVADER | MFI_FLAGS_FURY))) 993262967Smarkj sgl_ptr->Flags = MPI25_IEEE_SGE_FLAGS_END_OF_LIST; 994262967Smarkj else 995262967Smarkj sgl_ptr->Flags = 0; 996227068Sambrisko sgl_ptr++; 997227068Sambrisko cmd->io_request->ChainOffset = 0; 998227068Sambrisko } 999227068Sambrisko 1000227068Sambrisko sg_processed = i; 1001227068Sambrisko 1002227068Sambrisko if (sg_processed < sge_count) { 1003227068Sambrisko pMpi25IeeeSgeChain64_t sg_chain; 1004227068Sambrisko sg_to_process = sge_count - sg_processed; 1005227068Sambrisko cmd->io_request->ChainOffset = 1006227068Sambrisko sc->chain_offset_value_for_main_message; 1007227068Sambrisko sg_chain = sgl_ptr; 1008227068Sambrisko /* Prepare chain element */ 1009227068Sambrisko sg_chain->NextChainOffset = 0; 1010262967Smarkj if (sc->mfi_flags & (MFI_FLAGS_INVADER | MFI_FLAGS_FURY)) 1011262967Smarkj sg_chain->Flags = MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT; 1012262967Smarkj else 1013262967Smarkj sg_chain->Flags = MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT | 1014262967Smarkj MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR; 1015227068Sambrisko sg_chain->Length = (sizeof(MPI2_SGE_IO_UNION) * 1016227068Sambrisko (sge_count - sg_processed)); 1017233711Sambrisko sg_chain->Address = cmd->sg_frame_phys_addr; 1018227068Sambrisko sgl_ptr = (pMpi25IeeeSgeChain64_t)cmd->sg_frame; 1019227068Sambrisko for (; i < sge_count; i++) { 1020227068Sambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY) { 1021227068Sambrisko sgl_ptr->Length = os_sgl->sg_skinny[i].len; 1022227068Sambrisko sgl_ptr->Address = os_sgl->sg_skinny[i].addr; 1023233711Sambrisko } else { 1024227068Sambrisko sgl_ptr->Length = os_sgl->sg32[i].len; 1025233711Sambrisko sgl_ptr->Address = os_sgl->sg32[i].addr; 1026227068Sambrisko } 1027262967Smarkj if (i == sge_count - 1 && 1028262967Smarkj (sc->mfi_flags & 1029262967Smarkj (MFI_FLAGS_INVADER | MFI_FLAGS_FURY))) 1030262967Smarkj sgl_ptr->Flags = 1031262967Smarkj MPI25_IEEE_SGE_FLAGS_END_OF_LIST; 1032262967Smarkj else 1033262967Smarkj sgl_ptr->Flags = 0; 1034227068Sambrisko sgl_ptr++; 1035227068Sambrisko } 1036227068Sambrisko } 1037227068Sambrisko return sge_count; 1038227068Sambrisko} 1039227068Sambrisko 1040227068Sambriskounion mfi_mpi2_request_descriptor * 1041227068Sambriskomfi_build_and_issue_cmd(struct mfi_softc *sc, struct mfi_command *mfi_cmd) 1042227068Sambrisko{ 1043227068Sambrisko struct mfi_cmd_tbolt *cmd; 1044227068Sambrisko union mfi_mpi2_request_descriptor *req_desc = NULL; 1045227068Sambrisko uint16_t index; 1046247369Ssmh cmd = mfi_tbolt_get_cmd(sc, mfi_cmd); 1047247369Ssmh if (cmd == NULL) 1048247369Ssmh return (NULL); 1049227068Sambrisko 1050227068Sambrisko index = cmd->index; 1051227068Sambrisko req_desc = mfi_tbolt_get_request_descriptor(sc, index-1); 1052247369Ssmh if (req_desc == NULL) { 1053247369Ssmh mfi_tbolt_return_cmd(sc, cmd, mfi_cmd); 1054247369Ssmh return (NULL); 1055247369Ssmh } 1056247369Ssmh 1057247369Ssmh if (mfi_tbolt_build_io(sc, mfi_cmd, cmd) != 0) { 1058247369Ssmh mfi_tbolt_return_cmd(sc, cmd, mfi_cmd); 1059247369Ssmh return (NULL); 1060247369Ssmh } 1061227068Sambrisko req_desc->header.SMID = index; 1062227068Sambrisko return req_desc; 1063227068Sambrisko} 1064227068Sambrisko 1065227068Sambriskounion mfi_mpi2_request_descriptor * 1066227068Sambriskomfi_tbolt_build_mpt_cmd(struct mfi_softc *sc, struct mfi_command *cmd) 1067227068Sambrisko{ 1068227068Sambrisko union mfi_mpi2_request_descriptor *req_desc = NULL; 1069227068Sambrisko uint16_t index; 1070227068Sambrisko if (mfi_build_mpt_pass_thru(sc, cmd)) { 1071227068Sambrisko device_printf(sc->mfi_dev, "Couldn't build MFI pass thru " 1072227068Sambrisko "cmd\n"); 1073227068Sambrisko return NULL; 1074227068Sambrisko } 1075227068Sambrisko /* For fusion the frame_count variable is used for SMID */ 1076227068Sambrisko index = cmd->cm_extra_frames; 1077227068Sambrisko 1078227068Sambrisko req_desc = mfi_tbolt_get_request_descriptor(sc, index - 1); 1079247369Ssmh if (req_desc == NULL) 1080227068Sambrisko return NULL; 1081227068Sambrisko 1082237546Skevlo bzero(req_desc, sizeof(*req_desc)); 1083227068Sambrisko req_desc->header.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO << 1084227068Sambrisko MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 1085227068Sambrisko req_desc->header.SMID = index; 1086227068Sambrisko return req_desc; 1087227068Sambrisko} 1088227068Sambrisko 1089227068Sambriskoint 1090227068Sambriskomfi_tbolt_send_frame(struct mfi_softc *sc, struct mfi_command *cm) 1091227068Sambrisko{ 1092227068Sambrisko struct mfi_frame_header *hdr; 1093227068Sambrisko uint8_t *cdb; 1094227068Sambrisko union mfi_mpi2_request_descriptor *req_desc = NULL; 1095247369Ssmh int tm = mfi_polled_cmd_timeout * 1000; 1096227068Sambrisko 1097227068Sambrisko hdr = &cm->cm_frame->header; 1098227068Sambrisko cdb = cm->cm_frame->pass.cdb; 1099233711Sambrisko if (sc->adpreset) 1100227068Sambrisko return 1; 1101227068Sambrisko if ((cm->cm_flags & MFI_CMD_POLLED) == 0) { 1102227068Sambrisko cm->cm_timestamp = time_uptime; 1103227068Sambrisko mfi_enqueue_busy(cm); 1104242681Sambrisko } else { /* still get interrupts for it */ 1105235014Sambrisko hdr->cmd_status = MFI_STAT_INVALID_STATUS; 1106227068Sambrisko hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE; 1107227068Sambrisko } 1108227068Sambrisko 1109227068Sambrisko if (hdr->cmd == MFI_CMD_PD_SCSI_IO) { 1110227068Sambrisko /* check for inquiry commands coming from CLI */ 1111227068Sambrisko if (cdb[0] != 0x28 || cdb[0] != 0x2A) { 1112227068Sambrisko if ((req_desc = mfi_tbolt_build_mpt_cmd(sc, cm)) == 1113227068Sambrisko NULL) { 1114227068Sambrisko device_printf(sc->mfi_dev, "Mapping from MFI " 1115227068Sambrisko "to MPT Failed \n"); 1116227068Sambrisko return 1; 1117227068Sambrisko } 1118227068Sambrisko } 1119227068Sambrisko else 1120227068Sambrisko device_printf(sc->mfi_dev, "DJA NA XXX SYSPDIO\n"); 1121242681Sambrisko } else if (hdr->cmd == MFI_CMD_LD_SCSI_IO || 1122227068Sambrisko hdr->cmd == MFI_CMD_LD_READ || hdr->cmd == MFI_CMD_LD_WRITE) { 1123242681Sambrisko cm->cm_flags |= MFI_CMD_SCSI; 1124227068Sambrisko if ((req_desc = mfi_build_and_issue_cmd(sc, cm)) == NULL) { 1125227068Sambrisko device_printf(sc->mfi_dev, "LDIO Failed \n"); 1126227068Sambrisko return 1; 1127227068Sambrisko } 1128242681Sambrisko } else if ((req_desc = mfi_tbolt_build_mpt_cmd(sc, cm)) == NULL) { 1129247369Ssmh device_printf(sc->mfi_dev, "Mapping from MFI to MPT Failed\n"); 1130247369Ssmh return (1); 1131242681Sambrisko } 1132242681Sambrisko 1133242681Sambrisko if (cm->cm_flags & MFI_CMD_SCSI) { 1134242681Sambrisko /* 1135242681Sambrisko * LD IO needs to be posted since it doesn't get 1136242681Sambrisko * acknowledged via a status update so have the 1137242681Sambrisko * controller reply via mfi_tbolt_complete_cmd. 1138242681Sambrisko */ 1139242681Sambrisko hdr->flags &= ~MFI_FRAME_DONT_POST_IN_REPLY_QUEUE; 1140242681Sambrisko } 1141242681Sambrisko 1142227068Sambrisko MFI_WRITE4(sc, MFI_ILQP, (req_desc->words & 0xFFFFFFFF)); 1143227068Sambrisko MFI_WRITE4(sc, MFI_IHQP, (req_desc->words >>0x20)); 1144227068Sambrisko 1145227068Sambrisko if ((cm->cm_flags & MFI_CMD_POLLED) == 0) 1146227068Sambrisko return 0; 1147227068Sambrisko 1148247369Ssmh /* 1149247369Ssmh * This is a polled command, so busy-wait for it to complete. 1150247369Ssmh * 1151247369Ssmh * The value of hdr->cmd_status is updated directly by the hardware 1152247369Ssmh * so there is no garantee that mfi_tbolt_complete_cmd is called 1153247369Ssmh * prior to this value changing. 1154247369Ssmh */ 1155235014Sambrisko while (hdr->cmd_status == MFI_STAT_INVALID_STATUS) { 1156227068Sambrisko DELAY(1000); 1157227068Sambrisko tm -= 1; 1158227068Sambrisko if (tm <= 0) 1159242681Sambrisko break; 1160242681Sambrisko if (cm->cm_flags & MFI_CMD_SCSI) { 1161247369Ssmh /* 1162247369Ssmh * Force check reply queue. 1163247369Ssmh * This ensures that dump works correctly 1164247369Ssmh */ 1165242681Sambrisko mfi_tbolt_complete_cmd(sc); 1166242681Sambrisko } 1167227068Sambrisko } 1168235016Sambrisko 1169247369Ssmh /* ensure the command cleanup has been processed before returning */ 1170247369Ssmh mfi_tbolt_complete_cmd(sc); 1171247369Ssmh 1172235014Sambrisko if (hdr->cmd_status == MFI_STAT_INVALID_STATUS) { 1173227068Sambrisko device_printf(sc->mfi_dev, "Frame %p timed out " 1174235014Sambrisko "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode); 1175227068Sambrisko return (ETIMEDOUT); 1176227068Sambrisko } 1177227068Sambrisko return 0; 1178227068Sambrisko} 1179227068Sambrisko 1180235016Sambriskostatic void 1181247369Ssmhmfi_issue_pending_cmds_again(struct mfi_softc *sc) 1182227068Sambrisko{ 1183233711Sambrisko struct mfi_command *cm, *tmp; 1184247369Ssmh struct mfi_cmd_tbolt *cmd; 1185227068Sambrisko 1186227068Sambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1187233711Sambrisko TAILQ_FOREACH_REVERSE_SAFE(cm, &sc->mfi_busy, BUSYQ, cm_link, tmp) { 1188227068Sambrisko 1189227068Sambrisko cm->retry_for_fw_reset++; 1190227068Sambrisko 1191227068Sambrisko /* 1192227068Sambrisko * If a command has continuously been tried multiple times 1193227068Sambrisko * and causing a FW reset condition, no further recoveries 1194227068Sambrisko * should be performed on the controller 1195227068Sambrisko */ 1196227068Sambrisko if (cm->retry_for_fw_reset == 3) { 1197247369Ssmh device_printf(sc->mfi_dev, "megaraid_sas: command %p " 1198247369Ssmh "index=%d was tried multiple times during adapter " 1199247369Ssmh "reset - Shutting down the HBA\n", cm, cm->cm_index); 1200227068Sambrisko mfi_kill_hba(sc); 1201227068Sambrisko sc->hw_crit_error = 1; 1202227068Sambrisko return; 1203227068Sambrisko } 1204227068Sambrisko 1205247369Ssmh mfi_remove_busy(cm); 1206247369Ssmh if ((cm->cm_flags & MFI_CMD_TBOLT) != 0) { 1207247369Ssmh if (cm->cm_extra_frames != 0 && cm->cm_extra_frames <= 1208247369Ssmh sc->mfi_max_fw_cmds) { 1209247369Ssmh cmd = sc->mfi_cmd_pool_tbolt[cm->cm_extra_frames - 1]; 1210247369Ssmh mfi_tbolt_return_cmd(sc, cmd, cm); 1211247369Ssmh } else { 1212247369Ssmh device_printf(sc->mfi_dev, 1213247369Ssmh "Invalid extra_frames: %d detected\n", 1214247369Ssmh cm->cm_extra_frames); 1215227068Sambrisko } 1216227068Sambrisko } 1217247369Ssmh 1218247369Ssmh if (cm->cm_frame->dcmd.opcode != MFI_DCMD_CTRL_EVENT_WAIT) { 1219247369Ssmh device_printf(sc->mfi_dev, 1220247369Ssmh "APJ ****requeue command %p index=%d\n", 1221247369Ssmh cm, cm->cm_index); 1222247369Ssmh mfi_requeue_ready(cm); 1223247369Ssmh } else 1224247369Ssmh mfi_release_command(cm); 1225227068Sambrisko } 1226227068Sambrisko mfi_startio(sc); 1227227068Sambrisko} 1228227068Sambrisko 1229235016Sambriskostatic void 1230247369Ssmhmfi_kill_hba(struct mfi_softc *sc) 1231227068Sambrisko{ 1232227068Sambrisko if (sc->mfi_flags & MFI_FLAGS_TBOLT) 1233247369Ssmh MFI_WRITE4(sc, 0x00, MFI_STOP_ADP); 1234227068Sambrisko else 1235247369Ssmh MFI_WRITE4(sc, MFI_IDB, MFI_STOP_ADP); 1236227068Sambrisko} 1237227068Sambrisko 1238235016Sambriskostatic void 1239235016Sambriskomfi_process_fw_state_chg_isr(void *arg) 1240227068Sambrisko{ 1241227068Sambrisko struct mfi_softc *sc= (struct mfi_softc *)arg; 1242227068Sambrisko int error, status; 1243227068Sambrisko 1244227068Sambrisko if (sc->adpreset == 1) { 1245233711Sambrisko device_printf(sc->mfi_dev, "First stage of FW reset " 1246227068Sambrisko "initiated...\n"); 1247227068Sambrisko 1248227068Sambrisko sc->mfi_adp_reset(sc); 1249227068Sambrisko sc->mfi_enable_intr(sc); 1250227068Sambrisko 1251233711Sambrisko device_printf(sc->mfi_dev, "First stage of reset complete, " 1252227068Sambrisko "second stage initiated...\n"); 1253227068Sambrisko 1254227068Sambrisko sc->adpreset = 2; 1255227068Sambrisko 1256227068Sambrisko /* waiting for about 20 second before start the second init */ 1257233711Sambrisko for (int wait = 0; wait < 20000; wait++) 1258227068Sambrisko DELAY(1000); 1259233711Sambrisko device_printf(sc->mfi_dev, "Second stage of FW reset " 1260227068Sambrisko "initiated...\n"); 1261233711Sambrisko while ((status = MFI_READ4(sc, MFI_RSR)) & 0x04); 1262227068Sambrisko 1263227068Sambrisko sc->mfi_disable_intr(sc); 1264227068Sambrisko 1265227068Sambrisko /* We expect the FW state to be READY */ 1266227068Sambrisko if (mfi_transition_firmware(sc)) { 1267233711Sambrisko device_printf(sc->mfi_dev, "controller is not in " 1268233711Sambrisko "ready state\n"); 1269227068Sambrisko mfi_kill_hba(sc); 1270247369Ssmh sc->hw_crit_error = 1; 1271247369Ssmh return; 1272227068Sambrisko } 1273247369Ssmh if ((error = mfi_tbolt_init_MFI_queue(sc)) != 0) { 1274247369Ssmh device_printf(sc->mfi_dev, "Failed to initialise MFI " 1275247369Ssmh "queue\n"); 1276247369Ssmh mfi_kill_hba(sc); 1277247369Ssmh sc->hw_crit_error = 1; 1278247369Ssmh return; 1279247369Ssmh } 1280227068Sambrisko 1281247369Ssmh /* Init last reply index and max */ 1282247369Ssmh MFI_WRITE4(sc, MFI_RFPI, sc->mfi_max_fw_cmds - 1); 1283247369Ssmh MFI_WRITE4(sc, MFI_RPI, sc->last_reply_idx); 1284227068Sambrisko 1285227068Sambrisko sc->mfi_enable_intr(sc); 1286227068Sambrisko sc->adpreset = 0; 1287247369Ssmh if (sc->mfi_aen_cm != NULL) { 1288247369Ssmh free(sc->mfi_aen_cm->cm_data, M_MFIBUF); 1289247369Ssmh mfi_remove_busy(sc->mfi_aen_cm); 1290227068Sambrisko mfi_release_command(sc->mfi_aen_cm); 1291227068Sambrisko sc->mfi_aen_cm = NULL; 1292227068Sambrisko } 1293247369Ssmh 1294247369Ssmh if (sc->mfi_map_sync_cm != NULL) { 1295247369Ssmh mfi_remove_busy(sc->mfi_map_sync_cm); 1296235014Sambrisko mfi_release_command(sc->mfi_map_sync_cm); 1297235014Sambrisko sc->mfi_map_sync_cm = NULL; 1298227068Sambrisko } 1299227068Sambrisko mfi_issue_pending_cmds_again(sc); 1300227068Sambrisko 1301227068Sambrisko /* 1302227068Sambrisko * Issue pending command can result in adapter being marked 1303227068Sambrisko * dead because of too many re-tries. Check for that 1304227068Sambrisko * condition before clearing the reset condition on the FW 1305227068Sambrisko */ 1306227068Sambrisko if (!sc->hw_crit_error) { 1307227068Sambrisko /* 1308247369Ssmh * Initiate AEN (Asynchronous Event Notification) & 1309247369Ssmh * Sync Map 1310227068Sambrisko */ 1311227068Sambrisko mfi_aen_setup(sc, sc->last_seq_num); 1312247369Ssmh mfi_tbolt_sync_map_info(sc); 1313247369Ssmh 1314227068Sambrisko sc->issuepend_done = 1; 1315233711Sambrisko device_printf(sc->mfi_dev, "second stage of reset " 1316227068Sambrisko "complete, FW is ready now.\n"); 1317227068Sambrisko } else { 1318233711Sambrisko device_printf(sc->mfi_dev, "second stage of reset " 1319227068Sambrisko "never completed, hba was marked offline.\n"); 1320227068Sambrisko } 1321227068Sambrisko } else { 1322227068Sambrisko device_printf(sc->mfi_dev, "mfi_process_fw_state_chg_isr " 1323227068Sambrisko "called with unhandled value:%d\n", sc->adpreset); 1324227068Sambrisko } 1325227068Sambrisko} 1326235014Sambrisko 1327235014Sambrisko/* 1328235014Sambrisko * The ThunderBolt HW has an option for the driver to directly 1329235016Sambrisko * access the underlying disks and operate on the RAID. To 1330235014Sambrisko * do this there needs to be a capability to keep the RAID controller 1331235014Sambrisko * and driver in sync. The FreeBSD driver does not take advantage 1332235014Sambrisko * of this feature since it adds a lot of complexity and slows down 1333235014Sambrisko * performance. Performance is gained by using the controller's 1334235014Sambrisko * cache etc. 1335235014Sambrisko * 1336235014Sambrisko * Even though this driver doesn't access the disks directly, an 1337235014Sambrisko * AEN like command is used to inform the RAID firmware to "sync" 1338235014Sambrisko * with all LD's via the MFI_DCMD_LD_MAP_GET_INFO command. This 1339235014Sambrisko * command in write mode will return when the RAID firmware has 1340235014Sambrisko * detected a change to the RAID state. Examples of this type 1341235014Sambrisko * of change are removing a disk. Once the command returns then 1342235014Sambrisko * the driver needs to acknowledge this and "sync" all LD's again. 1343235014Sambrisko * This repeats until we shutdown. Then we need to cancel this 1344235014Sambrisko * pending command. 1345235014Sambrisko * 1346235014Sambrisko * If this is not done right the RAID firmware will not remove a 1347235014Sambrisko * pulled drive and the RAID won't go degraded etc. Effectively, 1348235014Sambrisko * stopping any RAID mangement to functions. 1349235014Sambrisko * 1350235014Sambrisko * Doing another LD sync, requires the use of an event since the 1351235014Sambrisko * driver needs to do a mfi_wait_command and can't do that in an 1352235014Sambrisko * interrupt thread. 1353235014Sambrisko * 1354235014Sambrisko * The driver could get the RAID state via the MFI_DCMD_LD_MAP_GET_INFO 1355235014Sambrisko * That requires a bunch of structure and it is simplier to just do 1356235014Sambrisko * the MFI_DCMD_LD_GET_LIST versus walking the RAID map. 1357235014Sambrisko */ 1358235014Sambrisko 1359235014Sambriskovoid 1360235014Sambriskomfi_tbolt_sync_map_info(struct mfi_softc *sc) 1361235014Sambrisko{ 1362235014Sambrisko int error = 0, i; 1363247369Ssmh struct mfi_command *cmd = NULL; 1364247369Ssmh struct mfi_dcmd_frame *dcmd = NULL; 1365235014Sambrisko uint32_t context = 0; 1366247369Ssmh union mfi_ld_ref *ld_sync = NULL; 1367235014Sambrisko size_t ld_size; 1368235014Sambrisko struct mfi_frame_header *hdr; 1369235014Sambrisko struct mfi_command *cm = NULL; 1370235014Sambrisko struct mfi_ld_list *list = NULL; 1371235014Sambrisko 1372247369Ssmh mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1373247369Ssmh 1374235014Sambrisko if (sc->mfi_map_sync_cm != NULL || sc->cm_map_abort) 1375235014Sambrisko return; 1376235014Sambrisko 1377235014Sambrisko error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_LIST, 1378235014Sambrisko (void **)&list, sizeof(*list)); 1379235014Sambrisko if (error) 1380235014Sambrisko goto out; 1381235014Sambrisko 1382235014Sambrisko cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAIN; 1383247369Ssmh 1384235014Sambrisko if (mfi_wait_command(sc, cm) != 0) { 1385235014Sambrisko device_printf(sc->mfi_dev, "Failed to get device listing\n"); 1386235014Sambrisko goto out; 1387235014Sambrisko } 1388235014Sambrisko 1389235014Sambrisko hdr = &cm->cm_frame->header; 1390235014Sambrisko if (hdr->cmd_status != MFI_STAT_OK) { 1391235014Sambrisko device_printf(sc->mfi_dev, "MFI_DCMD_LD_GET_LIST failed %x\n", 1392235014Sambrisko hdr->cmd_status); 1393235014Sambrisko goto out; 1394235014Sambrisko } 1395235014Sambrisko 1396235014Sambrisko ld_size = sizeof(*ld_sync) * list->ld_count; 1397235014Sambrisko ld_sync = (union mfi_ld_ref *) malloc(ld_size, M_MFIBUF, 1398247369Ssmh M_NOWAIT | M_ZERO); 1399235040Sambrisko if (ld_sync == NULL) { 1400235040Sambrisko device_printf(sc->mfi_dev, "Failed to allocate sync\n"); 1401235040Sambrisko goto out; 1402235040Sambrisko } 1403247369Ssmh for (i = 0; i < list->ld_count; i++) 1404235014Sambrisko ld_sync[i].ref = list->ld_list[i].ld.ref; 1405235014Sambrisko 1406235040Sambrisko if ((cmd = mfi_dequeue_free(sc)) == NULL) { 1407235040Sambrisko device_printf(sc->mfi_dev, "Failed to get command\n"); 1408235040Sambrisko free(ld_sync, M_MFIBUF); 1409235040Sambrisko goto out; 1410235040Sambrisko } 1411242681Sambrisko 1412235014Sambrisko context = cmd->cm_frame->header.context; 1413235014Sambrisko bzero(cmd->cm_frame, sizeof(union mfi_frame)); 1414235014Sambrisko cmd->cm_frame->header.context = context; 1415235014Sambrisko 1416235014Sambrisko dcmd = &cmd->cm_frame->dcmd; 1417235014Sambrisko bzero(dcmd->mbox, MFI_MBOX_SIZE); 1418235014Sambrisko dcmd->header.cmd = MFI_CMD_DCMD; 1419235014Sambrisko dcmd->header.flags = MFI_FRAME_DIR_WRITE; 1420235014Sambrisko dcmd->header.timeout = 0; 1421235014Sambrisko dcmd->header.data_len = ld_size; 1422235014Sambrisko dcmd->header.scsi_status = 0; 1423235014Sambrisko dcmd->opcode = MFI_DCMD_LD_MAP_GET_INFO; 1424235014Sambrisko cmd->cm_sg = &dcmd->sgl; 1425235014Sambrisko cmd->cm_total_frame_size = MFI_DCMD_FRAME_SIZE; 1426235014Sambrisko cmd->cm_data = ld_sync; 1427235014Sambrisko cmd->cm_private = ld_sync; 1428235014Sambrisko 1429235014Sambrisko cmd->cm_len = ld_size; 1430235014Sambrisko cmd->cm_complete = mfi_sync_map_complete; 1431235014Sambrisko sc->mfi_map_sync_cm = cmd; 1432235014Sambrisko 1433235014Sambrisko cmd->cm_flags = MFI_CMD_DATAOUT; 1434235014Sambrisko cmd->cm_frame->dcmd.mbox[0] = list->ld_count; 1435235014Sambrisko cmd->cm_frame->dcmd.mbox[1] = MFI_DCMD_MBOX_PEND_FLAG; 1436235014Sambrisko 1437235014Sambrisko if ((error = mfi_mapcmd(sc, cmd)) != 0) { 1438235014Sambrisko device_printf(sc->mfi_dev, "failed to send map sync\n"); 1439235040Sambrisko free(ld_sync, M_MFIBUF); 1440235040Sambrisko sc->mfi_map_sync_cm = NULL; 1441247369Ssmh mfi_release_command(cmd); 1442235040Sambrisko goto out; 1443235014Sambrisko } 1444235014Sambrisko 1445235014Sambriskoout: 1446235014Sambrisko if (list) 1447235014Sambrisko free(list, M_MFIBUF); 1448235014Sambrisko if (cm) 1449235014Sambrisko mfi_release_command(cm); 1450235014Sambrisko} 1451235014Sambrisko 1452235014Sambriskostatic void 1453235014Sambriskomfi_sync_map_complete(struct mfi_command *cm) 1454235014Sambrisko{ 1455235014Sambrisko struct mfi_frame_header *hdr; 1456235014Sambrisko struct mfi_softc *sc; 1457235014Sambrisko int aborted = 0; 1458235014Sambrisko 1459235014Sambrisko sc = cm->cm_sc; 1460235014Sambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1461235014Sambrisko 1462235014Sambrisko hdr = &cm->cm_frame->header; 1463235014Sambrisko 1464235014Sambrisko if (sc->mfi_map_sync_cm == NULL) 1465235014Sambrisko return; 1466235014Sambrisko 1467235014Sambrisko if (sc->cm_map_abort || 1468235014Sambrisko hdr->cmd_status == MFI_STAT_INVALID_STATUS) { 1469235014Sambrisko sc->cm_map_abort = 0; 1470235014Sambrisko aborted = 1; 1471235014Sambrisko } 1472235014Sambrisko 1473235014Sambrisko free(cm->cm_data, M_MFIBUF); 1474247369Ssmh wakeup(&sc->mfi_map_sync_cm); 1475235014Sambrisko sc->mfi_map_sync_cm = NULL; 1476235014Sambrisko mfi_release_command(cm); 1477235014Sambrisko 1478235014Sambrisko /* set it up again so the driver can catch more events */ 1479247369Ssmh if (!aborted) 1480235014Sambrisko mfi_queue_map_sync(sc); 1481235014Sambrisko} 1482235014Sambrisko 1483235014Sambriskostatic void 1484235014Sambriskomfi_queue_map_sync(struct mfi_softc *sc) 1485235014Sambrisko{ 1486235014Sambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1487235014Sambrisko taskqueue_enqueue(taskqueue_swi, &sc->mfi_map_sync_task); 1488235014Sambrisko} 1489235014Sambrisko 1490235014Sambriskovoid 1491235014Sambriskomfi_handle_map_sync(void *context, int pending) 1492235014Sambrisko{ 1493235014Sambrisko struct mfi_softc *sc; 1494235014Sambrisko 1495235014Sambrisko sc = context; 1496247369Ssmh mtx_lock(&sc->mfi_io_lock); 1497235014Sambrisko mfi_tbolt_sync_map_info(sc); 1498247369Ssmh mtx_unlock(&sc->mfi_io_lock); 1499235014Sambrisko} 1500