1331722Seadler /*- 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: stable/11/sys/dev/mfi/mfi_tbolt.c 360843 2020-05-09 11:18:34Z dim $"); 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 89247369SsmhSYSCTL_INT(_hw_mfi, OID_AUTO, fw_reset_test, CTLFLAG_RWTUN, &mfi_fw_reset_test, 90247369Ssmh 0, "Force a firmware reset condition"); 91247369Ssmh#endif 92247369Ssmh 93227068Sambriskovoid 94227068Sambriskomfi_tbolt_enable_intr_ppc(struct mfi_softc *sc) 95227068Sambrisko{ 96227068Sambrisko MFI_WRITE4(sc, MFI_OMSK, ~MFI_FUSION_ENABLE_INTERRUPT_MASK); 97227068Sambrisko MFI_READ4(sc, MFI_OMSK); 98227068Sambrisko} 99227068Sambrisko 100227068Sambriskovoid 101227068Sambriskomfi_tbolt_disable_intr_ppc(struct mfi_softc *sc) 102227068Sambrisko{ 103227068Sambrisko MFI_WRITE4(sc, MFI_OMSK, 0xFFFFFFFF); 104227068Sambrisko MFI_READ4(sc, MFI_OMSK); 105227068Sambrisko} 106227068Sambrisko 107227068Sambriskoint32_t 108227068Sambriskomfi_tbolt_read_fw_status_ppc(struct mfi_softc *sc) 109227068Sambrisko{ 110227068Sambrisko return MFI_READ4(sc, MFI_OSP0); 111227068Sambrisko} 112227068Sambrisko 113227068Sambriskoint32_t 114227068Sambriskomfi_tbolt_check_clear_intr_ppc(struct mfi_softc *sc) 115227068Sambrisko{ 116227068Sambrisko int32_t status, mfi_status = 0; 117227068Sambrisko 118227068Sambrisko status = MFI_READ4(sc, MFI_OSTS); 119227068Sambrisko 120233711Sambrisko if (status & 1) { 121227068Sambrisko MFI_WRITE4(sc, MFI_OSTS, status); 122227068Sambrisko MFI_READ4(sc, MFI_OSTS); 123233711Sambrisko if (status & MFI_STATE_CHANGE_INTERRUPT) { 124227068Sambrisko mfi_status |= MFI_FIRMWARE_STATE_CHANGE; 125227068Sambrisko } 126227068Sambrisko 127227068Sambrisko return mfi_status; 128227068Sambrisko } 129233711Sambrisko if (!(status & MFI_FUSION_ENABLE_INTERRUPT_MASK)) 130227068Sambrisko return 1; 131227068Sambrisko 132227068Sambrisko MFI_READ4(sc, MFI_OSTS); 133227068Sambrisko return 0; 134227068Sambrisko} 135227068Sambrisko 136227068Sambrisko 137227068Sambriskovoid 138233711Sambriskomfi_tbolt_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add, 139227068Sambrisko uint32_t frame_cnt) 140227068Sambrisko{ 141227068Sambrisko bus_add |= (MFI_REQ_DESCRIPT_FLAGS_MFA 142227068Sambrisko << MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 143233711Sambrisko MFI_WRITE4(sc, MFI_IQPL, (uint32_t)bus_add); 144233711Sambrisko MFI_WRITE4(sc, MFI_IQPH, (uint32_t)((uint64_t)bus_add >> 32)); 145227068Sambrisko} 146227068Sambrisko 147235016Sambrisko/* 148227068Sambrisko * mfi_tbolt_adp_reset - For controller reset 149227068Sambrisko * @regs: MFI register set 150227068Sambrisko */ 151235016Sambriskoint 152235016Sambriskomfi_tbolt_adp_reset(struct mfi_softc *sc) 153227068Sambrisko{ 154233711Sambrisko int retry = 0, i = 0; 155233711Sambrisko int HostDiag; 156227068Sambrisko 157233711Sambrisko MFI_WRITE4(sc, MFI_WSR, 0xF); 158233711Sambrisko MFI_WRITE4(sc, MFI_WSR, 4); 159233711Sambrisko MFI_WRITE4(sc, MFI_WSR, 0xB); 160233711Sambrisko MFI_WRITE4(sc, MFI_WSR, 2); 161233711Sambrisko MFI_WRITE4(sc, MFI_WSR, 7); 162233711Sambrisko MFI_WRITE4(sc, MFI_WSR, 0xD); 163227068Sambrisko 164233711Sambrisko for (i = 0; i < 10000; i++) ; 165227068Sambrisko 166233711Sambrisko HostDiag = (uint32_t)MFI_READ4(sc, MFI_HDR); 167227068Sambrisko 168233711Sambrisko while (!( HostDiag & DIAG_WRITE_ENABLE)) { 169233711Sambrisko for (i = 0; i < 1000; i++); 170233711Sambrisko HostDiag = (uint32_t)MFI_READ4(sc, MFI_HDR); 171247369Ssmh device_printf(sc->mfi_dev, "ADP_RESET_TBOLT: retry time=%d, " 172247369Ssmh "hostdiag=%#x\n", retry, HostDiag); 173227068Sambrisko 174233711Sambrisko if (retry++ >= 100) 175233711Sambrisko return 1; 176233711Sambrisko } 177227068Sambrisko 178247369Ssmh device_printf(sc->mfi_dev, "ADP_RESET_TBOLT: HostDiag=%#x\n", HostDiag); 179227068Sambrisko 180233711Sambrisko MFI_WRITE4(sc, MFI_HDR, (HostDiag | DIAG_RESET_ADAPTER)); 181227068Sambrisko 182233711Sambrisko for (i=0; i < 10; i++) { 183233711Sambrisko for (i = 0; i < 10000; i++); 184233711Sambrisko } 185227068Sambrisko 186233711Sambrisko HostDiag = (uint32_t)MFI_READ4(sc, MFI_RSR); 187233711Sambrisko while (HostDiag & DIAG_RESET_ADAPTER) { 188233711Sambrisko for (i = 0; i < 1000; i++) ; 189233711Sambrisko HostDiag = (uint32_t)MFI_READ4(sc, MFI_RSR); 190247369Ssmh device_printf(sc->mfi_dev, "ADP_RESET_TBOLT: retry time=%d, " 191247369Ssmh "hostdiag=%#x\n", retry, HostDiag); 192227068Sambrisko 193233711Sambrisko if (retry++ >= 1000) 194233711Sambrisko return 1; 195233711Sambrisko } 196233711Sambrisko return 0; 197227068Sambrisko} 198227068Sambrisko 199227068Sambrisko/* 200235016Sambrisko * This routine initialize Thunderbolt specific device information 201227068Sambrisko */ 202235016Sambriskovoid 203235016Sambriskomfi_tbolt_init_globals(struct mfi_softc *sc) 204227068Sambrisko{ 205227068Sambrisko /* Initialize single reply size and Message size */ 206227068Sambrisko sc->reply_size = MEGASAS_THUNDERBOLT_REPLY_SIZE; 207227068Sambrisko sc->raid_io_msg_size = MEGASAS_THUNDERBOLT_NEW_MSG_SIZE; 208227068Sambrisko 209227068Sambrisko /* 210227068Sambrisko * Calculating how many SGEs allowed in a allocated main message 211227068Sambrisko * (size of the Message - Raid SCSI IO message size(except SGE)) 212227068Sambrisko * / size of SGE 213227068Sambrisko * (0x100 - (0x90 - 0x10)) / 0x10 = 8 214227068Sambrisko */ 215227068Sambrisko sc->max_SGEs_in_main_message = 216227068Sambrisko (uint8_t)((sc->raid_io_msg_size 217227068Sambrisko - (sizeof(struct mfi_mpi2_request_raid_scsi_io) 218227068Sambrisko - sizeof(MPI2_SGE_IO_UNION))) / sizeof(MPI2_SGE_IO_UNION)); 219227068Sambrisko /* 220227068Sambrisko * (Command frame size allocaed in SRB ext - Raid SCSI IO message size) 221227068Sambrisko * / size of SGL ; 222227068Sambrisko * (1280 - 256) / 16 = 64 223227068Sambrisko */ 224227068Sambrisko sc->max_SGEs_in_chain_message = (MR_COMMAND_SIZE 225227068Sambrisko - sc->raid_io_msg_size) / sizeof(MPI2_SGE_IO_UNION); 226227068Sambrisko /* 227227068Sambrisko * (0x08-1) + 0x40 = 0x47 - 0x01 = 0x46 one is left for command 228227068Sambrisko * colscing 229227068Sambrisko */ 230227068Sambrisko sc->mfi_max_sge = (sc->max_SGEs_in_main_message - 1) 231227068Sambrisko + sc->max_SGEs_in_chain_message - 1; 232227068Sambrisko /* 233227068Sambrisko * This is the offset in number of 4 * 32bit words to the next chain 234227068Sambrisko * (0x100 - 0x10)/0x10 = 0xF(15) 235227068Sambrisko */ 236227068Sambrisko sc->chain_offset_value_for_main_message = (sc->raid_io_msg_size 237227068Sambrisko - sizeof(MPI2_SGE_IO_UNION))/16; 238227068Sambrisko sc->chain_offset_value_for_mpt_ptmsg 239227068Sambrisko = offsetof(struct mfi_mpi2_request_raid_scsi_io, SGL)/16; 240227068Sambrisko sc->mfi_cmd_pool_tbolt = NULL; 241227068Sambrisko sc->request_desc_pool = NULL; 242227068Sambrisko} 243227068Sambrisko 244227068Sambrisko/* 245235016Sambrisko * This function calculates the memory requirement for Thunderbolt 246235016Sambrisko * controller, returns the total required memory in bytes 247227068Sambrisko */ 248227068Sambrisko 249235016Sambriskouint32_t 250235016Sambriskomfi_tbolt_get_memory_requirement(struct mfi_softc *sc) 251227068Sambrisko{ 252227068Sambrisko uint32_t size; 253233711Sambrisko size = MEGASAS_THUNDERBOLT_MSG_ALLIGNMENT; /* for Alignment */ 254227068Sambrisko size += sc->raid_io_msg_size * (sc->mfi_max_fw_cmds + 1); 255227068Sambrisko size += sc->reply_size * sc->mfi_max_fw_cmds; 256233711Sambrisko /* this is for SGL's */ 257227068Sambrisko size += MEGASAS_MAX_SZ_CHAIN_FRAME * sc->mfi_max_fw_cmds; 258227068Sambrisko return size; 259227068Sambrisko} 260227068Sambrisko 261227068Sambrisko/* 262227068Sambrisko * Description: 263227068Sambrisko * This function will prepare message pools for the Thunderbolt controller 264227068Sambrisko * Arguments: 265227068Sambrisko * DevExt - HBA miniport driver's adapter data storage structure 266227068Sambrisko * pMemLocation - start of the memory allocated for Thunderbolt. 267227068Sambrisko * Return Value: 268227068Sambrisko * TRUE if successful 269227068Sambrisko * FALSE if failed 270227068Sambrisko */ 271235016Sambriskoint 272235016Sambriskomfi_tbolt_init_desc_pool(struct mfi_softc *sc, uint8_t* mem_location, 273227068Sambrisko uint32_t tbolt_contg_length) 274227068Sambrisko{ 275227068Sambrisko uint32_t offset = 0; 276227068Sambrisko uint8_t *addr = mem_location; 277227068Sambrisko 278227068Sambrisko /* Request Descriptor Base physical Address */ 279227068Sambrisko 280227068Sambrisko /* For Request Decriptors Virtual Memory */ 281227068Sambrisko /* Initialise the aligned IO Frames Virtual Memory Pointer */ 282233711Sambrisko if (((uintptr_t)addr) & (0xFF)) { 283227068Sambrisko addr = &addr[sc->raid_io_msg_size]; 284227068Sambrisko addr = (uint8_t *)((uintptr_t)addr & (~0xFF)); 285227068Sambrisko sc->request_message_pool_align = addr; 286227068Sambrisko } else 287227068Sambrisko sc->request_message_pool_align = addr; 288227068Sambrisko 289227068Sambrisko offset = sc->request_message_pool_align - sc->request_message_pool; 290227068Sambrisko sc->request_msg_busaddr = sc->mfi_tb_busaddr + offset; 291227068Sambrisko 292227068Sambrisko /* DJA XXX should this be bus dma ??? */ 293227068Sambrisko /* Skip request message pool */ 294227068Sambrisko addr = &addr[sc->raid_io_msg_size * (sc->mfi_max_fw_cmds + 1)]; 295227068Sambrisko /* Reply Frame Pool is initialized */ 296227068Sambrisko sc->reply_frame_pool = (struct mfi_mpi2_reply_header *) addr; 297233711Sambrisko if (((uintptr_t)addr) & (0xFF)) { 298227068Sambrisko addr = &addr[sc->reply_size]; 299227068Sambrisko addr = (uint8_t *)((uintptr_t)addr & (~0xFF)); 300227068Sambrisko } 301227068Sambrisko sc->reply_frame_pool_align 302227068Sambrisko = (struct mfi_mpi2_reply_header *)addr; 303227068Sambrisko 304227068Sambrisko offset = (uintptr_t)sc->reply_frame_pool_align 305227068Sambrisko - (uintptr_t)sc->request_message_pool; 306227068Sambrisko sc->reply_frame_busaddr = sc->mfi_tb_busaddr + offset; 307227068Sambrisko 308227068Sambrisko /* Skip Reply Frame Pool */ 309227068Sambrisko addr += sc->reply_size * sc->mfi_max_fw_cmds; 310227068Sambrisko sc->reply_pool_limit = addr; 311227068Sambrisko 312227068Sambrisko /* initializing reply address to 0xFFFFFFFF */ 313227068Sambrisko memset((uint8_t *)sc->reply_frame_pool, 0xFF, 314227068Sambrisko (sc->reply_size * sc->mfi_max_fw_cmds)); 315227068Sambrisko 316227068Sambrisko offset = sc->reply_size * sc->mfi_max_fw_cmds; 317227068Sambrisko sc->sg_frame_busaddr = sc->reply_frame_busaddr + offset; 318227068Sambrisko /* initialize the last_reply_idx to 0 */ 319227068Sambrisko sc->last_reply_idx = 0; 320247369Ssmh MFI_WRITE4(sc, MFI_RFPI, sc->mfi_max_fw_cmds - 1); 321247369Ssmh MFI_WRITE4(sc, MFI_RPI, sc->last_reply_idx); 322227068Sambrisko offset = (sc->sg_frame_busaddr + (MEGASAS_MAX_SZ_CHAIN_FRAME * 323227068Sambrisko sc->mfi_max_fw_cmds)) - sc->mfi_tb_busaddr; 324233711Sambrisko if (offset > tbolt_contg_length) 325233711Sambrisko device_printf(sc->mfi_dev, "Error:Initialized more than " 326227068Sambrisko "allocated\n"); 327227068Sambrisko return 0; 328227068Sambrisko} 329227068Sambrisko 330227068Sambrisko/* 331235016Sambrisko * This routine prepare and issue INIT2 frame to the Firmware 332227068Sambrisko */ 333227068Sambrisko 334227068Sambriskoint 335227068Sambriskomfi_tbolt_init_MFI_queue(struct mfi_softc *sc) 336227068Sambrisko{ 337227068Sambrisko struct MPI2_IOC_INIT_REQUEST *mpi2IocInit; 338247369Ssmh struct mfi_init_frame *mfi_init; 339227068Sambrisko uintptr_t offset = 0; 340233711Sambrisko bus_addr_t phyAddress; 341227068Sambrisko MFI_ADDRESS *mfiAddressTemp; 342247369Ssmh struct mfi_command *cm, cmd_tmp; 343227068Sambrisko int error; 344227068Sambrisko 345247369Ssmh mtx_assert(&sc->mfi_io_lock, MA_OWNED); 346247369Ssmh 347227068Sambrisko /* Check if initialization is already completed */ 348233711Sambrisko if (sc->MFA_enabled) { 349247369Ssmh device_printf(sc->mfi_dev, "tbolt_init already initialised!\n"); 350227068Sambrisko return 1; 351227068Sambrisko } 352227068Sambrisko 353227068Sambrisko if ((cm = mfi_dequeue_free(sc)) == NULL) { 354247369Ssmh device_printf(sc->mfi_dev, "tbolt_init failed to get command " 355247369Ssmh " entry!\n"); 356227068Sambrisko return (EBUSY); 357227068Sambrisko } 358247369Ssmh 359247369Ssmh cmd_tmp.cm_frame = cm->cm_frame; 360247369Ssmh cmd_tmp.cm_frame_busaddr = cm->cm_frame_busaddr; 361247369Ssmh cmd_tmp.cm_dmamap = cm->cm_dmamap; 362247369Ssmh 363227068Sambrisko cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_tb_init); 364227068Sambrisko cm->cm_frame_busaddr = sc->mfi_tb_init_busaddr; 365227068Sambrisko cm->cm_dmamap = sc->mfi_tb_init_dmamap; 366227068Sambrisko cm->cm_frame->header.context = 0; 367227068Sambrisko 368227068Sambrisko /* 369227068Sambrisko * Abuse the SG list area of the frame to hold the init_qinfo 370227068Sambrisko * object; 371227068Sambrisko */ 372227068Sambrisko mfi_init = &cm->cm_frame->init; 373227068Sambrisko 374247369Ssmh mpi2IocInit = (struct MPI2_IOC_INIT_REQUEST *)sc->mfi_tb_ioc_init_desc; 375227068Sambrisko bzero(mpi2IocInit, sizeof(struct MPI2_IOC_INIT_REQUEST)); 376227068Sambrisko mpi2IocInit->Function = MPI2_FUNCTION_IOC_INIT; 377227068Sambrisko mpi2IocInit->WhoInit = MPI2_WHOINIT_HOST_DRIVER; 378227068Sambrisko 379227068Sambrisko /* set MsgVersion and HeaderVersion host driver was built with */ 380227068Sambrisko mpi2IocInit->MsgVersion = MPI2_VERSION; 381227068Sambrisko mpi2IocInit->HeaderVersion = MPI2_HEADER_VERSION; 382227068Sambrisko mpi2IocInit->SystemRequestFrameSize = sc->raid_io_msg_size/4; 383227068Sambrisko mpi2IocInit->ReplyDescriptorPostQueueDepth 384227068Sambrisko = (uint16_t)sc->mfi_max_fw_cmds; 385227068Sambrisko mpi2IocInit->ReplyFreeQueueDepth = 0; /* Not supported by MR. */ 386227068Sambrisko 387227068Sambrisko /* Get physical address of reply frame pool */ 388227068Sambrisko offset = (uintptr_t) sc->reply_frame_pool_align 389227068Sambrisko - (uintptr_t)sc->request_message_pool; 390227068Sambrisko phyAddress = sc->mfi_tb_busaddr + offset; 391227068Sambrisko mfiAddressTemp = 392227068Sambrisko (MFI_ADDRESS *)&mpi2IocInit->ReplyDescriptorPostQueueAddress; 393233711Sambrisko mfiAddressTemp->u.addressLow = (uint32_t)phyAddress; 394233711Sambrisko mfiAddressTemp->u.addressHigh = (uint32_t)((uint64_t)phyAddress >> 32); 395227068Sambrisko 396227068Sambrisko /* Get physical address of request message pool */ 397227068Sambrisko offset = sc->request_message_pool_align - sc->request_message_pool; 398227068Sambrisko phyAddress = sc->mfi_tb_busaddr + offset; 399227068Sambrisko mfiAddressTemp = (MFI_ADDRESS *)&mpi2IocInit->SystemRequestFrameBaseAddress; 400233711Sambrisko mfiAddressTemp->u.addressLow = (uint32_t)phyAddress; 401233711Sambrisko mfiAddressTemp->u.addressHigh = (uint32_t)((uint64_t)phyAddress >> 32); 402233711Sambrisko mpi2IocInit->ReplyFreeQueueAddress = 0; /* Not supported by MR. */ 403227068Sambrisko mpi2IocInit->TimeStamp = time_uptime; 404227068Sambrisko 405227068Sambrisko if (sc->verbuf) { 406227068Sambrisko snprintf((char *)sc->verbuf, strlen(MEGASAS_VERSION) + 2, "%s\n", 407227068Sambrisko MEGASAS_VERSION); 408233711Sambrisko mfi_init->driver_ver_lo = (uint32_t)sc->verbuf_h_busaddr; 409233711Sambrisko mfi_init->driver_ver_hi = 410233711Sambrisko (uint32_t)((uint64_t)sc->verbuf_h_busaddr >> 32); 411227068Sambrisko } 412227068Sambrisko /* Get the physical address of the mpi2 ioc init command */ 413227068Sambrisko phyAddress = sc->mfi_tb_ioc_init_busaddr; 414233711Sambrisko mfi_init->qinfo_new_addr_lo = (uint32_t)phyAddress; 415233711Sambrisko mfi_init->qinfo_new_addr_hi = (uint32_t)((uint64_t)phyAddress >> 32); 416227068Sambrisko mfi_init->header.flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE; 417227068Sambrisko 418227068Sambrisko mfi_init->header.cmd = MFI_CMD_INIT; 419227068Sambrisko mfi_init->header.data_len = sizeof(struct MPI2_IOC_INIT_REQUEST); 420227068Sambrisko mfi_init->header.cmd_status = MFI_STAT_INVALID_STATUS; 421227068Sambrisko 422227068Sambrisko cm->cm_data = NULL; 423227068Sambrisko cm->cm_flags |= MFI_CMD_POLLED; 424227068Sambrisko cm->cm_timestamp = time_uptime; 425227068Sambrisko if ((error = mfi_mapcmd(sc, cm)) != 0) { 426227068Sambrisko device_printf(sc->mfi_dev, "failed to send IOC init2 " 427227068Sambrisko "command %d at %lx\n", error, (long)cm->cm_frame_busaddr); 428247369Ssmh goto out; 429227068Sambrisko } 430227068Sambrisko 431247369Ssmh if (mfi_init->header.cmd_status == MFI_STAT_OK) { 432227068Sambrisko sc->MFA_enabled = 1; 433247369Ssmh } else { 434247369Ssmh device_printf(sc->mfi_dev, "Init command Failed %#x\n", 435227068Sambrisko mfi_init->header.cmd_status); 436247369Ssmh error = mfi_init->header.cmd_status; 437247369Ssmh goto out; 438227068Sambrisko } 439227068Sambrisko 440247369Ssmhout: 441247369Ssmh cm->cm_frame = cmd_tmp.cm_frame; 442247369Ssmh cm->cm_frame_busaddr = cmd_tmp.cm_frame_busaddr; 443247369Ssmh cm->cm_dmamap = cmd_tmp.cm_dmamap; 444247369Ssmh mfi_release_command(cm); 445227068Sambrisko 446247369Ssmh return (error); 447247369Ssmh 448227068Sambrisko} 449227068Sambrisko 450235016Sambriskoint 451235016Sambriskomfi_tbolt_alloc_cmd(struct mfi_softc *sc) 452227068Sambrisko{ 453227068Sambrisko struct mfi_cmd_tbolt *cmd; 454233711Sambrisko bus_addr_t io_req_base_phys; 455227068Sambrisko uint8_t *io_req_base; 456233711Sambrisko int i = 0, j = 0, offset = 0; 457227068Sambrisko 458227068Sambrisko /* 459227068Sambrisko * sc->mfi_cmd_pool_tbolt is an array of struct mfi_cmd_tbolt pointers. 460227068Sambrisko * Allocate the dynamic array first and then allocate individual 461227068Sambrisko * commands. 462227068Sambrisko */ 463227068Sambrisko sc->request_desc_pool = malloc(sizeof( 464227068Sambrisko union mfi_mpi2_request_descriptor) * sc->mfi_max_fw_cmds, 465227068Sambrisko M_MFIBUF, M_NOWAIT|M_ZERO); 466247369Ssmh 467247369Ssmh if (sc->request_desc_pool == NULL) { 468247369Ssmh device_printf(sc->mfi_dev, "Could not alloc " 469247369Ssmh "memory for request_desc_pool\n"); 470247369Ssmh return (ENOMEM); 471247369Ssmh } 472247369Ssmh 473227068Sambrisko sc->mfi_cmd_pool_tbolt = malloc(sizeof(struct mfi_cmd_tbolt*) 474227068Sambrisko * sc->mfi_max_fw_cmds, M_MFIBUF, M_NOWAIT|M_ZERO); 475227068Sambrisko 476247369Ssmh if (sc->mfi_cmd_pool_tbolt == NULL) { 477247369Ssmh free(sc->request_desc_pool, M_MFIBUF); 478247369Ssmh device_printf(sc->mfi_dev, "Could not alloc " 479247369Ssmh "memory for cmd_pool_tbolt\n"); 480247369Ssmh return (ENOMEM); 481227068Sambrisko } 482227068Sambrisko 483227068Sambrisko for (i = 0; i < sc->mfi_max_fw_cmds; i++) { 484227068Sambrisko sc->mfi_cmd_pool_tbolt[i] = malloc(sizeof( 485227068Sambrisko struct mfi_cmd_tbolt),M_MFIBUF, M_NOWAIT|M_ZERO); 486227068Sambrisko 487227068Sambrisko if (!sc->mfi_cmd_pool_tbolt[i]) { 488247369Ssmh device_printf(sc->mfi_dev, "Could not alloc " 489247369Ssmh "cmd_pool_tbolt entry\n"); 490227068Sambrisko 491227068Sambrisko for (j = 0; j < i; j++) 492227068Sambrisko free(sc->mfi_cmd_pool_tbolt[j], M_MFIBUF); 493227068Sambrisko 494247369Ssmh free(sc->request_desc_pool, M_MFIBUF); 495247369Ssmh sc->request_desc_pool = NULL; 496227068Sambrisko free(sc->mfi_cmd_pool_tbolt, M_MFIBUF); 497227068Sambrisko sc->mfi_cmd_pool_tbolt = NULL; 498247369Ssmh 499247369Ssmh return (ENOMEM); 500227068Sambrisko } 501227068Sambrisko } 502227068Sambrisko 503227068Sambrisko /* 504227068Sambrisko * The first 256 bytes (SMID 0) is not used. Don't add to the cmd 505247369Ssmh * list 506227068Sambrisko */ 507227068Sambrisko io_req_base = sc->request_message_pool_align 508227068Sambrisko + MEGASAS_THUNDERBOLT_NEW_MSG_SIZE; 509227068Sambrisko io_req_base_phys = sc->request_msg_busaddr 510227068Sambrisko + MEGASAS_THUNDERBOLT_NEW_MSG_SIZE; 511227068Sambrisko 512227068Sambrisko /* 513227068Sambrisko * Add all the commands to command pool (instance->cmd_pool) 514227068Sambrisko */ 515227068Sambrisko /* SMID 0 is reserved. Set SMID/index from 1 */ 516227068Sambrisko 517227068Sambrisko for (i = 0; i < sc->mfi_max_fw_cmds; i++) { 518227068Sambrisko cmd = sc->mfi_cmd_pool_tbolt[i]; 519227068Sambrisko offset = MEGASAS_THUNDERBOLT_NEW_MSG_SIZE * i; 520227068Sambrisko cmd->index = i + 1; 521227068Sambrisko cmd->request_desc = (union mfi_mpi2_request_descriptor *) 522227068Sambrisko (sc->request_desc_pool + i); 523227068Sambrisko cmd->io_request = (struct mfi_mpi2_request_raid_scsi_io *) 524227068Sambrisko (io_req_base + offset); 525227068Sambrisko cmd->io_request_phys_addr = io_req_base_phys + offset; 526227068Sambrisko cmd->sg_frame = (MPI2_SGE_IO_UNION *)(sc->reply_pool_limit 527227068Sambrisko + i * MEGASAS_MAX_SZ_CHAIN_FRAME); 528227068Sambrisko cmd->sg_frame_phys_addr = sc->sg_frame_busaddr + i 529227068Sambrisko * MEGASAS_MAX_SZ_CHAIN_FRAME; 530242681Sambrisko cmd->sync_cmd_idx = sc->mfi_max_fw_cmds; 531227068Sambrisko 532227068Sambrisko TAILQ_INSERT_TAIL(&(sc->mfi_cmd_tbolt_tqh), cmd, next); 533227068Sambrisko } 534227068Sambrisko return 0; 535227068Sambrisko} 536227068Sambrisko 537235016Sambriskoint 538235016Sambriskomfi_tbolt_reset(struct mfi_softc *sc) 539227068Sambrisko{ 540227068Sambrisko uint32_t fw_state; 541227068Sambrisko 542227068Sambrisko mtx_lock(&sc->mfi_io_lock); 543233711Sambrisko if (sc->hw_crit_error) { 544233711Sambrisko device_printf(sc->mfi_dev, "HW CRITICAL ERROR\n"); 545227068Sambrisko mtx_unlock(&sc->mfi_io_lock); 546227068Sambrisko return 1; 547227068Sambrisko } 548227068Sambrisko 549233711Sambrisko if (sc->mfi_flags & MFI_FLAGS_TBOLT) { 550227068Sambrisko fw_state = sc->mfi_read_fw_status(sc); 551247369Ssmh if ((fw_state & MFI_FWSTATE_FAULT) == MFI_FWSTATE_FAULT || 552247369Ssmh mfi_fw_reset_test) { 553233711Sambrisko if ((sc->disableOnlineCtrlReset == 0) 554233711Sambrisko && (sc->adpreset == 0)) { 555233711Sambrisko device_printf(sc->mfi_dev, "Adapter RESET " 556227068Sambrisko "condition is detected\n"); 557227068Sambrisko sc->adpreset = 1; 558227068Sambrisko sc->issuepend_done = 0; 559227068Sambrisko sc->MFA_enabled = 0; 560227068Sambrisko sc->last_reply_idx = 0; 561227068Sambrisko mfi_process_fw_state_chg_isr((void *) sc); 562227068Sambrisko } 563227068Sambrisko mtx_unlock(&sc->mfi_io_lock); 564227068Sambrisko return 0; 565227068Sambrisko } 566227068Sambrisko } 567227068Sambrisko mtx_unlock(&sc->mfi_io_lock); 568227068Sambrisko return 1; 569227068Sambrisko} 570227068Sambrisko 571227068Sambrisko/* 572227068Sambrisko * mfi_intr_tbolt - isr entry point 573227068Sambrisko */ 574235016Sambriskovoid 575235016Sambriskomfi_intr_tbolt(void *arg) 576227068Sambrisko{ 577227068Sambrisko struct mfi_softc *sc = (struct mfi_softc *)arg; 578227068Sambrisko 579233711Sambrisko if (sc->mfi_check_clear_intr(sc) == 1) { 580227068Sambrisko return; 581227068Sambrisko } 582233711Sambrisko if (sc->mfi_detaching) 583227068Sambrisko return; 584227068Sambrisko mtx_lock(&sc->mfi_io_lock); 585227068Sambrisko mfi_tbolt_complete_cmd(sc); 586247369Ssmh sc->mfi_flags &= ~MFI_FLAGS_QFRZN; 587227068Sambrisko mfi_startio(sc); 588227068Sambrisko mtx_unlock(&sc->mfi_io_lock); 589227068Sambrisko return; 590227068Sambrisko} 591227068Sambrisko 592235016Sambrisko/* 593227068Sambrisko * map_cmd_status - Maps FW cmd status to OS cmd status 594227068Sambrisko * @cmd : Pointer to cmd 595227068Sambrisko * @status : status of cmd returned by FW 596227068Sambrisko * @ext_status : ext status of cmd returned by FW 597227068Sambrisko */ 598227068Sambrisko 599227068Sambriskovoid 600227068Sambriskomap_tbolt_cmd_status(struct mfi_command *mfi_cmd, uint8_t status, 601227068Sambrisko uint8_t ext_status) 602227068Sambrisko{ 603227068Sambrisko switch (status) { 604247369Ssmh case MFI_STAT_OK: 605247369Ssmh mfi_cmd->cm_frame->header.cmd_status = MFI_STAT_OK; 606247369Ssmh mfi_cmd->cm_frame->dcmd.header.cmd_status = MFI_STAT_OK; 607247369Ssmh mfi_cmd->cm_error = MFI_STAT_OK; 608247369Ssmh break; 609227068Sambrisko 610247369Ssmh case MFI_STAT_SCSI_IO_FAILED: 611247369Ssmh case MFI_STAT_LD_INIT_IN_PROGRESS: 612247369Ssmh mfi_cmd->cm_frame->header.cmd_status = status; 613247369Ssmh mfi_cmd->cm_frame->header.scsi_status = ext_status; 614247369Ssmh mfi_cmd->cm_frame->dcmd.header.cmd_status = status; 615247369Ssmh mfi_cmd->cm_frame->dcmd.header.scsi_status 616247369Ssmh = ext_status; 617247369Ssmh break; 618227068Sambrisko 619247369Ssmh case MFI_STAT_SCSI_DONE_WITH_ERROR: 620247369Ssmh mfi_cmd->cm_frame->header.cmd_status = ext_status; 621247369Ssmh mfi_cmd->cm_frame->dcmd.header.cmd_status = ext_status; 622247369Ssmh break; 623227068Sambrisko 624247369Ssmh case MFI_STAT_LD_OFFLINE: 625247369Ssmh case MFI_STAT_DEVICE_NOT_FOUND: 626247369Ssmh mfi_cmd->cm_frame->header.cmd_status = status; 627247369Ssmh mfi_cmd->cm_frame->dcmd.header.cmd_status = status; 628247369Ssmh break; 629227068Sambrisko 630247369Ssmh default: 631247369Ssmh mfi_cmd->cm_frame->header.cmd_status = status; 632247369Ssmh mfi_cmd->cm_frame->dcmd.header.cmd_status = status; 633247369Ssmh break; 634247369Ssmh } 635227068Sambrisko} 636227068Sambrisko 637235016Sambrisko/* 638233711Sambrisko * mfi_tbolt_return_cmd - Return a cmd to free command pool 639233711Sambrisko * @instance: Adapter soft state 640247369Ssmh * @tbolt_cmd: Tbolt command packet to be returned to free command pool 641247369Ssmh * @mfi_cmd: Oning MFI command packe 642233711Sambrisko */ 643247369Ssmhvoid 644247369Ssmhmfi_tbolt_return_cmd(struct mfi_softc *sc, struct mfi_cmd_tbolt *tbolt_cmd, 645247369Ssmh struct mfi_command *mfi_cmd) 646233711Sambrisko{ 647233711Sambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED); 648227068Sambrisko 649247369Ssmh mfi_cmd->cm_flags &= ~MFI_CMD_TBOLT; 650247369Ssmh mfi_cmd->cm_extra_frames = 0; 651247369Ssmh tbolt_cmd->sync_cmd_idx = sc->mfi_max_fw_cmds; 652247369Ssmh 653247369Ssmh TAILQ_INSERT_TAIL(&sc->mfi_cmd_tbolt_tqh, tbolt_cmd, next); 654233711Sambrisko} 655227068Sambrisko 656235014Sambriskovoid 657235014Sambriskomfi_tbolt_complete_cmd(struct mfi_softc *sc) 658227068Sambrisko{ 659227068Sambrisko struct mfi_mpi2_reply_header *desc, *reply_desc; 660247369Ssmh struct mfi_command *cmd_mfi; /* For MFA Cmds */ 661227068Sambrisko struct mfi_cmd_tbolt *cmd_tbolt; 662227068Sambrisko uint16_t smid; 663227068Sambrisko uint8_t reply_descript_type; 664227068Sambrisko struct mfi_mpi2_request_raid_scsi_io *scsi_io_req; 665227068Sambrisko uint32_t status, extStatus; 666227068Sambrisko uint16_t num_completed; 667227068Sambrisko union desc_value val; 668247369Ssmh mtx_assert(&sc->mfi_io_lock, MA_OWNED); 669227068Sambrisko 670227068Sambrisko desc = (struct mfi_mpi2_reply_header *) 671227068Sambrisko ((uintptr_t)sc->reply_frame_pool_align 672227068Sambrisko + sc->last_reply_idx * sc->reply_size); 673227068Sambrisko reply_desc = desc; 674227068Sambrisko 675247369Ssmh if (reply_desc == NULL) { 676227068Sambrisko device_printf(sc->mfi_dev, "reply desc is NULL!!\n"); 677247369Ssmh return; 678247369Ssmh } 679227068Sambrisko 680227068Sambrisko reply_descript_type = reply_desc->ReplyFlags 681227068Sambrisko & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; 682227068Sambrisko if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) 683227068Sambrisko return; 684227068Sambrisko 685227068Sambrisko num_completed = 0; 686227068Sambrisko val.word = ((union mfi_mpi2_reply_descriptor *)desc)->words; 687227068Sambrisko 688227068Sambrisko /* Read Reply descriptor */ 689227068Sambrisko while ((val.u.low != 0xFFFFFFFF) && (val.u.high != 0xFFFFFFFF)) { 690227068Sambrisko smid = reply_desc->SMID; 691247369Ssmh if (smid == 0 || smid > sc->mfi_max_fw_cmds) { 692247369Ssmh device_printf(sc->mfi_dev, "smid is %d cannot " 693247369Ssmh "proceed - skipping\n", smid); 694247369Ssmh goto next; 695227068Sambrisko } 696227068Sambrisko cmd_tbolt = sc->mfi_cmd_pool_tbolt[smid - 1]; 697247369Ssmh if (cmd_tbolt->sync_cmd_idx == sc->mfi_max_fw_cmds) { 698247369Ssmh device_printf(sc->mfi_dev, "cmd_tbolt %p " 699247369Ssmh "has invalid sync_cmd_idx=%d - skipping\n", 700247369Ssmh cmd_tbolt, cmd_tbolt->sync_cmd_idx); 701247369Ssmh goto next; 702247369Ssmh } 703227068Sambrisko cmd_mfi = &sc->mfi_commands[cmd_tbolt->sync_cmd_idx]; 704227068Sambrisko scsi_io_req = cmd_tbolt->io_request; 705227068Sambrisko 706227068Sambrisko status = cmd_mfi->cm_frame->dcmd.header.cmd_status; 707227068Sambrisko extStatus = cmd_mfi->cm_frame->dcmd.header.scsi_status; 708235014Sambrisko map_tbolt_cmd_status(cmd_mfi, status, extStatus); 709227068Sambrisko 710247369Ssmh /* mfi_tbolt_return_cmd is handled by mfi complete / return */ 711247369Ssmh if ((cmd_mfi->cm_flags & MFI_CMD_SCSI) != 0 && 712242681Sambrisko (cmd_mfi->cm_flags & MFI_CMD_POLLED) != 0) { 713242681Sambrisko /* polled LD/SYSPD IO command */ 714242681Sambrisko /* XXX mark okay for now DJA */ 715242681Sambrisko cmd_mfi->cm_frame->header.cmd_status = MFI_STAT_OK; 716247369Ssmh 717242681Sambrisko } else { 718242681Sambrisko /* remove command from busy queue if not polled */ 719247369Ssmh if ((cmd_mfi->cm_flags & MFI_ON_MFIQ_BUSY) != 0) 720247369Ssmh mfi_remove_busy(cmd_mfi); 721242681Sambrisko 722242681Sambrisko /* complete the command */ 723242681Sambrisko mfi_complete(sc, cmd_mfi); 724227068Sambrisko } 725227068Sambrisko 726247369Ssmhnext: 727227068Sambrisko sc->last_reply_idx++; 728227068Sambrisko if (sc->last_reply_idx >= sc->mfi_max_fw_cmds) { 729227068Sambrisko MFI_WRITE4(sc, MFI_RPI, sc->last_reply_idx); 730227068Sambrisko sc->last_reply_idx = 0; 731227068Sambrisko } 732247369Ssmh 733247369Ssmh /* Set it back to all 0xfff */ 734227068Sambrisko ((union mfi_mpi2_reply_descriptor*)desc)->words = 735227068Sambrisko ~((uint64_t)0x00); 736227068Sambrisko 737227068Sambrisko num_completed++; 738227068Sambrisko 739227068Sambrisko /* Get the next reply descriptor */ 740227068Sambrisko desc = (struct mfi_mpi2_reply_header *) 741227068Sambrisko ((uintptr_t)sc->reply_frame_pool_align 742227068Sambrisko + sc->last_reply_idx * sc->reply_size); 743227068Sambrisko reply_desc = desc; 744227068Sambrisko val.word = ((union mfi_mpi2_reply_descriptor*)desc)->words; 745227068Sambrisko reply_descript_type = reply_desc->ReplyFlags 746227068Sambrisko & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; 747233711Sambrisko if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) 748227068Sambrisko break; 749227068Sambrisko } 750227068Sambrisko 751227068Sambrisko if (!num_completed) 752227068Sambrisko return; 753227068Sambrisko 754227068Sambrisko /* update replyIndex to FW */ 755233711Sambrisko if (sc->last_reply_idx) 756227068Sambrisko MFI_WRITE4(sc, MFI_RPI, sc->last_reply_idx); 757227068Sambrisko 758227068Sambrisko return; 759227068Sambrisko} 760227068Sambrisko 761235016Sambrisko/* 762227068Sambrisko * mfi_get_cmd - Get a command from the free pool 763227068Sambrisko * @instance: Adapter soft state 764227068Sambrisko * 765227068Sambrisko * Returns a free command from the pool 766227068Sambrisko */ 767227068Sambrisko 768235016Sambriskostruct mfi_cmd_tbolt * 769247369Ssmhmfi_tbolt_get_cmd(struct mfi_softc *sc, struct mfi_command *mfi_cmd) 770227068Sambrisko{ 771227068Sambrisko struct mfi_cmd_tbolt *cmd = NULL; 772227068Sambrisko 773227068Sambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED); 774227068Sambrisko 775247369Ssmh if ((cmd = TAILQ_FIRST(&sc->mfi_cmd_tbolt_tqh)) == NULL) 776247369Ssmh return (NULL); 777227068Sambrisko TAILQ_REMOVE(&sc->mfi_cmd_tbolt_tqh, cmd, next); 778227068Sambrisko memset((uint8_t *)cmd->sg_frame, 0, MEGASAS_MAX_SZ_CHAIN_FRAME); 779227068Sambrisko memset((uint8_t *)cmd->io_request, 0, 780227068Sambrisko MEGASAS_THUNDERBOLT_NEW_MSG_SIZE); 781247369Ssmh 782247369Ssmh cmd->sync_cmd_idx = mfi_cmd->cm_index; 783247369Ssmh mfi_cmd->cm_extra_frames = cmd->index; /* Frame count used as SMID */ 784247369Ssmh mfi_cmd->cm_flags |= MFI_CMD_TBOLT; 785247369Ssmh 786227068Sambrisko return cmd; 787227068Sambrisko} 788227068Sambrisko 789227068Sambriskounion mfi_mpi2_request_descriptor * 790227068Sambriskomfi_tbolt_get_request_descriptor(struct mfi_softc *sc, uint16_t index) 791227068Sambrisko{ 792227068Sambrisko uint8_t *p; 793227068Sambrisko 794227068Sambrisko if (index >= sc->mfi_max_fw_cmds) { 795227068Sambrisko device_printf(sc->mfi_dev, "Invalid SMID (0x%x)request " 796227068Sambrisko "for descriptor\n", index); 797227068Sambrisko return NULL; 798227068Sambrisko } 799227068Sambrisko p = sc->request_desc_pool + sizeof(union mfi_mpi2_request_descriptor) 800227068Sambrisko * index; 801227068Sambrisko memset(p, 0, sizeof(union mfi_mpi2_request_descriptor)); 802227068Sambrisko return (union mfi_mpi2_request_descriptor *)p; 803227068Sambrisko} 804227068Sambrisko 805227068Sambrisko 806233711Sambrisko/* Used to build IOCTL cmd */ 807227068Sambriskouint8_t 808227068Sambriskomfi_build_mpt_pass_thru(struct mfi_softc *sc, struct mfi_command *mfi_cmd) 809227068Sambrisko{ 810227068Sambrisko MPI25_IEEE_SGE_CHAIN64 *mpi25_ieee_chain; 811227068Sambrisko struct mfi_mpi2_request_raid_scsi_io *io_req; 812227068Sambrisko struct mfi_cmd_tbolt *cmd; 813227068Sambrisko 814247369Ssmh cmd = mfi_tbolt_get_cmd(sc, mfi_cmd); 815227068Sambrisko if (!cmd) 816227068Sambrisko return EBUSY; 817227068Sambrisko io_req = cmd->io_request; 818227068Sambrisko mpi25_ieee_chain = (MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL.IeeeChain; 819227068Sambrisko 820227068Sambrisko io_req->Function = MPI2_FUNCTION_PASSTHRU_IO_REQUEST; 821227068Sambrisko io_req->SGLOffset0 = offsetof(struct mfi_mpi2_request_raid_scsi_io, 822227068Sambrisko SGL) / 4; 823227068Sambrisko io_req->ChainOffset = sc->chain_offset_value_for_mpt_ptmsg; 824227068Sambrisko 825227068Sambrisko mpi25_ieee_chain->Address = mfi_cmd->cm_frame_busaddr; 826227068Sambrisko 827227068Sambrisko /* 828227068Sambrisko In MFI pass thru, nextChainOffset will always be zero to 829227068Sambrisko indicate the end of the chain. 830227068Sambrisko */ 831227068Sambrisko mpi25_ieee_chain->Flags= MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT 832227068Sambrisko | MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR; 833227068Sambrisko 834227068Sambrisko /* setting the length to the maximum length */ 835227068Sambrisko mpi25_ieee_chain->Length = 1024; 836227068Sambrisko 837227068Sambrisko return 0; 838227068Sambrisko} 839227068Sambrisko 840227068Sambriskovoid 841227068Sambriskomfi_tbolt_build_ldio(struct mfi_softc *sc, struct mfi_command *mfi_cmd, 842227068Sambrisko struct mfi_cmd_tbolt *cmd) 843227068Sambrisko{ 844227068Sambrisko uint32_t start_lba_lo = 0, start_lba_hi = 0, device_id; 845227068Sambrisko struct mfi_mpi2_request_raid_scsi_io *io_request; 846227068Sambrisko struct IO_REQUEST_INFO io_info; 847227068Sambrisko 848227068Sambrisko device_id = mfi_cmd->cm_frame->io.header.target_id; 849227068Sambrisko io_request = cmd->io_request; 850227068Sambrisko io_request->RaidContext.TargetID = device_id; 851227068Sambrisko io_request->RaidContext.Status = 0; 852261535Smarkj io_request->RaidContext.exStatus = 0; 853261535Smarkj io_request->RaidContext.regLockFlags = 0; 854227068Sambrisko 855227068Sambrisko start_lba_lo = mfi_cmd->cm_frame->io.lba_lo; 856227068Sambrisko start_lba_hi = mfi_cmd->cm_frame->io.lba_hi; 857227068Sambrisko 858227068Sambrisko memset(&io_info, 0, sizeof(struct IO_REQUEST_INFO)); 859227068Sambrisko io_info.ldStartBlock = ((uint64_t)start_lba_hi << 32) | start_lba_lo; 860227068Sambrisko io_info.numBlocks = mfi_cmd->cm_frame->io.header.data_len; 861227068Sambrisko io_info.ldTgtId = device_id; 862227068Sambrisko if ((mfi_cmd->cm_frame->header.flags & MFI_FRAME_DIR_READ) == 863227068Sambrisko MFI_FRAME_DIR_READ) 864227068Sambrisko io_info.isRead = 1; 865227068Sambrisko 866242681Sambrisko io_request->RaidContext.timeoutValue 867242681Sambrisko = MFI_FUSION_FP_DEFAULT_TIMEOUT; 868242681Sambrisko io_request->Function = MPI2_FUNCTION_LD_IO_REQUEST; 869242681Sambrisko io_request->DevHandle = device_id; 870242681Sambrisko cmd->request_desc->header.RequestFlags 871242681Sambrisko = (MFI_REQ_DESCRIPT_FLAGS_LD_IO 872242681Sambrisko << MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 873233711Sambrisko if ((io_request->IoFlags == 6) && (io_info.numBlocks == 0)) 874227068Sambrisko io_request->RaidContext.RegLockLength = 0x100; 875227068Sambrisko io_request->DataLength = mfi_cmd->cm_frame->io.header.data_len 876227068Sambrisko * MFI_SECTOR_LEN; 877227068Sambrisko} 878227068Sambrisko 879235016Sambriskoint 880235016Sambriskomfi_tbolt_build_io(struct mfi_softc *sc, struct mfi_command *mfi_cmd, 881235016Sambrisko struct mfi_cmd_tbolt *cmd) 882227068Sambrisko{ 883242681Sambrisko struct mfi_mpi2_request_raid_scsi_io *io_request; 884227068Sambrisko uint32_t sge_count; 885242681Sambrisko uint8_t cdb_len; 886242681Sambrisko int readop; 887242681Sambrisko u_int64_t lba; 888227068Sambrisko 889242681Sambrisko io_request = cmd->io_request; 890242681Sambrisko if (!(mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_READ 891242681Sambrisko || mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)) 892242681Sambrisko return 1; 893227068Sambrisko 894242681Sambrisko mfi_tbolt_build_ldio(sc, mfi_cmd, cmd); 895227068Sambrisko 896242681Sambrisko /* Convert to SCSI command CDB */ 897242681Sambrisko bzero(io_request->CDB.CDB32, sizeof(io_request->CDB.CDB32)); 898242681Sambrisko if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE) 899242681Sambrisko readop = 0; 900242681Sambrisko else 901242681Sambrisko readop = 1; 902227068Sambrisko 903242681Sambrisko lba = mfi_cmd->cm_frame->io.lba_hi; 904242681Sambrisko lba = (lba << 32) + mfi_cmd->cm_frame->io.lba_lo; 905242681Sambrisko cdb_len = mfi_build_cdb(readop, 0, lba, 906242681Sambrisko mfi_cmd->cm_frame->io.header.data_len, io_request->CDB.CDB32); 907242681Sambrisko 908242681Sambrisko /* Just the CDB length, rest of the Flags are zero */ 909227068Sambrisko io_request->IoFlags = cdb_len; 910227068Sambrisko 911227068Sambrisko /* 912227068Sambrisko * Construct SGL 913227068Sambrisko */ 914227068Sambrisko sge_count = mfi_tbolt_make_sgl(sc, mfi_cmd, 915227068Sambrisko (pMpi25IeeeSgeChain64_t) &io_request->SGL, cmd); 916227068Sambrisko if (sge_count > sc->mfi_max_sge) { 917227068Sambrisko device_printf(sc->mfi_dev, "Error. sge_count (0x%x) exceeds " 918227068Sambrisko "max (0x%x) allowed\n", sge_count, sc->mfi_max_sge); 919227068Sambrisko return 1; 920227068Sambrisko } 921227068Sambrisko io_request->RaidContext.numSGE = sge_count; 922227068Sambrisko io_request->SGLFlags = MPI2_SGE_FLAGS_64_BIT_ADDRESSING; 923227068Sambrisko 924227068Sambrisko if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE) 925227068Sambrisko io_request->Control = MPI2_SCSIIO_CONTROL_WRITE; 926227068Sambrisko else 927227068Sambrisko io_request->Control = MPI2_SCSIIO_CONTROL_READ; 928227068Sambrisko 929227068Sambrisko io_request->SGLOffset0 = offsetof( 930227068Sambrisko struct mfi_mpi2_request_raid_scsi_io, SGL)/4; 931227068Sambrisko 932227068Sambrisko io_request->SenseBufferLowAddress = mfi_cmd->cm_sense_busaddr; 933227068Sambrisko io_request->SenseBufferLength = MFI_SENSE_LEN; 934242681Sambrisko io_request->RaidContext.Status = MFI_STAT_INVALID_STATUS; 935242681Sambrisko io_request->RaidContext.exStatus = MFI_STAT_INVALID_STATUS; 936242681Sambrisko 937227068Sambrisko return 0; 938227068Sambrisko} 939227068Sambrisko 940227068Sambrisko 941227068Sambriskostatic int 942227068Sambriskomfi_tbolt_make_sgl(struct mfi_softc *sc, struct mfi_command *mfi_cmd, 943233711Sambrisko pMpi25IeeeSgeChain64_t sgl_ptr, struct mfi_cmd_tbolt *cmd) 944227068Sambrisko{ 945233711Sambrisko uint8_t i, sg_processed, sg_to_process; 946227068Sambrisko uint8_t sge_count, sge_idx; 947227068Sambrisko union mfi_sgl *os_sgl; 948261535Smarkj pMpi25IeeeSgeChain64_t sgl_end; 949227068Sambrisko 950227068Sambrisko /* 951227068Sambrisko * Return 0 if there is no data transfer 952227068Sambrisko */ 953227068Sambrisko if (!mfi_cmd->cm_sg || !mfi_cmd->cm_len) { 954227068Sambrisko device_printf(sc->mfi_dev, "Buffer empty \n"); 955227068Sambrisko return 0; 956227068Sambrisko } 957227068Sambrisko os_sgl = mfi_cmd->cm_sg; 958227068Sambrisko sge_count = mfi_cmd->cm_frame->header.sg_count; 959227068Sambrisko 960227068Sambrisko if (sge_count > sc->mfi_max_sge) { 961227068Sambrisko device_printf(sc->mfi_dev, "sgl ptr %p sg_cnt %d \n", 962233711Sambrisko os_sgl, sge_count); 963227068Sambrisko return sge_count; 964227068Sambrisko } 965227068Sambrisko 966227068Sambrisko if (sge_count > sc->max_SGEs_in_main_message) 967227068Sambrisko /* One element to store the chain info */ 968227068Sambrisko sge_idx = sc->max_SGEs_in_main_message - 1; 969227068Sambrisko else 970227068Sambrisko sge_idx = sge_count; 971227068Sambrisko 972261535Smarkj if (sc->mfi_flags & (MFI_FLAGS_INVADER | MFI_FLAGS_FURY)) { 973261535Smarkj sgl_end = sgl_ptr + (sc->max_SGEs_in_main_message - 1); 974261535Smarkj sgl_end->Flags = 0; 975261535Smarkj } 976261535Smarkj 977227068Sambrisko for (i = 0; i < sge_idx; i++) { 978227068Sambrisko /* 979233711Sambrisko * For 32bit BSD we are getting 32 bit SGL's from OS 980233711Sambrisko * but FW only take 64 bit SGL's so copying from 32 bit 981233711Sambrisko * SGL's to 64. 982233711Sambrisko */ 983227068Sambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY) { 984227068Sambrisko sgl_ptr->Length = os_sgl->sg_skinny[i].len; 985227068Sambrisko sgl_ptr->Address = os_sgl->sg_skinny[i].addr; 986227068Sambrisko } else { 987227068Sambrisko sgl_ptr->Length = os_sgl->sg32[i].len; 988233711Sambrisko sgl_ptr->Address = os_sgl->sg32[i].addr; 989227068Sambrisko } 990261535Smarkj if (i == sge_count - 1 && 991261535Smarkj (sc->mfi_flags & (MFI_FLAGS_INVADER | MFI_FLAGS_FURY))) 992261535Smarkj sgl_ptr->Flags = MPI25_IEEE_SGE_FLAGS_END_OF_LIST; 993261535Smarkj else 994261535Smarkj sgl_ptr->Flags = 0; 995227068Sambrisko sgl_ptr++; 996227068Sambrisko cmd->io_request->ChainOffset = 0; 997227068Sambrisko } 998227068Sambrisko 999227068Sambrisko sg_processed = i; 1000227068Sambrisko 1001227068Sambrisko if (sg_processed < sge_count) { 1002227068Sambrisko pMpi25IeeeSgeChain64_t sg_chain; 1003227068Sambrisko sg_to_process = sge_count - sg_processed; 1004227068Sambrisko cmd->io_request->ChainOffset = 1005227068Sambrisko sc->chain_offset_value_for_main_message; 1006227068Sambrisko sg_chain = sgl_ptr; 1007227068Sambrisko /* Prepare chain element */ 1008227068Sambrisko sg_chain->NextChainOffset = 0; 1009261535Smarkj if (sc->mfi_flags & (MFI_FLAGS_INVADER | MFI_FLAGS_FURY)) 1010261535Smarkj sg_chain->Flags = MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT; 1011261535Smarkj else 1012261535Smarkj sg_chain->Flags = MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT | 1013261535Smarkj MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR; 1014227068Sambrisko sg_chain->Length = (sizeof(MPI2_SGE_IO_UNION) * 1015227068Sambrisko (sge_count - sg_processed)); 1016233711Sambrisko sg_chain->Address = cmd->sg_frame_phys_addr; 1017227068Sambrisko sgl_ptr = (pMpi25IeeeSgeChain64_t)cmd->sg_frame; 1018227068Sambrisko for (; i < sge_count; i++) { 1019227068Sambrisko if (sc->mfi_flags & MFI_FLAGS_SKINNY) { 1020227068Sambrisko sgl_ptr->Length = os_sgl->sg_skinny[i].len; 1021227068Sambrisko sgl_ptr->Address = os_sgl->sg_skinny[i].addr; 1022233711Sambrisko } else { 1023227068Sambrisko sgl_ptr->Length = os_sgl->sg32[i].len; 1024233711Sambrisko sgl_ptr->Address = os_sgl->sg32[i].addr; 1025227068Sambrisko } 1026261535Smarkj if (i == sge_count - 1 && 1027261535Smarkj (sc->mfi_flags & 1028261535Smarkj (MFI_FLAGS_INVADER | MFI_FLAGS_FURY))) 1029261535Smarkj sgl_ptr->Flags = 1030261535Smarkj MPI25_IEEE_SGE_FLAGS_END_OF_LIST; 1031261535Smarkj else 1032261535Smarkj sgl_ptr->Flags = 0; 1033227068Sambrisko sgl_ptr++; 1034227068Sambrisko } 1035227068Sambrisko } 1036227068Sambrisko return sge_count; 1037227068Sambrisko} 1038227068Sambrisko 1039227068Sambriskounion mfi_mpi2_request_descriptor * 1040227068Sambriskomfi_build_and_issue_cmd(struct mfi_softc *sc, struct mfi_command *mfi_cmd) 1041227068Sambrisko{ 1042227068Sambrisko struct mfi_cmd_tbolt *cmd; 1043227068Sambrisko union mfi_mpi2_request_descriptor *req_desc = NULL; 1044227068Sambrisko uint16_t index; 1045247369Ssmh cmd = mfi_tbolt_get_cmd(sc, mfi_cmd); 1046247369Ssmh if (cmd == NULL) 1047247369Ssmh return (NULL); 1048227068Sambrisko 1049227068Sambrisko index = cmd->index; 1050227068Sambrisko req_desc = mfi_tbolt_get_request_descriptor(sc, index-1); 1051247369Ssmh if (req_desc == NULL) { 1052247369Ssmh mfi_tbolt_return_cmd(sc, cmd, mfi_cmd); 1053247369Ssmh return (NULL); 1054247369Ssmh } 1055247369Ssmh 1056247369Ssmh if (mfi_tbolt_build_io(sc, mfi_cmd, cmd) != 0) { 1057247369Ssmh mfi_tbolt_return_cmd(sc, cmd, mfi_cmd); 1058247369Ssmh return (NULL); 1059247369Ssmh } 1060227068Sambrisko req_desc->header.SMID = index; 1061227068Sambrisko return req_desc; 1062227068Sambrisko} 1063227068Sambrisko 1064227068Sambriskounion mfi_mpi2_request_descriptor * 1065227068Sambriskomfi_tbolt_build_mpt_cmd(struct mfi_softc *sc, struct mfi_command *cmd) 1066227068Sambrisko{ 1067227068Sambrisko union mfi_mpi2_request_descriptor *req_desc = NULL; 1068227068Sambrisko uint16_t index; 1069227068Sambrisko if (mfi_build_mpt_pass_thru(sc, cmd)) { 1070227068Sambrisko device_printf(sc->mfi_dev, "Couldn't build MFI pass thru " 1071227068Sambrisko "cmd\n"); 1072227068Sambrisko return NULL; 1073227068Sambrisko } 1074227068Sambrisko /* For fusion the frame_count variable is used for SMID */ 1075227068Sambrisko index = cmd->cm_extra_frames; 1076227068Sambrisko 1077227068Sambrisko req_desc = mfi_tbolt_get_request_descriptor(sc, index - 1); 1078247369Ssmh if (req_desc == NULL) 1079227068Sambrisko return NULL; 1080227068Sambrisko 1081237546Skevlo bzero(req_desc, sizeof(*req_desc)); 1082227068Sambrisko req_desc->header.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO << 1083227068Sambrisko MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 1084227068Sambrisko req_desc->header.SMID = index; 1085227068Sambrisko return req_desc; 1086227068Sambrisko} 1087227068Sambrisko 1088227068Sambriskoint 1089227068Sambriskomfi_tbolt_send_frame(struct mfi_softc *sc, struct mfi_command *cm) 1090227068Sambrisko{ 1091227068Sambrisko struct mfi_frame_header *hdr; 1092227068Sambrisko uint8_t *cdb; 1093227068Sambrisko union mfi_mpi2_request_descriptor *req_desc = NULL; 1094247369Ssmh int tm = mfi_polled_cmd_timeout * 1000; 1095227068Sambrisko 1096227068Sambrisko hdr = &cm->cm_frame->header; 1097227068Sambrisko cdb = cm->cm_frame->pass.cdb; 1098233711Sambrisko if (sc->adpreset) 1099227068Sambrisko return 1; 1100227068Sambrisko if ((cm->cm_flags & MFI_CMD_POLLED) == 0) { 1101227068Sambrisko cm->cm_timestamp = time_uptime; 1102227068Sambrisko mfi_enqueue_busy(cm); 1103242681Sambrisko } else { /* still get interrupts for it */ 1104235014Sambrisko hdr->cmd_status = MFI_STAT_INVALID_STATUS; 1105227068Sambrisko hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE; 1106227068Sambrisko } 1107227068Sambrisko 1108227068Sambrisko if (hdr->cmd == MFI_CMD_PD_SCSI_IO) { 1109227068Sambrisko /* check for inquiry commands coming from CLI */ 1110360843Sdim if (cdb[0] != 0x28 && cdb[0] != 0x2A) { 1111227068Sambrisko if ((req_desc = mfi_tbolt_build_mpt_cmd(sc, cm)) == 1112227068Sambrisko NULL) { 1113227068Sambrisko device_printf(sc->mfi_dev, "Mapping from MFI " 1114227068Sambrisko "to MPT Failed \n"); 1115227068Sambrisko return 1; 1116227068Sambrisko } 1117227068Sambrisko } 1118227068Sambrisko else 1119227068Sambrisko device_printf(sc->mfi_dev, "DJA NA XXX SYSPDIO\n"); 1120242681Sambrisko } else if (hdr->cmd == MFI_CMD_LD_SCSI_IO || 1121227068Sambrisko hdr->cmd == MFI_CMD_LD_READ || hdr->cmd == MFI_CMD_LD_WRITE) { 1122242681Sambrisko cm->cm_flags |= MFI_CMD_SCSI; 1123227068Sambrisko if ((req_desc = mfi_build_and_issue_cmd(sc, cm)) == NULL) { 1124227068Sambrisko device_printf(sc->mfi_dev, "LDIO Failed \n"); 1125227068Sambrisko return 1; 1126227068Sambrisko } 1127242681Sambrisko } else if ((req_desc = mfi_tbolt_build_mpt_cmd(sc, cm)) == NULL) { 1128247369Ssmh device_printf(sc->mfi_dev, "Mapping from MFI to MPT Failed\n"); 1129247369Ssmh return (1); 1130242681Sambrisko } 1131242681Sambrisko 1132242681Sambrisko if (cm->cm_flags & MFI_CMD_SCSI) { 1133242681Sambrisko /* 1134242681Sambrisko * LD IO needs to be posted since it doesn't get 1135242681Sambrisko * acknowledged via a status update so have the 1136242681Sambrisko * controller reply via mfi_tbolt_complete_cmd. 1137242681Sambrisko */ 1138242681Sambrisko hdr->flags &= ~MFI_FRAME_DONT_POST_IN_REPLY_QUEUE; 1139242681Sambrisko } 1140242681Sambrisko 1141227068Sambrisko MFI_WRITE4(sc, MFI_ILQP, (req_desc->words & 0xFFFFFFFF)); 1142227068Sambrisko MFI_WRITE4(sc, MFI_IHQP, (req_desc->words >>0x20)); 1143227068Sambrisko 1144227068Sambrisko if ((cm->cm_flags & MFI_CMD_POLLED) == 0) 1145227068Sambrisko return 0; 1146227068Sambrisko 1147247369Ssmh /* 1148247369Ssmh * This is a polled command, so busy-wait for it to complete. 1149247369Ssmh * 1150247369Ssmh * The value of hdr->cmd_status is updated directly by the hardware 1151298955Spfg * so there is no guarantee that mfi_tbolt_complete_cmd is called 1152247369Ssmh * prior to this value changing. 1153247369Ssmh */ 1154235014Sambrisko while (hdr->cmd_status == MFI_STAT_INVALID_STATUS) { 1155227068Sambrisko DELAY(1000); 1156227068Sambrisko tm -= 1; 1157227068Sambrisko if (tm <= 0) 1158242681Sambrisko break; 1159242681Sambrisko if (cm->cm_flags & MFI_CMD_SCSI) { 1160247369Ssmh /* 1161247369Ssmh * Force check reply queue. 1162247369Ssmh * This ensures that dump works correctly 1163247369Ssmh */ 1164242681Sambrisko mfi_tbolt_complete_cmd(sc); 1165242681Sambrisko } 1166227068Sambrisko } 1167235016Sambrisko 1168247369Ssmh /* ensure the command cleanup has been processed before returning */ 1169247369Ssmh mfi_tbolt_complete_cmd(sc); 1170247369Ssmh 1171235014Sambrisko if (hdr->cmd_status == MFI_STAT_INVALID_STATUS) { 1172227068Sambrisko device_printf(sc->mfi_dev, "Frame %p timed out " 1173235014Sambrisko "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode); 1174227068Sambrisko return (ETIMEDOUT); 1175227068Sambrisko } 1176227068Sambrisko return 0; 1177227068Sambrisko} 1178227068Sambrisko 1179235016Sambriskostatic void 1180247369Ssmhmfi_issue_pending_cmds_again(struct mfi_softc *sc) 1181227068Sambrisko{ 1182233711Sambrisko struct mfi_command *cm, *tmp; 1183247369Ssmh struct mfi_cmd_tbolt *cmd; 1184227068Sambrisko 1185227068Sambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1186233711Sambrisko TAILQ_FOREACH_REVERSE_SAFE(cm, &sc->mfi_busy, BUSYQ, cm_link, tmp) { 1187227068Sambrisko 1188227068Sambrisko cm->retry_for_fw_reset++; 1189227068Sambrisko 1190227068Sambrisko /* 1191227068Sambrisko * If a command has continuously been tried multiple times 1192227068Sambrisko * and causing a FW reset condition, no further recoveries 1193227068Sambrisko * should be performed on the controller 1194227068Sambrisko */ 1195227068Sambrisko if (cm->retry_for_fw_reset == 3) { 1196247369Ssmh device_printf(sc->mfi_dev, "megaraid_sas: command %p " 1197247369Ssmh "index=%d was tried multiple times during adapter " 1198247369Ssmh "reset - Shutting down the HBA\n", cm, cm->cm_index); 1199227068Sambrisko mfi_kill_hba(sc); 1200227068Sambrisko sc->hw_crit_error = 1; 1201227068Sambrisko return; 1202227068Sambrisko } 1203227068Sambrisko 1204247369Ssmh mfi_remove_busy(cm); 1205247369Ssmh if ((cm->cm_flags & MFI_CMD_TBOLT) != 0) { 1206247369Ssmh if (cm->cm_extra_frames != 0 && cm->cm_extra_frames <= 1207247369Ssmh sc->mfi_max_fw_cmds) { 1208247369Ssmh cmd = sc->mfi_cmd_pool_tbolt[cm->cm_extra_frames - 1]; 1209247369Ssmh mfi_tbolt_return_cmd(sc, cmd, cm); 1210247369Ssmh } else { 1211247369Ssmh device_printf(sc->mfi_dev, 1212247369Ssmh "Invalid extra_frames: %d detected\n", 1213247369Ssmh cm->cm_extra_frames); 1214227068Sambrisko } 1215227068Sambrisko } 1216247369Ssmh 1217247369Ssmh if (cm->cm_frame->dcmd.opcode != MFI_DCMD_CTRL_EVENT_WAIT) { 1218247369Ssmh device_printf(sc->mfi_dev, 1219247369Ssmh "APJ ****requeue command %p index=%d\n", 1220247369Ssmh cm, cm->cm_index); 1221247369Ssmh mfi_requeue_ready(cm); 1222247369Ssmh } else 1223247369Ssmh mfi_release_command(cm); 1224227068Sambrisko } 1225227068Sambrisko mfi_startio(sc); 1226227068Sambrisko} 1227227068Sambrisko 1228235016Sambriskostatic void 1229247369Ssmhmfi_kill_hba(struct mfi_softc *sc) 1230227068Sambrisko{ 1231227068Sambrisko if (sc->mfi_flags & MFI_FLAGS_TBOLT) 1232247369Ssmh MFI_WRITE4(sc, 0x00, MFI_STOP_ADP); 1233227068Sambrisko else 1234247369Ssmh MFI_WRITE4(sc, MFI_IDB, MFI_STOP_ADP); 1235227068Sambrisko} 1236227068Sambrisko 1237235016Sambriskostatic void 1238235016Sambriskomfi_process_fw_state_chg_isr(void *arg) 1239227068Sambrisko{ 1240227068Sambrisko struct mfi_softc *sc= (struct mfi_softc *)arg; 1241227068Sambrisko int error, status; 1242227068Sambrisko 1243227068Sambrisko if (sc->adpreset == 1) { 1244233711Sambrisko device_printf(sc->mfi_dev, "First stage of FW reset " 1245227068Sambrisko "initiated...\n"); 1246227068Sambrisko 1247227068Sambrisko sc->mfi_adp_reset(sc); 1248227068Sambrisko sc->mfi_enable_intr(sc); 1249227068Sambrisko 1250233711Sambrisko device_printf(sc->mfi_dev, "First stage of reset complete, " 1251227068Sambrisko "second stage initiated...\n"); 1252227068Sambrisko 1253227068Sambrisko sc->adpreset = 2; 1254227068Sambrisko 1255227068Sambrisko /* waiting for about 20 second before start the second init */ 1256233711Sambrisko for (int wait = 0; wait < 20000; wait++) 1257227068Sambrisko DELAY(1000); 1258233711Sambrisko device_printf(sc->mfi_dev, "Second stage of FW reset " 1259227068Sambrisko "initiated...\n"); 1260233711Sambrisko while ((status = MFI_READ4(sc, MFI_RSR)) & 0x04); 1261227068Sambrisko 1262227068Sambrisko sc->mfi_disable_intr(sc); 1263227068Sambrisko 1264227068Sambrisko /* We expect the FW state to be READY */ 1265227068Sambrisko if (mfi_transition_firmware(sc)) { 1266233711Sambrisko device_printf(sc->mfi_dev, "controller is not in " 1267233711Sambrisko "ready state\n"); 1268227068Sambrisko mfi_kill_hba(sc); 1269247369Ssmh sc->hw_crit_error = 1; 1270247369Ssmh return; 1271227068Sambrisko } 1272247369Ssmh if ((error = mfi_tbolt_init_MFI_queue(sc)) != 0) { 1273247369Ssmh device_printf(sc->mfi_dev, "Failed to initialise MFI " 1274247369Ssmh "queue\n"); 1275247369Ssmh mfi_kill_hba(sc); 1276247369Ssmh sc->hw_crit_error = 1; 1277247369Ssmh return; 1278247369Ssmh } 1279227068Sambrisko 1280247369Ssmh /* Init last reply index and max */ 1281247369Ssmh MFI_WRITE4(sc, MFI_RFPI, sc->mfi_max_fw_cmds - 1); 1282247369Ssmh MFI_WRITE4(sc, MFI_RPI, sc->last_reply_idx); 1283227068Sambrisko 1284227068Sambrisko sc->mfi_enable_intr(sc); 1285227068Sambrisko sc->adpreset = 0; 1286247369Ssmh if (sc->mfi_aen_cm != NULL) { 1287247369Ssmh free(sc->mfi_aen_cm->cm_data, M_MFIBUF); 1288247369Ssmh mfi_remove_busy(sc->mfi_aen_cm); 1289227068Sambrisko mfi_release_command(sc->mfi_aen_cm); 1290227068Sambrisko sc->mfi_aen_cm = NULL; 1291227068Sambrisko } 1292247369Ssmh 1293247369Ssmh if (sc->mfi_map_sync_cm != NULL) { 1294247369Ssmh mfi_remove_busy(sc->mfi_map_sync_cm); 1295235014Sambrisko mfi_release_command(sc->mfi_map_sync_cm); 1296235014Sambrisko sc->mfi_map_sync_cm = NULL; 1297227068Sambrisko } 1298227068Sambrisko mfi_issue_pending_cmds_again(sc); 1299227068Sambrisko 1300227068Sambrisko /* 1301227068Sambrisko * Issue pending command can result in adapter being marked 1302227068Sambrisko * dead because of too many re-tries. Check for that 1303227068Sambrisko * condition before clearing the reset condition on the FW 1304227068Sambrisko */ 1305227068Sambrisko if (!sc->hw_crit_error) { 1306227068Sambrisko /* 1307247369Ssmh * Initiate AEN (Asynchronous Event Notification) & 1308247369Ssmh * Sync Map 1309227068Sambrisko */ 1310227068Sambrisko mfi_aen_setup(sc, sc->last_seq_num); 1311247369Ssmh mfi_tbolt_sync_map_info(sc); 1312247369Ssmh 1313227068Sambrisko sc->issuepend_done = 1; 1314233711Sambrisko device_printf(sc->mfi_dev, "second stage of reset " 1315227068Sambrisko "complete, FW is ready now.\n"); 1316227068Sambrisko } else { 1317233711Sambrisko device_printf(sc->mfi_dev, "second stage of reset " 1318227068Sambrisko "never completed, hba was marked offline.\n"); 1319227068Sambrisko } 1320227068Sambrisko } else { 1321227068Sambrisko device_printf(sc->mfi_dev, "mfi_process_fw_state_chg_isr " 1322227068Sambrisko "called with unhandled value:%d\n", sc->adpreset); 1323227068Sambrisko } 1324227068Sambrisko} 1325235014Sambrisko 1326235014Sambrisko/* 1327235014Sambrisko * The ThunderBolt HW has an option for the driver to directly 1328235016Sambrisko * access the underlying disks and operate on the RAID. To 1329235014Sambrisko * do this there needs to be a capability to keep the RAID controller 1330235014Sambrisko * and driver in sync. The FreeBSD driver does not take advantage 1331235014Sambrisko * of this feature since it adds a lot of complexity and slows down 1332235014Sambrisko * performance. Performance is gained by using the controller's 1333235014Sambrisko * cache etc. 1334235014Sambrisko * 1335235014Sambrisko * Even though this driver doesn't access the disks directly, an 1336235014Sambrisko * AEN like command is used to inform the RAID firmware to "sync" 1337235014Sambrisko * with all LD's via the MFI_DCMD_LD_MAP_GET_INFO command. This 1338235014Sambrisko * command in write mode will return when the RAID firmware has 1339235014Sambrisko * detected a change to the RAID state. Examples of this type 1340235014Sambrisko * of change are removing a disk. Once the command returns then 1341235014Sambrisko * the driver needs to acknowledge this and "sync" all LD's again. 1342235014Sambrisko * This repeats until we shutdown. Then we need to cancel this 1343235014Sambrisko * pending command. 1344235014Sambrisko * 1345235014Sambrisko * If this is not done right the RAID firmware will not remove a 1346235014Sambrisko * pulled drive and the RAID won't go degraded etc. Effectively, 1347235014Sambrisko * stopping any RAID mangement to functions. 1348235014Sambrisko * 1349235014Sambrisko * Doing another LD sync, requires the use of an event since the 1350235014Sambrisko * driver needs to do a mfi_wait_command and can't do that in an 1351235014Sambrisko * interrupt thread. 1352235014Sambrisko * 1353235014Sambrisko * The driver could get the RAID state via the MFI_DCMD_LD_MAP_GET_INFO 1354298955Spfg * That requires a bunch of structure and it is simpler to just do 1355235014Sambrisko * the MFI_DCMD_LD_GET_LIST versus walking the RAID map. 1356235014Sambrisko */ 1357235014Sambrisko 1358235014Sambriskovoid 1359235014Sambriskomfi_tbolt_sync_map_info(struct mfi_softc *sc) 1360235014Sambrisko{ 1361235014Sambrisko int error = 0, i; 1362247369Ssmh struct mfi_command *cmd = NULL; 1363247369Ssmh struct mfi_dcmd_frame *dcmd = NULL; 1364235014Sambrisko uint32_t context = 0; 1365247369Ssmh union mfi_ld_ref *ld_sync = NULL; 1366235014Sambrisko size_t ld_size; 1367235014Sambrisko struct mfi_frame_header *hdr; 1368235014Sambrisko struct mfi_command *cm = NULL; 1369235014Sambrisko struct mfi_ld_list *list = NULL; 1370235014Sambrisko 1371247369Ssmh mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1372247369Ssmh 1373235014Sambrisko if (sc->mfi_map_sync_cm != NULL || sc->cm_map_abort) 1374235014Sambrisko return; 1375235014Sambrisko 1376235014Sambrisko error = mfi_dcmd_command(sc, &cm, MFI_DCMD_LD_GET_LIST, 1377235014Sambrisko (void **)&list, sizeof(*list)); 1378235014Sambrisko if (error) 1379235014Sambrisko goto out; 1380235014Sambrisko 1381235014Sambrisko cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAIN; 1382247369Ssmh 1383235014Sambrisko if (mfi_wait_command(sc, cm) != 0) { 1384235014Sambrisko device_printf(sc->mfi_dev, "Failed to get device listing\n"); 1385235014Sambrisko goto out; 1386235014Sambrisko } 1387235014Sambrisko 1388235014Sambrisko hdr = &cm->cm_frame->header; 1389235014Sambrisko if (hdr->cmd_status != MFI_STAT_OK) { 1390235014Sambrisko device_printf(sc->mfi_dev, "MFI_DCMD_LD_GET_LIST failed %x\n", 1391235014Sambrisko hdr->cmd_status); 1392235014Sambrisko goto out; 1393235014Sambrisko } 1394235014Sambrisko 1395235014Sambrisko ld_size = sizeof(*ld_sync) * list->ld_count; 1396235014Sambrisko ld_sync = (union mfi_ld_ref *) malloc(ld_size, M_MFIBUF, 1397247369Ssmh M_NOWAIT | M_ZERO); 1398235040Sambrisko if (ld_sync == NULL) { 1399235040Sambrisko device_printf(sc->mfi_dev, "Failed to allocate sync\n"); 1400235040Sambrisko goto out; 1401235040Sambrisko } 1402247369Ssmh for (i = 0; i < list->ld_count; i++) 1403235014Sambrisko ld_sync[i].ref = list->ld_list[i].ld.ref; 1404235014Sambrisko 1405235040Sambrisko if ((cmd = mfi_dequeue_free(sc)) == NULL) { 1406235040Sambrisko device_printf(sc->mfi_dev, "Failed to get command\n"); 1407235040Sambrisko free(ld_sync, M_MFIBUF); 1408235040Sambrisko goto out; 1409235040Sambrisko } 1410242681Sambrisko 1411235014Sambrisko context = cmd->cm_frame->header.context; 1412235014Sambrisko bzero(cmd->cm_frame, sizeof(union mfi_frame)); 1413235014Sambrisko cmd->cm_frame->header.context = context; 1414235014Sambrisko 1415235014Sambrisko dcmd = &cmd->cm_frame->dcmd; 1416235014Sambrisko bzero(dcmd->mbox, MFI_MBOX_SIZE); 1417235014Sambrisko dcmd->header.cmd = MFI_CMD_DCMD; 1418235014Sambrisko dcmd->header.flags = MFI_FRAME_DIR_WRITE; 1419235014Sambrisko dcmd->header.timeout = 0; 1420235014Sambrisko dcmd->header.data_len = ld_size; 1421235014Sambrisko dcmd->header.scsi_status = 0; 1422235014Sambrisko dcmd->opcode = MFI_DCMD_LD_MAP_GET_INFO; 1423235014Sambrisko cmd->cm_sg = &dcmd->sgl; 1424235014Sambrisko cmd->cm_total_frame_size = MFI_DCMD_FRAME_SIZE; 1425235014Sambrisko cmd->cm_data = ld_sync; 1426235014Sambrisko cmd->cm_private = ld_sync; 1427235014Sambrisko 1428235014Sambrisko cmd->cm_len = ld_size; 1429235014Sambrisko cmd->cm_complete = mfi_sync_map_complete; 1430235014Sambrisko sc->mfi_map_sync_cm = cmd; 1431235014Sambrisko 1432235014Sambrisko cmd->cm_flags = MFI_CMD_DATAOUT; 1433235014Sambrisko cmd->cm_frame->dcmd.mbox[0] = list->ld_count; 1434235014Sambrisko cmd->cm_frame->dcmd.mbox[1] = MFI_DCMD_MBOX_PEND_FLAG; 1435235014Sambrisko 1436235014Sambrisko if ((error = mfi_mapcmd(sc, cmd)) != 0) { 1437235014Sambrisko device_printf(sc->mfi_dev, "failed to send map sync\n"); 1438235040Sambrisko free(ld_sync, M_MFIBUF); 1439235040Sambrisko sc->mfi_map_sync_cm = NULL; 1440247369Ssmh mfi_release_command(cmd); 1441235040Sambrisko goto out; 1442235014Sambrisko } 1443235014Sambrisko 1444235014Sambriskoout: 1445235014Sambrisko if (list) 1446235014Sambrisko free(list, M_MFIBUF); 1447235014Sambrisko if (cm) 1448235014Sambrisko mfi_release_command(cm); 1449235014Sambrisko} 1450235014Sambrisko 1451235014Sambriskostatic void 1452235014Sambriskomfi_sync_map_complete(struct mfi_command *cm) 1453235014Sambrisko{ 1454235014Sambrisko struct mfi_frame_header *hdr; 1455235014Sambrisko struct mfi_softc *sc; 1456235014Sambrisko int aborted = 0; 1457235014Sambrisko 1458235014Sambrisko sc = cm->cm_sc; 1459235014Sambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1460235014Sambrisko 1461235014Sambrisko hdr = &cm->cm_frame->header; 1462235014Sambrisko 1463235014Sambrisko if (sc->mfi_map_sync_cm == NULL) 1464235014Sambrisko return; 1465235014Sambrisko 1466235014Sambrisko if (sc->cm_map_abort || 1467235014Sambrisko hdr->cmd_status == MFI_STAT_INVALID_STATUS) { 1468235014Sambrisko sc->cm_map_abort = 0; 1469235014Sambrisko aborted = 1; 1470235014Sambrisko } 1471235014Sambrisko 1472235014Sambrisko free(cm->cm_data, M_MFIBUF); 1473247369Ssmh wakeup(&sc->mfi_map_sync_cm); 1474235014Sambrisko sc->mfi_map_sync_cm = NULL; 1475235014Sambrisko mfi_release_command(cm); 1476235014Sambrisko 1477235014Sambrisko /* set it up again so the driver can catch more events */ 1478247369Ssmh if (!aborted) 1479235014Sambrisko mfi_queue_map_sync(sc); 1480235014Sambrisko} 1481235014Sambrisko 1482235014Sambriskostatic void 1483235014Sambriskomfi_queue_map_sync(struct mfi_softc *sc) 1484235014Sambrisko{ 1485235014Sambrisko mtx_assert(&sc->mfi_io_lock, MA_OWNED); 1486235014Sambrisko taskqueue_enqueue(taskqueue_swi, &sc->mfi_map_sync_task); 1487235014Sambrisko} 1488235014Sambrisko 1489235014Sambriskovoid 1490235014Sambriskomfi_handle_map_sync(void *context, int pending) 1491235014Sambrisko{ 1492235014Sambrisko struct mfi_softc *sc; 1493235014Sambrisko 1494235014Sambrisko sc = context; 1495247369Ssmh mtx_lock(&sc->mfi_io_lock); 1496235014Sambrisko mfi_tbolt_sync_map_info(sc); 1497247369Ssmh mtx_unlock(&sc->mfi_io_lock); 1498235014Sambrisko} 1499