From owner-svn-src-all@freebsd.org Tue Nov 29 13:01:33 2016 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 0A2DFC5A952; Tue, 29 Nov 2016 13:01:33 +0000 (UTC) (envelope-from kadesai@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id ACE9B1702; Tue, 29 Nov 2016 13:01:32 +0000 (UTC) (envelope-from kadesai@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id uATD1VLK054714; Tue, 29 Nov 2016 13:01:31 GMT (envelope-from kadesai@FreeBSD.org) Received: (from kadesai@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id uATD1VZ6054711; Tue, 29 Nov 2016 13:01:31 GMT (envelope-from kadesai@FreeBSD.org) Message-Id: <201611291301.uATD1VZ6054711@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kadesai set sender to kadesai@FreeBSD.org using -f From: Kashyap D Desai Date: Tue, 29 Nov 2016 13:01:31 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r309290 - head/sys/dev/mrsas X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 29 Nov 2016 13:01:33 -0000 Author: kadesai Date: Tue Nov 29 13:01:31 2016 New Revision: 309290 URL: https://svnweb.freebsd.org/changeset/base/309290 Log: This patch will add task management support in driver. Below is high level description: If a SCSI IO times out, then before initiating OCR, now the driver will try to send a target reset to the particular target for which the IO is timed out. If that also fails, then the driver will initiate OCR. Submitted by: Sumit Saxena Reviewed by: Kashyap Desai MFC after: 3 days Sponsored by: Broadcom Limited/AVAGO Technologies Modified: head/sys/dev/mrsas/mrsas.c head/sys/dev/mrsas/mrsas.h head/sys/dev/mrsas/mrsas_cam.c Modified: head/sys/dev/mrsas/mrsas.c ============================================================================== --- head/sys/dev/mrsas/mrsas.c Tue Nov 29 12:59:38 2016 (r309289) +++ head/sys/dev/mrsas/mrsas.c Tue Nov 29 13:01:31 2016 (r309290) @@ -110,6 +110,7 @@ int mrsas_issue_polled(struct mrsas_soft int mrsas_reset_ctrl(struct mrsas_softc *sc, u_int8_t reset_reason); int mrsas_wait_for_outstanding(struct mrsas_softc *sc, u_int8_t check_reason); int mrsas_complete_cmd(struct mrsas_softc *sc, u_int32_t MSIxIndex); +int mrsas_reset_targets(struct mrsas_softc *sc); int mrsas_issue_blocked_cmd(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd); @@ -306,28 +307,11 @@ mrsas_enable_intr(struct mrsas_softc *sc static int mrsas_clear_intr(struct mrsas_softc *sc) { - u_int32_t status, fw_status, fw_state; + u_int32_t status; /* Read received interrupt */ status = mrsas_read_reg(sc, offsetof(mrsas_reg_set, outbound_intr_status)); - /* - * If FW state change interrupt is received, write to it again to - * clear - */ - if (status & MRSAS_FW_STATE_CHNG_INTERRUPT) { - fw_status = mrsas_read_reg(sc, offsetof(mrsas_reg_set, - outbound_scratch_pad)); - fw_state = fw_status & MFI_STATE_MASK; - if (fw_state == MFI_STATE_FAULT) { - device_printf(sc->mrsas_dev, "FW is in FAULT state!\n"); - if (sc->ocr_thread_active) - wakeup(&sc->ocr_chan); - } - mrsas_write_reg(sc, offsetof(mrsas_reg_set, outbound_intr_status), status); - mrsas_read_reg(sc, offsetof(mrsas_reg_set, outbound_intr_status)); - return (1); - } /* Not our interrupt, so just return */ if (!(status & MFI_FUSION_ENABLE_INTERRUPT_MASK)) return (0); @@ -882,6 +866,7 @@ mrsas_attach(device_t dev) TAILQ_INIT(&sc->mrsas_mfi_cmd_list_head); mrsas_atomic_set(&sc->fw_outstanding, 0); + mrsas_atomic_set(&sc->target_reset_outstanding, 0); sc->io_cmds_highwater = 0; @@ -1556,7 +1541,10 @@ mrsas_complete_cmd(struct mrsas_softc *s PLD_LOAD_BALANCE_INFO lbinfo; u_int32_t device_id; int threshold_reply_count = 0; - +#if TM_DEBUG + MR_TASK_MANAGE_REQUEST *mr_tm_req; + MPI2_SCSI_TASK_MANAGE_REQUEST *mpi_tm_req; +#endif /* If we have a hardware error, not need to continue */ if (sc->adprecovery == MRSAS_HW_CRITICAL_ERROR) @@ -1583,6 +1571,16 @@ mrsas_complete_cmd(struct mrsas_softc *s extStatus = scsi_io_req->RaidContext.exStatus; switch (scsi_io_req->Function) { + case MPI2_FUNCTION_SCSI_TASK_MGMT: +#if TM_DEBUG + mr_tm_req = (MR_TASK_MANAGE_REQUEST *) cmd_mpt->io_request; + mpi_tm_req = (MPI2_SCSI_TASK_MANAGE_REQUEST *) + &mr_tm_req->TmRequest; + device_printf(sc->mrsas_dev, "TM completion type 0x%X, " + "TaskMID: 0x%X", mpi_tm_req->TaskType, mpi_tm_req->TaskMID); +#endif + wakeup_one((void *)&sc->ocr_chan); + break; case MPI2_FUNCTION_SCSI_IO_REQUEST: /* Fast Path IO. */ device_id = cmd_mpt->ccb_ptr->ccb_h.target_id; lbinfo = &sc->load_balance_info[device_id]; @@ -2585,7 +2583,7 @@ mrsas_alloc_mpt_cmds(struct mrsas_softc memset(cmd, 0, sizeof(struct mrsas_mpt_cmd)); cmd->index = i + 1; cmd->ccb_ptr = NULL; - callout_init(&cmd->cm_callout, 0); + callout_init_mtx(&cmd->cm_callout, &sc->sim_lock, 0); cmd->sync_cmd_idx = (u_int32_t)MRSAS_ULONG_MAX; cmd->sc = sc; cmd->io_request = (MRSAS_RAID_SCSI_IO_REQUEST *) (io_req_base + offset); @@ -2780,6 +2778,7 @@ mrsas_ocr_thread(void *arg) { struct mrsas_softc *sc; u_int32_t fw_status, fw_state; + u_int8_t tm_target_reset_failed = 0; sc = (struct mrsas_softc *)arg; @@ -2802,20 +2801,57 @@ mrsas_ocr_thread(void *arg) fw_status = mrsas_read_reg(sc, offsetof(mrsas_reg_set, outbound_scratch_pad)); fw_state = fw_status & MFI_STATE_MASK; - if (fw_state == MFI_STATE_FAULT || sc->do_timedout_reset) { - device_printf(sc->mrsas_dev, "%s started due to %s!\n", - sc->disableOnlineCtrlReset ? "Kill Adapter" : "OCR", - sc->do_timedout_reset ? "IO Timeout" : - "FW fault detected"); - mtx_lock_spin(&sc->ioctl_lock); - sc->reset_in_progress = 1; - sc->reset_count++; - mtx_unlock_spin(&sc->ioctl_lock); + if (fw_state == MFI_STATE_FAULT || sc->do_timedout_reset || + mrsas_atomic_read(&sc->target_reset_outstanding)) { + + /* First, freeze further IOs to come to the SIM */ mrsas_xpt_freeze(sc); - mrsas_reset_ctrl(sc, sc->do_timedout_reset); - mrsas_xpt_release(sc); - sc->reset_in_progress = 0; - sc->do_timedout_reset = 0; + + /* If this is an IO timeout then go for target reset */ + if (mrsas_atomic_read(&sc->target_reset_outstanding)) { + device_printf(sc->mrsas_dev, "Initiating Target RESET " + "because of SCSI IO timeout!\n"); + + /* Let the remaining IOs to complete */ + msleep(&sc->ocr_chan, &sc->sim_lock, PRIBIO, + "mrsas_reset_targets", 5 * hz); + + /* Try to reset the target device */ + if (mrsas_reset_targets(sc) == FAIL) + tm_target_reset_failed = 1; + } + + /* If this is a DCMD timeout or FW fault, + * then go for controller reset + */ + if (fw_state == MFI_STATE_FAULT || tm_target_reset_failed || + (sc->do_timedout_reset == MFI_DCMD_TIMEOUT_OCR)) { + if (tm_target_reset_failed) + device_printf(sc->mrsas_dev, "Initiaiting OCR because of " + "TM FAILURE!\n"); + else + device_printf(sc->mrsas_dev, "Initiaiting OCR " + "because of %s!\n", sc->do_timedout_reset ? + "DCMD IO Timeout" : "FW fault"); + + mtx_lock_spin(&sc->ioctl_lock); + sc->reset_in_progress = 1; + mtx_unlock_spin(&sc->ioctl_lock); + sc->reset_count++; + + /* Try to reset the controller */ + mrsas_reset_ctrl(sc, sc->do_timedout_reset); + + sc->do_timedout_reset = 0; + sc->reset_in_progress = 0; + tm_target_reset_failed = 0; + mrsas_atomic_set(&sc->target_reset_outstanding, 0); + memset(sc->target_reset_pool, 0, + sizeof(sc->target_reset_pool)); + } + + /* Now allow IOs to come to the SIM */ + mrsas_xpt_release(sc); } } mtx_unlock(&sc->sim_lock); Modified: head/sys/dev/mrsas/mrsas.h ============================================================================== --- head/sys/dev/mrsas/mrsas.h Tue Nov 29 12:59:38 2016 (r309289) +++ head/sys/dev/mrsas/mrsas.h Tue Nov 29 13:01:31 2016 (r309290) @@ -205,7 +205,9 @@ typedef struct _RAID_CONTEXT { #define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD (0x0100) #define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP (0x0004) #define MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) /* SCSI IO */ -#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x06) +#define MPI2_FUNCTION_SCSI_TASK_MGMT (0x01) +#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x03) +#define MPI2_REQ_DESCRIPT_FLAGS_FP_IO (0x06) #define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO (0x00) #define MPI2_SGE_FLAGS_64_BIT_ADDRESSING (0x02) #define MPI2_SCSIIO_CONTROL_WRITE (0x01000000) @@ -314,6 +316,91 @@ typedef union { } MPI2_SCSI_IO_CDB_UNION, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_UNION, Mpi2ScsiIoCdb_t, MPI2_POINTER pMpi2ScsiIoCdb_t; +/**************************************************************************** + * * SCSI Task Management messages + * ****************************************************************************/ + +/*SCSI Task Management Request Message */ +typedef struct _MPI2_SCSI_TASK_MANAGE_REQUEST { + u_int16_t DevHandle; /*0x00 */ + u_int8_t ChainOffset; /*0x02 */ + u_int8_t Function; /*0x03 */ + u_int8_t Reserved1; /*0x04 */ + u_int8_t TaskType; /*0x05 */ + u_int8_t Reserved2; /*0x06 */ + u_int8_t MsgFlags; /*0x07 */ + u_int8_t VP_ID; /*0x08 */ + u_int8_t VF_ID; /*0x09 */ + u_int16_t Reserved3; /*0x0A */ + u_int8_t LUN[8]; /*0x0C */ + u_int32_t Reserved4[7]; /*0x14 */ + u_int16_t TaskMID; /*0x30 */ + u_int16_t Reserved5; /*0x32 */ +} MPI2_SCSI_TASK_MANAGE_REQUEST; + +/*SCSI Task Management Reply Message */ +typedef struct _MPI2_SCSI_TASK_MANAGE_REPLY { + u_int16_t DevHandle; /*0x00 */ + u_int8_t MsgLength; /*0x02 */ + u_int8_t Function; /*0x03 */ + u_int8_t ResponseCode; /*0x04 */ + u_int8_t TaskType; /*0x05 */ + u_int8_t Reserved1; /*0x06 */ + u_int8_t MsgFlags; /*0x07 */ + u_int8_t VP_ID; /*0x08 */ + u_int8_t VF_ID; /*0x09 */ + u_int16_t Reserved2; /*0x0A */ + u_int16_t Reserved3; /*0x0C */ + u_int16_t IOCStatus; /*0x0E */ + u_int32_t IOCLogInfo; /*0x10 */ + u_int32_t TerminationCount; /*0x14 */ + u_int32_t ResponseInfo; /*0x18 */ +} MPI2_SCSI_TASK_MANAGE_REPLY; + +typedef struct _MR_TM_REQUEST { + char request[128]; +} MR_TM_REQUEST; + +typedef struct _MR_TM_REPLY { + char reply[128]; +} MR_TM_REPLY; + +/* SCSI Task Management Request Message */ +typedef struct _MR_TASK_MANAGE_REQUEST { + /*To be type casted to struct MPI2_SCSI_TASK_MANAGE_REQUEST */ + MR_TM_REQUEST TmRequest; + union { + struct { + u_int32_t isTMForLD:1; + u_int32_t isTMForPD:1; + u_int32_t reserved1:30; + u_int32_t reserved2; + } tmReqFlags; + MR_TM_REPLY TMReply; + } uTmReqReply; +} MR_TASK_MANAGE_REQUEST; + +/* TaskType values */ +#define MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK (0x01) +#define MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET (0x02) +#define MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET (0x03) +#define MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05) +#define MPI2_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06) +#define MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK (0x07) +#define MPI2_SCSITASKMGMT_TASKTYPE_CLR_ACA (0x08) +#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_TASK_SET (0x09) +#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT (0x0A) + +/* ResponseCode values */ +#define MPI2_SCSITASKMGMT_RSP_TM_COMPLETE (0x00) +#define MPI2_SCSITASKMGMT_RSP_INVALID_FRAME (0x02) +#define MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED (0x04) +#define MPI2_SCSITASKMGMT_RSP_TM_FAILED (0x05) +#define MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED (0x08) +#define MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN (0x09) +#define MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG (0x0A) +#define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC (0x80) + /* * RAID SCSI IO Request Message Total SGE count will be one less than * _MPI2_SCSI_IO_REQUEST @@ -584,7 +671,7 @@ Mpi2IOCInitRequest_t, MPI2_POINTER pMpi2 #define MAX_RAIDMAP_PHYSICAL_DEVICES (MAX_PHYSICAL_DEVICES) #define MR_DCMD_LD_MAP_GET_INFO 0x0300e101 #define MR_DCMD_SYSTEM_PD_MAP_GET_INFO 0x0200e102 - +#define MR_DCMD_PD_MFI_TASK_MGMT 0x0200e100 #define MRSAS_MAX_PD_CHANNELS 1 #define MRSAS_MAX_LD_CHANNELS 1 @@ -599,7 +686,7 @@ Mpi2IOCInitRequest_t, MPI2_POINTER pMpi2 #define VD_EXT_DEBUG 0 - +#define TM_DEBUG 1 /******************************************************************* * RAID map related structures @@ -659,7 +746,8 @@ typedef struct _MR_LD_RAID { u_int32_t fpWriteAcrossStripe:1; u_int32_t fpReadAcrossStripe:1; u_int32_t fpNonRWCapable:1; - u_int32_t reserved4:7; + u_int32_t tmCapable:1; + u_int32_t reserved4:6; } capability; u_int32_t reserved6; u_int64_t size; @@ -876,7 +964,11 @@ struct IO_REQUEST_INFO { struct MR_PD_CFG_SEQ { u_int16_t seqNum; u_int16_t devHandle; - u_int8_t reserved[4]; + struct { + u_int8_t tmCapable:1; + u_int8_t reserved:7; + } capability; + u_int8_t reserved[3]; } __packed; struct MR_PD_CFG_SEQ_NUM_SYNC { @@ -1396,6 +1488,7 @@ struct mrsas_mpt_cmd { union ccb *ccb_ptr; struct callout cm_callout; struct mrsas_softc *sc; + boolean_t tmCapable; TAILQ_ENTRY(mrsas_mpt_cmd) next; }; @@ -2472,8 +2565,7 @@ struct mrsas_irq_context { enum MEGASAS_OCR_REASON { FW_FAULT_OCR = 0, - SCSIIO_TIMEOUT_OCR = 1, - MFI_DCMD_TIMEOUT_OCR = 2, + MFI_DCMD_TIMEOUT_OCR = 1, }; /* Controller management info added to support Linux Emulator */ @@ -2748,6 +2840,9 @@ struct mrsas_softc { u_int8_t do_timedout_reset; u_int32_t reset_in_progress; u_int32_t reset_count; + mrsas_atomic_t target_reset_outstanding; +#define MRSAS_MAX_TM_TARGETS (MRSAS_MAX_PD + MRSAS_MAX_LD_IDS) + struct mrsas_mpt_cmd *target_reset_pool[MRSAS_MAX_TM_TARGETS]; bus_dma_tag_t jbodmap_tag[2]; bus_dmamap_t jbodmap_dmamap[2]; Modified: head/sys/dev/mrsas/mrsas_cam.c ============================================================================== --- head/sys/dev/mrsas/mrsas_cam.c Tue Nov 29 12:59:38 2016 (r309289) +++ head/sys/dev/mrsas/mrsas_cam.c Tue Nov 29 13:01:31 2016 (r309290) @@ -95,6 +95,11 @@ static void mrsas_freeze_simq(struct mrs static void mrsas_cam_poll(struct cam_sim *sim); static void mrsas_action(struct cam_sim *sim, union ccb *ccb); static void mrsas_scsiio_timeout(void *data); +static int mrsas_track_scsiio(struct mrsas_softc *sc, target_id_t id, u_int32_t bus_id); +static void mrsas_tm_response_code(struct mrsas_softc *sc, + MPI2_SCSI_TASK_MANAGE_REPLY *mpi_reply); +static int mrsas_issue_tm(struct mrsas_softc *sc, + MRSAS_REQUEST_DESCRIPTOR_UNION *req_desc); static void mrsas_data_load_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error); @@ -105,6 +110,10 @@ struct mrsas_mpt_cmd *mrsas_get_mpt_cmd( MRSAS_REQUEST_DESCRIPTOR_UNION * mrsas_get_request_desc(struct mrsas_softc *sc, u_int16_t index); +extern void +mrsas_map_mpt_cmd_status(struct mrsas_mpt_cmd *cmd, u_int8_t status, + u_int8_t extStatus); +extern int mrsas_reset_targets(struct mrsas_softc *sc); extern u_int16_t MR_TargetIdToLdGet(u_int32_t ldTgtId, MR_DRV_RAID_MAP_ALL * map); extern u_int32_t MR_LdBlockSizeGet(u_int32_t ldTgtId, MR_DRV_RAID_MAP_ALL * map, @@ -125,6 +134,9 @@ extern u_int8_t megasas_get_best_arm(PLD_LOAD_BALANCE_INFO lbInfo, u_int8_t arm, u_int64_t block, u_int32_t count); extern int mrsas_complete_cmd(struct mrsas_softc *sc, u_int32_t MSIxIndex); +extern MR_LD_RAID *MR_LdRaidGet(u_int32_t ld, MR_DRV_RAID_MAP_ALL * map); +extern void mrsas_disable_intr(struct mrsas_softc *sc); +extern void mrsas_enable_intr(struct mrsas_softc *sc); /* @@ -386,6 +398,10 @@ mrsas_scsiio_timeout(void *data) { struct mrsas_mpt_cmd *cmd; struct mrsas_softc *sc; + u_int32_t target_id; + + if (!data) + return; cmd = (struct mrsas_mpt_cmd *)data; sc = cmd->sc; @@ -394,6 +410,7 @@ mrsas_scsiio_timeout(void *data) printf("command timeout with NULL ccb\n"); return; } + /* * Below callout is dummy entry so that it will be cancelled from * mrsas_cmd_done(). Now Controller will go to OCR/Kill Adapter based @@ -401,15 +418,25 @@ mrsas_scsiio_timeout(void *data) * context. */ #if (__FreeBSD_version >= 1000510) - callout_reset_sbt(&cmd->cm_callout, SBT_1S * 600, 0, + callout_reset_sbt(&cmd->cm_callout, SBT_1S * 180, 0, mrsas_scsiio_timeout, cmd, 0); #else - callout_reset(&cmd->cm_callout, (600000 * hz) / 1000, + callout_reset(&cmd->cm_callout, (180000 * hz) / 1000, mrsas_scsiio_timeout, cmd); #endif - sc->do_timedout_reset = SCSIIO_TIMEOUT_OCR; - if (sc->ocr_thread_active) - wakeup(&sc->ocr_chan); + + if (cmd->ccb_ptr->cpi.bus_id == 0) + target_id = cmd->ccb_ptr->ccb_h.target_id; + else + target_id = (cmd->ccb_ptr->ccb_h.target_id + (MRSAS_MAX_PD - 1)); + + /* Save the cmd to be processed for TM, if it is not there in the array */ + if (sc->target_reset_pool[target_id] == NULL) { + sc->target_reset_pool[target_id] = cmd; + mrsas_atomic_inc(&sc->target_reset_outstanding); + } + + return; } /* @@ -596,10 +623,10 @@ mrsas_startio(struct mrsas_softc *sc, st * Start timer for IO timeout. Default timeout value is 90 second. */ #if (__FreeBSD_version >= 1000510) - callout_reset_sbt(&cmd->cm_callout, SBT_1S * 600, 0, + callout_reset_sbt(&cmd->cm_callout, SBT_1S * 180, 0, mrsas_scsiio_timeout, cmd, 0); #else - callout_reset(&cmd->cm_callout, (600000 * hz) / 1000, + callout_reset(&cmd->cm_callout, (180000 * hz) / 1000, mrsas_scsiio_timeout, cmd); #endif mrsas_atomic_inc(&sc->fw_outstanding); @@ -788,8 +815,9 @@ mrsas_setup_io(struct mrsas_softc *sc, s struct ccb_scsiio *csio = &(ccb->csio); struct IO_REQUEST_INFO io_info; MR_DRV_RAID_MAP_ALL *map_ptr; + MR_LD_RAID *raid; u_int8_t fp_possible; - u_int32_t start_lba_hi, start_lba_lo, ld_block_size; + u_int32_t start_lba_hi, start_lba_lo, ld_block_size, ld; u_int32_t datalength = 0; start_lba_lo = 0; @@ -868,8 +896,8 @@ mrsas_setup_io(struct mrsas_softc *sc, s map_ptr = sc->ld_drv_map[(sc->map_id & 1)]; ld_block_size = MR_LdBlockSizeGet(device_id, map_ptr, sc); - if ((MR_TargetIdToLdGet(device_id, map_ptr) >= MAX_LOGICAL_DRIVES_EXT) || - (!sc->fast_path_io)) { + ld = MR_TargetIdToLdGet(device_id, map_ptr); + if ((ld >= MAX_LOGICAL_DRIVES_EXT) || (!sc->fast_path_io)) { io_request->RaidContext.regLockFlags = 0; fp_possible = 0; } else { @@ -877,6 +905,10 @@ mrsas_setup_io(struct mrsas_softc *sc, s fp_possible = io_info.fpOkForIo; } + raid = MR_LdRaidGet(ld, map_ptr); + /* Store the TM capability value in cmd */ + cmd->tmCapable = raid->capability.tmCapable; + cmd->request_desc->SCSIIO.MSIxIndex = sc->msix_vectors ? smp_processor_id() % sc->msix_vectors : 0; @@ -886,7 +918,7 @@ mrsas_setup_io(struct mrsas_softc *sc, s start_lba_lo, ld_block_size); io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; cmd->request_desc->SCSIIO.RequestFlags = - (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY << + (MPI2_REQ_DESCRIPT_FLAGS_FP_IO << MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); if (sc->mrsas_gen3_ctrl) { if (io_request->RaidContext.regLockFlags == REGION_TYPE_UNUSED) @@ -948,12 +980,20 @@ mrsas_build_ldio_nonrw(struct mrsas_soft union ccb *ccb) { struct ccb_hdr *ccb_h = &(ccb->ccb_h); - u_int32_t device_id; + u_int32_t device_id, ld; + MR_DRV_RAID_MAP_ALL *map_ptr; + MR_LD_RAID *raid; MRSAS_RAID_SCSI_IO_REQUEST *io_request; io_request = cmd->io_request; device_id = ccb_h->target_id; + map_ptr = sc->ld_drv_map[(sc->map_id & 1)]; + ld = MR_TargetIdToLdGet(device_id, map_ptr); + raid = MR_LdRaidGet(ld, map_ptr); + /* Store the TM capability value in cmd */ + cmd->tmCapable = raid->capability.tmCapable; + /* FW path for LD Non-RW (SCSI management commands) */ io_request->Function = MRSAS_MPI2_FUNCTION_LD_IO_REQUEST; io_request->DevHandle = device_id; @@ -1003,8 +1043,6 @@ mrsas_build_syspdio(struct mrsas_softc * MRSAS_RAID_SCSI_IO_REQUEST *io_request; struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync; - pd_sync = (void *)sc->jbodmap_mem[(sc->pd_seq_map_id - 1) & 1]; - io_request = cmd->io_request; device_id = ccb_h->target_id; local_map_ptr = sc->ld_drv_map[(sc->map_id & 1)]; @@ -1018,6 +1056,8 @@ mrsas_build_syspdio(struct mrsas_softc * if (sc->use_seqnum_jbod_fp && sc->pd_list[device_id].driveType == 0x00) { //printf("Using Drv seq num\n"); + pd_sync = (void *)sc->jbodmap_mem[(sc->pd_seq_map_id - 1) & 1]; + cmd->tmCapable = pd_sync->seq[device_id].capability.tmCapable; io_request->RaidContext.VirtualDiskTgtId = device_id + 255; io_request->RaidContext.configSeqNum = pd_sync->seq[device_id].seqNum; io_request->DevHandle = pd_sync->seq[device_id].devHandle; @@ -1066,7 +1106,7 @@ mrsas_build_syspdio(struct mrsas_softc * io_request->IoFlags |= MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH; cmd->request_desc->SCSIIO.RequestFlags = - (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY << + (MPI2_REQ_DESCRIPT_FLAGS_FP_IO << MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); } @@ -1276,9 +1316,10 @@ mrsas_xpt_release(struct mrsas_softc *sc void mrsas_cmd_done(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd) { - callout_stop(&cmd->cm_callout); mrsas_unmap_request(sc, cmd); + mtx_lock(&sc->sim_lock); + callout_stop(&cmd->cm_callout); xpt_done(cmd->ccb_ptr); cmd->ccb_ptr = NULL; mtx_unlock(&sc->sim_lock); @@ -1376,3 +1417,269 @@ mrsas_bus_scan_sim(struct mrsas_softc *s return (0); } + +/* + * mrsas_track_scsiio: Track IOs for a given target in the mpt_cmd_list + * input: Adapter instance soft state + * Target ID of target + * Bus ID of the target + * + * This function checks for any pending IO in the whole mpt_cmd_list pool + * with the bus_id and target_id passed in arguments. If some IO is found + * that means target reset is not successfully completed. + * + * Returns FAIL if IOs pending to the target device, else return SUCCESS + */ +static int +mrsas_track_scsiio(struct mrsas_softc *sc, target_id_t tgt_id, u_int32_t bus_id) +{ + int i; + struct mrsas_mpt_cmd *mpt_cmd = NULL; + + for (i = 0 ; i < sc->max_fw_cmds; i++) { + mpt_cmd = sc->mpt_cmd_list[i]; + + /* + * Check if the target_id and bus_id is same as the timeout IO + */ + if (mpt_cmd->ccb_ptr) { + /* bus_id = 1 denotes a VD */ + if (bus_id == 1) + tgt_id = (mpt_cmd->ccb_ptr->ccb_h.target_id - (MRSAS_MAX_PD - 1)); + + if (mpt_cmd->ccb_ptr->cpi.bus_id == bus_id && + mpt_cmd->ccb_ptr->ccb_h.target_id == tgt_id) { + device_printf(sc->mrsas_dev, + "IO commands pending to target id %d\n", tgt_id); + return FAIL; + } + } + } + + return SUCCESS; +} + +#if TM_DEBUG +/* + * mrsas_tm_response_code: Prints TM response code received from FW + * input: Adapter instance soft state + * MPI reply returned from firmware + * + * Returns nothing. + */ +static void +mrsas_tm_response_code(struct mrsas_softc *sc, + MPI2_SCSI_TASK_MANAGE_REPLY *mpi_reply) +{ + char *desc; + + switch (mpi_reply->ResponseCode) { + case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE: + desc = "task management request completed"; + break; + case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME: + desc = "invalid frame"; + break; + case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED: + desc = "task management request not supported"; + break; + case MPI2_SCSITASKMGMT_RSP_TM_FAILED: + desc = "task management request failed"; + break; + case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED: + desc = "task management request succeeded"; + break; + case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN: + desc = "invalid lun"; + break; + case 0xA: + desc = "overlapped tag attempted"; + break; + case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC: + desc = "task queued, however not sent to target"; + break; + default: + desc = "unknown"; + break; + } + device_printf(sc->mrsas_dev, "response_code(%01x): %s\n", + mpi_reply->ResponseCode, desc); + device_printf(sc->mrsas_dev, + "TerminationCount/DevHandle/Function/TaskType/IOCStat/IOCLoginfo\n" + "0x%x/0x%x/0x%x/0x%x/0x%x/0x%x\n", + mpi_reply->TerminationCount, mpi_reply->DevHandle, + mpi_reply->Function, mpi_reply->TaskType, + mpi_reply->IOCStatus, mpi_reply->IOCLogInfo); +} +#endif + +/* + * mrsas_issue_tm: Fires the TM command to FW and waits for completion + * input: Adapter instance soft state + * reqest descriptor compiled by mrsas_reset_targets + * + * Returns FAIL if TM command TIMEDOUT from FW else SUCCESS. + */ +static int +mrsas_issue_tm(struct mrsas_softc *sc, + MRSAS_REQUEST_DESCRIPTOR_UNION *req_desc) +{ + int sleep_stat; + + mrsas_fire_cmd(sc, req_desc->addr.u.low, req_desc->addr.u.high); + sleep_stat = msleep(&sc->ocr_chan, &sc->sim_lock, PRIBIO, "tm_sleep", 50*hz); + + if (sleep_stat == EWOULDBLOCK) { + device_printf(sc->mrsas_dev, "tm cmd TIMEDOUT\n"); + return FAIL; + } + + return SUCCESS; +} + +/* + * mrsas_reset_targets : Gathers info to fire a target reset command + * input: Adapter instance soft state + * + * This function compiles data for a target reset command to be fired to the FW + * and then traverse the target_reset_pool to see targets with TIMEDOUT IOs. + * + * Returns SUCCESS or FAIL + */ +int mrsas_reset_targets(struct mrsas_softc *sc) +{ + struct mrsas_mpt_cmd *tm_mpt_cmd = NULL; + struct mrsas_mpt_cmd *tgt_mpt_cmd = NULL; + MR_TASK_MANAGE_REQUEST *mr_request; + MPI2_SCSI_TASK_MANAGE_REQUEST *tm_mpi_request; + MRSAS_REQUEST_DESCRIPTOR_UNION *req_desc; + int retCode = FAIL, count, i, outstanding; + u_int32_t MSIxIndex, bus_id; + target_id_t tgt_id; +#if TM_DEBUG + MPI2_SCSI_TASK_MANAGE_REPLY *mpi_reply; +#endif + + outstanding = mrsas_atomic_read(&sc->fw_outstanding); + + if (!outstanding) { + device_printf(sc->mrsas_dev, "NO IOs pending...\n"); + mrsas_atomic_set(&sc->target_reset_outstanding, 0); + retCode = SUCCESS; + goto return_status; + } else if (sc->adprecovery != MRSAS_HBA_OPERATIONAL) { + device_printf(sc->mrsas_dev, "Controller is not operational\n"); + goto return_status; + } else { + /* Some more error checks will be added in future */ + } + + /* Get an mpt frame and an index to fire the TM cmd */ + tm_mpt_cmd = mrsas_get_mpt_cmd(sc); + if (!tm_mpt_cmd) { + retCode = FAIL; + goto return_status; + } + + req_desc = mrsas_get_request_desc(sc, (tm_mpt_cmd->index) - 1); + if (!req_desc) { + device_printf(sc->mrsas_dev, "Cannot get request_descriptor for tm.\n"); + retCode = FAIL; + goto release_mpt; + } + memset(req_desc, 0, sizeof(MRSAS_REQUEST_DESCRIPTOR_UNION)); + + req_desc->HighPriority.SMID = tm_mpt_cmd->index; + req_desc->HighPriority.RequestFlags = + (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY << + MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); + req_desc->HighPriority.MSIxIndex = 0; + req_desc->HighPriority.LMID = 0; + req_desc->HighPriority.Reserved1 = 0; + tm_mpt_cmd->request_desc = req_desc; + + mr_request = (MR_TASK_MANAGE_REQUEST *) tm_mpt_cmd->io_request; + memset(mr_request, 0, sizeof(MR_TASK_MANAGE_REQUEST)); + + tm_mpi_request = (MPI2_SCSI_TASK_MANAGE_REQUEST *) &mr_request->TmRequest; + tm_mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; + tm_mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; + tm_mpi_request->TaskMID = 0; /* smid task */ + tm_mpi_request->LUN[1] = 0; + + /* Traverse the tm_mpt pool to get valid entries */ + for (i = 0 ; i < MRSAS_MAX_TM_TARGETS; i++) { + if(!sc->target_reset_pool[i]) { + continue; + } else { + tgt_mpt_cmd = sc->target_reset_pool[i]; + } + + tgt_id = i; + + /* See if the target is tm capable or NOT */ + if (!tgt_mpt_cmd->tmCapable) { + device_printf(sc->mrsas_dev, "Task management NOT SUPPORTED for " + "CAM target:%d\n", tgt_id); + + retCode = FAIL; + goto release_mpt; + } + + tm_mpi_request->DevHandle = tgt_mpt_cmd->io_request->DevHandle; + + if (i < (MRSAS_MAX_PD - 1)) { + mr_request->uTmReqReply.tmReqFlags.isTMForPD = 1; + bus_id = 0; + } else { + mr_request->uTmReqReply.tmReqFlags.isTMForLD = 1; + bus_id = 1; + } + + device_printf(sc->mrsas_dev, "TM will be fired for " + "CAM target:%d and bus_id %d\n", tgt_id, bus_id); + + sc->ocr_chan = (void *)&tm_mpt_cmd; + retCode = mrsas_issue_tm(sc, req_desc); + if (retCode == FAIL) + goto release_mpt; + +#if TM_DEBUG + mpi_reply = + (MPI2_SCSI_TASK_MANAGE_REPLY *) &mr_request->uTmReqReply.TMReply; + mrsas_tm_response_code(sc, mpi_reply); +#endif + mrsas_atomic_dec(&sc->target_reset_outstanding); + sc->target_reset_pool[i] = NULL; + + /* Check for pending cmds in the mpt_cmd_pool with the tgt_id */ + mrsas_disable_intr(sc); + /* Wait for 1 second to complete parallel ISR calling same + * mrsas_complete_cmd() + */ + msleep(&sc->ocr_chan, &sc->sim_lock, PRIBIO, "mrsas_reset_wakeup", + 1 * hz); + count = sc->msix_vectors > 0 ? sc->msix_vectors : 1; + mtx_unlock(&sc->sim_lock); + for (MSIxIndex = 0; MSIxIndex < count; MSIxIndex++) + mrsas_complete_cmd(sc, MSIxIndex); + mtx_lock(&sc->sim_lock); + retCode = mrsas_track_scsiio(sc, tgt_id, bus_id); + mrsas_enable_intr(sc); + + if (retCode == FAIL) + goto release_mpt; + } + + device_printf(sc->mrsas_dev, "Number of targets outstanding " + "after reset: %d\n", mrsas_atomic_read(&sc->target_reset_outstanding)); + +release_mpt: + mrsas_release_mpt_cmd(tm_mpt_cmd); +return_status: + device_printf(sc->mrsas_dev, "target reset %s!!\n", + (retCode == SUCCESS) ? "SUCCESS" : "FAIL"); + + return retCode; +} +