162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Driver for Broadcom MPI3 Storage Controllers 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2017-2023 Broadcom Inc. 662306a36Sopenharmony_ci * (mailto: mpi3mr-linuxdrv.pdl@broadcom.com) 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "mpi3mr.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci/* global driver scop variables */ 1362306a36Sopenharmony_ciLIST_HEAD(mrioc_list); 1462306a36Sopenharmony_ciDEFINE_SPINLOCK(mrioc_list_lock); 1562306a36Sopenharmony_cistatic int mrioc_ids; 1662306a36Sopenharmony_cistatic int warn_non_secure_ctlr; 1762306a36Sopenharmony_ciatomic64_t event_counter; 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ciMODULE_AUTHOR(MPI3MR_DRIVER_AUTHOR); 2062306a36Sopenharmony_ciMODULE_DESCRIPTION(MPI3MR_DRIVER_DESC); 2162306a36Sopenharmony_ciMODULE_LICENSE(MPI3MR_DRIVER_LICENSE); 2262306a36Sopenharmony_ciMODULE_VERSION(MPI3MR_DRIVER_VERSION); 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* Module parameters*/ 2562306a36Sopenharmony_ciint prot_mask = -1; 2662306a36Sopenharmony_cimodule_param(prot_mask, int, 0); 2762306a36Sopenharmony_ciMODULE_PARM_DESC(prot_mask, "Host protection capabilities mask, def=0x07"); 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic int prot_guard_mask = 3; 3062306a36Sopenharmony_cimodule_param(prot_guard_mask, int, 0); 3162306a36Sopenharmony_ciMODULE_PARM_DESC(prot_guard_mask, " Host protection guard mask, def=3"); 3262306a36Sopenharmony_cistatic int logging_level; 3362306a36Sopenharmony_cimodule_param(logging_level, int, 0); 3462306a36Sopenharmony_ciMODULE_PARM_DESC(logging_level, 3562306a36Sopenharmony_ci " bits for enabling additional logging info (default=0)"); 3662306a36Sopenharmony_cistatic int max_sgl_entries = MPI3MR_DEFAULT_SGL_ENTRIES; 3762306a36Sopenharmony_cimodule_param(max_sgl_entries, int, 0444); 3862306a36Sopenharmony_ciMODULE_PARM_DESC(max_sgl_entries, 3962306a36Sopenharmony_ci "Preferred max number of SG entries to be used for a single I/O\n" 4062306a36Sopenharmony_ci "The actual value will be determined by the driver\n" 4162306a36Sopenharmony_ci "(Minimum=256, Maximum=2048, default=256)"); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/* Forward declarations*/ 4462306a36Sopenharmony_cistatic void mpi3mr_send_event_ack(struct mpi3mr_ioc *mrioc, u8 event, 4562306a36Sopenharmony_ci struct mpi3mr_drv_cmd *cmdparam, u32 event_ctx); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define MPI3MR_DRIVER_EVENT_TG_QD_REDUCTION (0xFFFF) 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#define MPI3_EVENT_WAIT_FOR_DEVICES_TO_REFRESH (0xFFFE) 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/** 5262306a36Sopenharmony_ci * mpi3mr_host_tag_for_scmd - Get host tag for a scmd 5362306a36Sopenharmony_ci * @mrioc: Adapter instance reference 5462306a36Sopenharmony_ci * @scmd: SCSI command reference 5562306a36Sopenharmony_ci * 5662306a36Sopenharmony_ci * Calculate the host tag based on block tag for a given scmd. 5762306a36Sopenharmony_ci * 5862306a36Sopenharmony_ci * Return: Valid host tag or MPI3MR_HOSTTAG_INVALID. 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_cistatic u16 mpi3mr_host_tag_for_scmd(struct mpi3mr_ioc *mrioc, 6162306a36Sopenharmony_ci struct scsi_cmnd *scmd) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci struct scmd_priv *priv = NULL; 6462306a36Sopenharmony_ci u32 unique_tag; 6562306a36Sopenharmony_ci u16 host_tag, hw_queue; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci unique_tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd)); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci hw_queue = blk_mq_unique_tag_to_hwq(unique_tag); 7062306a36Sopenharmony_ci if (hw_queue >= mrioc->num_op_reply_q) 7162306a36Sopenharmony_ci return MPI3MR_HOSTTAG_INVALID; 7262306a36Sopenharmony_ci host_tag = blk_mq_unique_tag_to_tag(unique_tag); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (WARN_ON(host_tag >= mrioc->max_host_ios)) 7562306a36Sopenharmony_ci return MPI3MR_HOSTTAG_INVALID; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci priv = scsi_cmd_priv(scmd); 7862306a36Sopenharmony_ci /*host_tag 0 is invalid hence incrementing by 1*/ 7962306a36Sopenharmony_ci priv->host_tag = host_tag + 1; 8062306a36Sopenharmony_ci priv->scmd = scmd; 8162306a36Sopenharmony_ci priv->in_lld_scope = 1; 8262306a36Sopenharmony_ci priv->req_q_idx = hw_queue; 8362306a36Sopenharmony_ci priv->meta_chain_idx = -1; 8462306a36Sopenharmony_ci priv->chain_idx = -1; 8562306a36Sopenharmony_ci priv->meta_sg_valid = 0; 8662306a36Sopenharmony_ci return priv->host_tag; 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/** 9062306a36Sopenharmony_ci * mpi3mr_scmd_from_host_tag - Get SCSI command from host tag 9162306a36Sopenharmony_ci * @mrioc: Adapter instance reference 9262306a36Sopenharmony_ci * @host_tag: Host tag 9362306a36Sopenharmony_ci * @qidx: Operational queue index 9462306a36Sopenharmony_ci * 9562306a36Sopenharmony_ci * Identify the block tag from the host tag and queue index and 9662306a36Sopenharmony_ci * retrieve associated scsi command using scsi_host_find_tag(). 9762306a36Sopenharmony_ci * 9862306a36Sopenharmony_ci * Return: SCSI command reference or NULL. 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_cistatic struct scsi_cmnd *mpi3mr_scmd_from_host_tag( 10162306a36Sopenharmony_ci struct mpi3mr_ioc *mrioc, u16 host_tag, u16 qidx) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci struct scsi_cmnd *scmd = NULL; 10462306a36Sopenharmony_ci struct scmd_priv *priv = NULL; 10562306a36Sopenharmony_ci u32 unique_tag = host_tag - 1; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci if (WARN_ON(host_tag > mrioc->max_host_ios)) 10862306a36Sopenharmony_ci goto out; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci unique_tag |= (qidx << BLK_MQ_UNIQUE_TAG_BITS); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci scmd = scsi_host_find_tag(mrioc->shost, unique_tag); 11362306a36Sopenharmony_ci if (scmd) { 11462306a36Sopenharmony_ci priv = scsi_cmd_priv(scmd); 11562306a36Sopenharmony_ci if (!priv->in_lld_scope) 11662306a36Sopenharmony_ci scmd = NULL; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ciout: 11962306a36Sopenharmony_ci return scmd; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci/** 12362306a36Sopenharmony_ci * mpi3mr_clear_scmd_priv - Cleanup SCSI command private date 12462306a36Sopenharmony_ci * @mrioc: Adapter instance reference 12562306a36Sopenharmony_ci * @scmd: SCSI command reference 12662306a36Sopenharmony_ci * 12762306a36Sopenharmony_ci * Invalidate the SCSI command private data to mark the command 12862306a36Sopenharmony_ci * is not in LLD scope anymore. 12962306a36Sopenharmony_ci * 13062306a36Sopenharmony_ci * Return: Nothing. 13162306a36Sopenharmony_ci */ 13262306a36Sopenharmony_cistatic void mpi3mr_clear_scmd_priv(struct mpi3mr_ioc *mrioc, 13362306a36Sopenharmony_ci struct scsi_cmnd *scmd) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci struct scmd_priv *priv = NULL; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci priv = scsi_cmd_priv(scmd); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if (WARN_ON(priv->in_lld_scope == 0)) 14062306a36Sopenharmony_ci return; 14162306a36Sopenharmony_ci priv->host_tag = MPI3MR_HOSTTAG_INVALID; 14262306a36Sopenharmony_ci priv->req_q_idx = 0xFFFF; 14362306a36Sopenharmony_ci priv->scmd = NULL; 14462306a36Sopenharmony_ci priv->in_lld_scope = 0; 14562306a36Sopenharmony_ci priv->meta_sg_valid = 0; 14662306a36Sopenharmony_ci if (priv->chain_idx >= 0) { 14762306a36Sopenharmony_ci clear_bit(priv->chain_idx, mrioc->chain_bitmap); 14862306a36Sopenharmony_ci priv->chain_idx = -1; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci if (priv->meta_chain_idx >= 0) { 15162306a36Sopenharmony_ci clear_bit(priv->meta_chain_idx, mrioc->chain_bitmap); 15262306a36Sopenharmony_ci priv->meta_chain_idx = -1; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic void mpi3mr_dev_rmhs_send_tm(struct mpi3mr_ioc *mrioc, u16 handle, 15762306a36Sopenharmony_ci struct mpi3mr_drv_cmd *cmdparam, u8 iou_rc); 15862306a36Sopenharmony_cistatic void mpi3mr_fwevt_worker(struct work_struct *work); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci/** 16162306a36Sopenharmony_ci * mpi3mr_fwevt_free - firmware event memory dealloctor 16262306a36Sopenharmony_ci * @r: k reference pointer of the firmware event 16362306a36Sopenharmony_ci * 16462306a36Sopenharmony_ci * Free firmware event memory when no reference. 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_cistatic void mpi3mr_fwevt_free(struct kref *r) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci kfree(container_of(r, struct mpi3mr_fwevt, ref_count)); 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci/** 17262306a36Sopenharmony_ci * mpi3mr_fwevt_get - k reference incrementor 17362306a36Sopenharmony_ci * @fwevt: Firmware event reference 17462306a36Sopenharmony_ci * 17562306a36Sopenharmony_ci * Increment firmware event reference count. 17662306a36Sopenharmony_ci */ 17762306a36Sopenharmony_cistatic void mpi3mr_fwevt_get(struct mpi3mr_fwevt *fwevt) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci kref_get(&fwevt->ref_count); 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci/** 18362306a36Sopenharmony_ci * mpi3mr_fwevt_put - k reference decrementor 18462306a36Sopenharmony_ci * @fwevt: Firmware event reference 18562306a36Sopenharmony_ci * 18662306a36Sopenharmony_ci * decrement firmware event reference count. 18762306a36Sopenharmony_ci */ 18862306a36Sopenharmony_cistatic void mpi3mr_fwevt_put(struct mpi3mr_fwevt *fwevt) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci kref_put(&fwevt->ref_count, mpi3mr_fwevt_free); 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci/** 19462306a36Sopenharmony_ci * mpi3mr_alloc_fwevt - Allocate firmware event 19562306a36Sopenharmony_ci * @len: length of firmware event data to allocate 19662306a36Sopenharmony_ci * 19762306a36Sopenharmony_ci * Allocate firmware event with required length and initialize 19862306a36Sopenharmony_ci * the reference counter. 19962306a36Sopenharmony_ci * 20062306a36Sopenharmony_ci * Return: firmware event reference. 20162306a36Sopenharmony_ci */ 20262306a36Sopenharmony_cistatic struct mpi3mr_fwevt *mpi3mr_alloc_fwevt(int len) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci struct mpi3mr_fwevt *fwevt; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci fwevt = kzalloc(sizeof(*fwevt) + len, GFP_ATOMIC); 20762306a36Sopenharmony_ci if (!fwevt) 20862306a36Sopenharmony_ci return NULL; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci kref_init(&fwevt->ref_count); 21162306a36Sopenharmony_ci return fwevt; 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci/** 21562306a36Sopenharmony_ci * mpi3mr_fwevt_add_to_list - Add firmware event to the list 21662306a36Sopenharmony_ci * @mrioc: Adapter instance reference 21762306a36Sopenharmony_ci * @fwevt: Firmware event reference 21862306a36Sopenharmony_ci * 21962306a36Sopenharmony_ci * Add the given firmware event to the firmware event list. 22062306a36Sopenharmony_ci * 22162306a36Sopenharmony_ci * Return: Nothing. 22262306a36Sopenharmony_ci */ 22362306a36Sopenharmony_cistatic void mpi3mr_fwevt_add_to_list(struct mpi3mr_ioc *mrioc, 22462306a36Sopenharmony_ci struct mpi3mr_fwevt *fwevt) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci unsigned long flags; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (!mrioc->fwevt_worker_thread) 22962306a36Sopenharmony_ci return; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci spin_lock_irqsave(&mrioc->fwevt_lock, flags); 23262306a36Sopenharmony_ci /* get fwevt reference count while adding it to fwevt_list */ 23362306a36Sopenharmony_ci mpi3mr_fwevt_get(fwevt); 23462306a36Sopenharmony_ci INIT_LIST_HEAD(&fwevt->list); 23562306a36Sopenharmony_ci list_add_tail(&fwevt->list, &mrioc->fwevt_list); 23662306a36Sopenharmony_ci INIT_WORK(&fwevt->work, mpi3mr_fwevt_worker); 23762306a36Sopenharmony_ci /* get fwevt reference count while enqueueing it to worker queue */ 23862306a36Sopenharmony_ci mpi3mr_fwevt_get(fwevt); 23962306a36Sopenharmony_ci queue_work(mrioc->fwevt_worker_thread, &fwevt->work); 24062306a36Sopenharmony_ci spin_unlock_irqrestore(&mrioc->fwevt_lock, flags); 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci/** 24462306a36Sopenharmony_ci * mpi3mr_fwevt_del_from_list - Delete firmware event from list 24562306a36Sopenharmony_ci * @mrioc: Adapter instance reference 24662306a36Sopenharmony_ci * @fwevt: Firmware event reference 24762306a36Sopenharmony_ci * 24862306a36Sopenharmony_ci * Delete the given firmware event from the firmware event list. 24962306a36Sopenharmony_ci * 25062306a36Sopenharmony_ci * Return: Nothing. 25162306a36Sopenharmony_ci */ 25262306a36Sopenharmony_cistatic void mpi3mr_fwevt_del_from_list(struct mpi3mr_ioc *mrioc, 25362306a36Sopenharmony_ci struct mpi3mr_fwevt *fwevt) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci unsigned long flags; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci spin_lock_irqsave(&mrioc->fwevt_lock, flags); 25862306a36Sopenharmony_ci if (!list_empty(&fwevt->list)) { 25962306a36Sopenharmony_ci list_del_init(&fwevt->list); 26062306a36Sopenharmony_ci /* 26162306a36Sopenharmony_ci * Put fwevt reference count after 26262306a36Sopenharmony_ci * removing it from fwevt_list 26362306a36Sopenharmony_ci */ 26462306a36Sopenharmony_ci mpi3mr_fwevt_put(fwevt); 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci spin_unlock_irqrestore(&mrioc->fwevt_lock, flags); 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci/** 27062306a36Sopenharmony_ci * mpi3mr_dequeue_fwevt - Dequeue firmware event from the list 27162306a36Sopenharmony_ci * @mrioc: Adapter instance reference 27262306a36Sopenharmony_ci * 27362306a36Sopenharmony_ci * Dequeue a firmware event from the firmware event list. 27462306a36Sopenharmony_ci * 27562306a36Sopenharmony_ci * Return: firmware event. 27662306a36Sopenharmony_ci */ 27762306a36Sopenharmony_cistatic struct mpi3mr_fwevt *mpi3mr_dequeue_fwevt( 27862306a36Sopenharmony_ci struct mpi3mr_ioc *mrioc) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci unsigned long flags; 28162306a36Sopenharmony_ci struct mpi3mr_fwevt *fwevt = NULL; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci spin_lock_irqsave(&mrioc->fwevt_lock, flags); 28462306a36Sopenharmony_ci if (!list_empty(&mrioc->fwevt_list)) { 28562306a36Sopenharmony_ci fwevt = list_first_entry(&mrioc->fwevt_list, 28662306a36Sopenharmony_ci struct mpi3mr_fwevt, list); 28762306a36Sopenharmony_ci list_del_init(&fwevt->list); 28862306a36Sopenharmony_ci /* 28962306a36Sopenharmony_ci * Put fwevt reference count after 29062306a36Sopenharmony_ci * removing it from fwevt_list 29162306a36Sopenharmony_ci */ 29262306a36Sopenharmony_ci mpi3mr_fwevt_put(fwevt); 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci spin_unlock_irqrestore(&mrioc->fwevt_lock, flags); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci return fwevt; 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci/** 30062306a36Sopenharmony_ci * mpi3mr_cancel_work - cancel firmware event 30162306a36Sopenharmony_ci * @fwevt: fwevt object which needs to be canceled 30262306a36Sopenharmony_ci * 30362306a36Sopenharmony_ci * Return: Nothing. 30462306a36Sopenharmony_ci */ 30562306a36Sopenharmony_cistatic void mpi3mr_cancel_work(struct mpi3mr_fwevt *fwevt) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci /* 30862306a36Sopenharmony_ci * Wait on the fwevt to complete. If this returns 1, then 30962306a36Sopenharmony_ci * the event was never executed. 31062306a36Sopenharmony_ci * 31162306a36Sopenharmony_ci * If it did execute, we wait for it to finish, and the put will 31262306a36Sopenharmony_ci * happen from mpi3mr_process_fwevt() 31362306a36Sopenharmony_ci */ 31462306a36Sopenharmony_ci if (cancel_work_sync(&fwevt->work)) { 31562306a36Sopenharmony_ci /* 31662306a36Sopenharmony_ci * Put fwevt reference count after 31762306a36Sopenharmony_ci * dequeuing it from worker queue 31862306a36Sopenharmony_ci */ 31962306a36Sopenharmony_ci mpi3mr_fwevt_put(fwevt); 32062306a36Sopenharmony_ci /* 32162306a36Sopenharmony_ci * Put fwevt reference count to neutralize 32262306a36Sopenharmony_ci * kref_init increment 32362306a36Sopenharmony_ci */ 32462306a36Sopenharmony_ci mpi3mr_fwevt_put(fwevt); 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci/** 32962306a36Sopenharmony_ci * mpi3mr_cleanup_fwevt_list - Cleanup firmware event list 33062306a36Sopenharmony_ci * @mrioc: Adapter instance reference 33162306a36Sopenharmony_ci * 33262306a36Sopenharmony_ci * Flush all pending firmware events from the firmware event 33362306a36Sopenharmony_ci * list. 33462306a36Sopenharmony_ci * 33562306a36Sopenharmony_ci * Return: Nothing. 33662306a36Sopenharmony_ci */ 33762306a36Sopenharmony_civoid mpi3mr_cleanup_fwevt_list(struct mpi3mr_ioc *mrioc) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci struct mpi3mr_fwevt *fwevt = NULL; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if ((list_empty(&mrioc->fwevt_list) && !mrioc->current_event) || 34262306a36Sopenharmony_ci !mrioc->fwevt_worker_thread) 34362306a36Sopenharmony_ci return; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci while ((fwevt = mpi3mr_dequeue_fwevt(mrioc))) 34662306a36Sopenharmony_ci mpi3mr_cancel_work(fwevt); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if (mrioc->current_event) { 34962306a36Sopenharmony_ci fwevt = mrioc->current_event; 35062306a36Sopenharmony_ci /* 35162306a36Sopenharmony_ci * Don't call cancel_work_sync() API for the 35262306a36Sopenharmony_ci * fwevt work if the controller reset is 35362306a36Sopenharmony_ci * get called as part of processing the 35462306a36Sopenharmony_ci * same fwevt work (or) when worker thread is 35562306a36Sopenharmony_ci * waiting for device add/remove APIs to complete. 35662306a36Sopenharmony_ci * Otherwise we will see deadlock. 35762306a36Sopenharmony_ci */ 35862306a36Sopenharmony_ci if (current_work() == &fwevt->work || fwevt->pending_at_sml) { 35962306a36Sopenharmony_ci fwevt->discard = 1; 36062306a36Sopenharmony_ci return; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci mpi3mr_cancel_work(fwevt); 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci/** 36862306a36Sopenharmony_ci * mpi3mr_queue_qd_reduction_event - Queue TG QD reduction event 36962306a36Sopenharmony_ci * @mrioc: Adapter instance reference 37062306a36Sopenharmony_ci * @tg: Throttle group information pointer 37162306a36Sopenharmony_ci * 37262306a36Sopenharmony_ci * Accessor to queue on synthetically generated driver event to 37362306a36Sopenharmony_ci * the event worker thread, the driver event will be used to 37462306a36Sopenharmony_ci * reduce the QD of all VDs in the TG from the worker thread. 37562306a36Sopenharmony_ci * 37662306a36Sopenharmony_ci * Return: None. 37762306a36Sopenharmony_ci */ 37862306a36Sopenharmony_cistatic void mpi3mr_queue_qd_reduction_event(struct mpi3mr_ioc *mrioc, 37962306a36Sopenharmony_ci struct mpi3mr_throttle_group_info *tg) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci struct mpi3mr_fwevt *fwevt; 38262306a36Sopenharmony_ci u16 sz = sizeof(struct mpi3mr_throttle_group_info *); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci /* 38562306a36Sopenharmony_ci * If the QD reduction event is already queued due to throttle and if 38662306a36Sopenharmony_ci * the QD is not restored through device info change event 38762306a36Sopenharmony_ci * then dont queue further reduction events 38862306a36Sopenharmony_ci */ 38962306a36Sopenharmony_ci if (tg->fw_qd != tg->modified_qd) 39062306a36Sopenharmony_ci return; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci fwevt = mpi3mr_alloc_fwevt(sz); 39362306a36Sopenharmony_ci if (!fwevt) { 39462306a36Sopenharmony_ci ioc_warn(mrioc, "failed to queue TG QD reduction event\n"); 39562306a36Sopenharmony_ci return; 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci *(struct mpi3mr_throttle_group_info **)fwevt->event_data = tg; 39862306a36Sopenharmony_ci fwevt->mrioc = mrioc; 39962306a36Sopenharmony_ci fwevt->event_id = MPI3MR_DRIVER_EVENT_TG_QD_REDUCTION; 40062306a36Sopenharmony_ci fwevt->send_ack = 0; 40162306a36Sopenharmony_ci fwevt->process_evt = 1; 40262306a36Sopenharmony_ci fwevt->evt_ctx = 0; 40362306a36Sopenharmony_ci fwevt->event_data_size = sz; 40462306a36Sopenharmony_ci tg->modified_qd = max_t(u16, (tg->fw_qd * tg->qd_reduction) / 10, 8); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci dprint_event_bh(mrioc, "qd reduction event queued for tg_id(%d)\n", 40762306a36Sopenharmony_ci tg->id); 40862306a36Sopenharmony_ci mpi3mr_fwevt_add_to_list(mrioc, fwevt); 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci/** 41262306a36Sopenharmony_ci * mpi3mr_invalidate_devhandles -Invalidate device handles 41362306a36Sopenharmony_ci * @mrioc: Adapter instance reference 41462306a36Sopenharmony_ci * 41562306a36Sopenharmony_ci * Invalidate the device handles in the target device structures 41662306a36Sopenharmony_ci * . Called post reset prior to reinitializing the controller. 41762306a36Sopenharmony_ci * 41862306a36Sopenharmony_ci * Return: Nothing. 41962306a36Sopenharmony_ci */ 42062306a36Sopenharmony_civoid mpi3mr_invalidate_devhandles(struct mpi3mr_ioc *mrioc) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgtdev; 42362306a36Sopenharmony_ci struct mpi3mr_stgt_priv_data *tgt_priv; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list) { 42662306a36Sopenharmony_ci tgtdev->dev_handle = MPI3MR_INVALID_DEV_HANDLE; 42762306a36Sopenharmony_ci if (tgtdev->starget && tgtdev->starget->hostdata) { 42862306a36Sopenharmony_ci tgt_priv = tgtdev->starget->hostdata; 42962306a36Sopenharmony_ci tgt_priv->dev_handle = MPI3MR_INVALID_DEV_HANDLE; 43062306a36Sopenharmony_ci tgt_priv->io_throttle_enabled = 0; 43162306a36Sopenharmony_ci tgt_priv->io_divert = 0; 43262306a36Sopenharmony_ci tgt_priv->throttle_group = NULL; 43362306a36Sopenharmony_ci tgt_priv->wslen = 0; 43462306a36Sopenharmony_ci if (tgtdev->host_exposed) 43562306a36Sopenharmony_ci atomic_set(&tgt_priv->block_io, 1); 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci/** 44162306a36Sopenharmony_ci * mpi3mr_print_scmd - print individual SCSI command 44262306a36Sopenharmony_ci * @rq: Block request 44362306a36Sopenharmony_ci * @data: Adapter instance reference 44462306a36Sopenharmony_ci * 44562306a36Sopenharmony_ci * Print the SCSI command details if it is in LLD scope. 44662306a36Sopenharmony_ci * 44762306a36Sopenharmony_ci * Return: true always. 44862306a36Sopenharmony_ci */ 44962306a36Sopenharmony_cistatic bool mpi3mr_print_scmd(struct request *rq, void *data) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci struct mpi3mr_ioc *mrioc = (struct mpi3mr_ioc *)data; 45262306a36Sopenharmony_ci struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq); 45362306a36Sopenharmony_ci struct scmd_priv *priv = NULL; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci if (scmd) { 45662306a36Sopenharmony_ci priv = scsi_cmd_priv(scmd); 45762306a36Sopenharmony_ci if (!priv->in_lld_scope) 45862306a36Sopenharmony_ci goto out; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci ioc_info(mrioc, "%s :Host Tag = %d, qid = %d\n", 46162306a36Sopenharmony_ci __func__, priv->host_tag, priv->req_q_idx + 1); 46262306a36Sopenharmony_ci scsi_print_command(scmd); 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ciout: 46662306a36Sopenharmony_ci return(true); 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci/** 47062306a36Sopenharmony_ci * mpi3mr_flush_scmd - Flush individual SCSI command 47162306a36Sopenharmony_ci * @rq: Block request 47262306a36Sopenharmony_ci * @data: Adapter instance reference 47362306a36Sopenharmony_ci * 47462306a36Sopenharmony_ci * Return the SCSI command to the upper layers if it is in LLD 47562306a36Sopenharmony_ci * scope. 47662306a36Sopenharmony_ci * 47762306a36Sopenharmony_ci * Return: true always. 47862306a36Sopenharmony_ci */ 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic bool mpi3mr_flush_scmd(struct request *rq, void *data) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci struct mpi3mr_ioc *mrioc = (struct mpi3mr_ioc *)data; 48362306a36Sopenharmony_ci struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq); 48462306a36Sopenharmony_ci struct scmd_priv *priv = NULL; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci if (scmd) { 48762306a36Sopenharmony_ci priv = scsi_cmd_priv(scmd); 48862306a36Sopenharmony_ci if (!priv->in_lld_scope) 48962306a36Sopenharmony_ci goto out; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci if (priv->meta_sg_valid) 49262306a36Sopenharmony_ci dma_unmap_sg(&mrioc->pdev->dev, scsi_prot_sglist(scmd), 49362306a36Sopenharmony_ci scsi_prot_sg_count(scmd), scmd->sc_data_direction); 49462306a36Sopenharmony_ci mpi3mr_clear_scmd_priv(mrioc, scmd); 49562306a36Sopenharmony_ci scsi_dma_unmap(scmd); 49662306a36Sopenharmony_ci scmd->result = DID_RESET << 16; 49762306a36Sopenharmony_ci scsi_print_command(scmd); 49862306a36Sopenharmony_ci scsi_done(scmd); 49962306a36Sopenharmony_ci mrioc->flush_io_count++; 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ciout: 50362306a36Sopenharmony_ci return(true); 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci/** 50762306a36Sopenharmony_ci * mpi3mr_count_dev_pending - Count commands pending for a lun 50862306a36Sopenharmony_ci * @rq: Block request 50962306a36Sopenharmony_ci * @data: SCSI device reference 51062306a36Sopenharmony_ci * 51162306a36Sopenharmony_ci * This is an iterator function called for each SCSI command in 51262306a36Sopenharmony_ci * a host and if the command is pending in the LLD for the 51362306a36Sopenharmony_ci * specific device(lun) then device specific pending I/O counter 51462306a36Sopenharmony_ci * is updated in the device structure. 51562306a36Sopenharmony_ci * 51662306a36Sopenharmony_ci * Return: true always. 51762306a36Sopenharmony_ci */ 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_cistatic bool mpi3mr_count_dev_pending(struct request *rq, void *data) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci struct scsi_device *sdev = (struct scsi_device *)data; 52262306a36Sopenharmony_ci struct mpi3mr_sdev_priv_data *sdev_priv_data = sdev->hostdata; 52362306a36Sopenharmony_ci struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq); 52462306a36Sopenharmony_ci struct scmd_priv *priv; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci if (scmd) { 52762306a36Sopenharmony_ci priv = scsi_cmd_priv(scmd); 52862306a36Sopenharmony_ci if (!priv->in_lld_scope) 52962306a36Sopenharmony_ci goto out; 53062306a36Sopenharmony_ci if (scmd->device == sdev) 53162306a36Sopenharmony_ci sdev_priv_data->pend_count++; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ciout: 53562306a36Sopenharmony_ci return true; 53662306a36Sopenharmony_ci} 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci/** 53962306a36Sopenharmony_ci * mpi3mr_count_tgt_pending - Count commands pending for target 54062306a36Sopenharmony_ci * @rq: Block request 54162306a36Sopenharmony_ci * @data: SCSI target reference 54262306a36Sopenharmony_ci * 54362306a36Sopenharmony_ci * This is an iterator function called for each SCSI command in 54462306a36Sopenharmony_ci * a host and if the command is pending in the LLD for the 54562306a36Sopenharmony_ci * specific target then target specific pending I/O counter is 54662306a36Sopenharmony_ci * updated in the target structure. 54762306a36Sopenharmony_ci * 54862306a36Sopenharmony_ci * Return: true always. 54962306a36Sopenharmony_ci */ 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_cistatic bool mpi3mr_count_tgt_pending(struct request *rq, void *data) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci struct scsi_target *starget = (struct scsi_target *)data; 55462306a36Sopenharmony_ci struct mpi3mr_stgt_priv_data *stgt_priv_data = starget->hostdata; 55562306a36Sopenharmony_ci struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq); 55662306a36Sopenharmony_ci struct scmd_priv *priv; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci if (scmd) { 55962306a36Sopenharmony_ci priv = scsi_cmd_priv(scmd); 56062306a36Sopenharmony_ci if (!priv->in_lld_scope) 56162306a36Sopenharmony_ci goto out; 56262306a36Sopenharmony_ci if (scmd->device && (scsi_target(scmd->device) == starget)) 56362306a36Sopenharmony_ci stgt_priv_data->pend_count++; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ciout: 56762306a36Sopenharmony_ci return true; 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci/** 57162306a36Sopenharmony_ci * mpi3mr_flush_host_io - Flush host I/Os 57262306a36Sopenharmony_ci * @mrioc: Adapter instance reference 57362306a36Sopenharmony_ci * 57462306a36Sopenharmony_ci * Flush all of the pending I/Os by calling 57562306a36Sopenharmony_ci * blk_mq_tagset_busy_iter() for each possible tag. This is 57662306a36Sopenharmony_ci * executed post controller reset 57762306a36Sopenharmony_ci * 57862306a36Sopenharmony_ci * Return: Nothing. 57962306a36Sopenharmony_ci */ 58062306a36Sopenharmony_civoid mpi3mr_flush_host_io(struct mpi3mr_ioc *mrioc) 58162306a36Sopenharmony_ci{ 58262306a36Sopenharmony_ci struct Scsi_Host *shost = mrioc->shost; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci mrioc->flush_io_count = 0; 58562306a36Sopenharmony_ci ioc_info(mrioc, "%s :Flushing Host I/O cmds post reset\n", __func__); 58662306a36Sopenharmony_ci blk_mq_tagset_busy_iter(&shost->tag_set, 58762306a36Sopenharmony_ci mpi3mr_flush_scmd, (void *)mrioc); 58862306a36Sopenharmony_ci ioc_info(mrioc, "%s :Flushed %d Host I/O cmds\n", __func__, 58962306a36Sopenharmony_ci mrioc->flush_io_count); 59062306a36Sopenharmony_ci} 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci/** 59362306a36Sopenharmony_ci * mpi3mr_flush_cmds_for_unrecovered_controller - Flush all pending cmds 59462306a36Sopenharmony_ci * @mrioc: Adapter instance reference 59562306a36Sopenharmony_ci * 59662306a36Sopenharmony_ci * This function waits for currently running IO poll threads to 59762306a36Sopenharmony_ci * exit and then flushes all host I/Os and any internal pending 59862306a36Sopenharmony_ci * cmds. This is executed after controller is marked as 59962306a36Sopenharmony_ci * unrecoverable. 60062306a36Sopenharmony_ci * 60162306a36Sopenharmony_ci * Return: Nothing. 60262306a36Sopenharmony_ci */ 60362306a36Sopenharmony_civoid mpi3mr_flush_cmds_for_unrecovered_controller(struct mpi3mr_ioc *mrioc) 60462306a36Sopenharmony_ci{ 60562306a36Sopenharmony_ci struct Scsi_Host *shost = mrioc->shost; 60662306a36Sopenharmony_ci int i; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci if (!mrioc->unrecoverable) 60962306a36Sopenharmony_ci return; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci if (mrioc->op_reply_qinfo) { 61262306a36Sopenharmony_ci for (i = 0; i < mrioc->num_queues; i++) { 61362306a36Sopenharmony_ci while (atomic_read(&mrioc->op_reply_qinfo[i].in_use)) 61462306a36Sopenharmony_ci udelay(500); 61562306a36Sopenharmony_ci atomic_set(&mrioc->op_reply_qinfo[i].pend_ios, 0); 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci mrioc->flush_io_count = 0; 61962306a36Sopenharmony_ci blk_mq_tagset_busy_iter(&shost->tag_set, 62062306a36Sopenharmony_ci mpi3mr_flush_scmd, (void *)mrioc); 62162306a36Sopenharmony_ci mpi3mr_flush_delayed_cmd_lists(mrioc); 62262306a36Sopenharmony_ci mpi3mr_flush_drv_cmds(mrioc); 62362306a36Sopenharmony_ci} 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci/** 62662306a36Sopenharmony_ci * mpi3mr_alloc_tgtdev - target device allocator 62762306a36Sopenharmony_ci * 62862306a36Sopenharmony_ci * Allocate target device instance and initialize the reference 62962306a36Sopenharmony_ci * count 63062306a36Sopenharmony_ci * 63162306a36Sopenharmony_ci * Return: target device instance. 63262306a36Sopenharmony_ci */ 63362306a36Sopenharmony_cistatic struct mpi3mr_tgt_dev *mpi3mr_alloc_tgtdev(void) 63462306a36Sopenharmony_ci{ 63562306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgtdev; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci tgtdev = kzalloc(sizeof(*tgtdev), GFP_ATOMIC); 63862306a36Sopenharmony_ci if (!tgtdev) 63962306a36Sopenharmony_ci return NULL; 64062306a36Sopenharmony_ci kref_init(&tgtdev->ref_count); 64162306a36Sopenharmony_ci return tgtdev; 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci/** 64562306a36Sopenharmony_ci * mpi3mr_tgtdev_add_to_list -Add tgtdevice to the list 64662306a36Sopenharmony_ci * @mrioc: Adapter instance reference 64762306a36Sopenharmony_ci * @tgtdev: Target device 64862306a36Sopenharmony_ci * 64962306a36Sopenharmony_ci * Add the target device to the target device list 65062306a36Sopenharmony_ci * 65162306a36Sopenharmony_ci * Return: Nothing. 65262306a36Sopenharmony_ci */ 65362306a36Sopenharmony_cistatic void mpi3mr_tgtdev_add_to_list(struct mpi3mr_ioc *mrioc, 65462306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgtdev) 65562306a36Sopenharmony_ci{ 65662306a36Sopenharmony_ci unsigned long flags; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci spin_lock_irqsave(&mrioc->tgtdev_lock, flags); 65962306a36Sopenharmony_ci mpi3mr_tgtdev_get(tgtdev); 66062306a36Sopenharmony_ci INIT_LIST_HEAD(&tgtdev->list); 66162306a36Sopenharmony_ci list_add_tail(&tgtdev->list, &mrioc->tgtdev_list); 66262306a36Sopenharmony_ci tgtdev->state = MPI3MR_DEV_CREATED; 66362306a36Sopenharmony_ci spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags); 66462306a36Sopenharmony_ci} 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci/** 66762306a36Sopenharmony_ci * mpi3mr_tgtdev_del_from_list -Delete tgtdevice from the list 66862306a36Sopenharmony_ci * @mrioc: Adapter instance reference 66962306a36Sopenharmony_ci * @tgtdev: Target device 67062306a36Sopenharmony_ci * @must_delete: Must delete the target device from the list irrespective 67162306a36Sopenharmony_ci * of the device state. 67262306a36Sopenharmony_ci * 67362306a36Sopenharmony_ci * Remove the target device from the target device list 67462306a36Sopenharmony_ci * 67562306a36Sopenharmony_ci * Return: Nothing. 67662306a36Sopenharmony_ci */ 67762306a36Sopenharmony_cistatic void mpi3mr_tgtdev_del_from_list(struct mpi3mr_ioc *mrioc, 67862306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgtdev, bool must_delete) 67962306a36Sopenharmony_ci{ 68062306a36Sopenharmony_ci unsigned long flags; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci spin_lock_irqsave(&mrioc->tgtdev_lock, flags); 68362306a36Sopenharmony_ci if ((tgtdev->state == MPI3MR_DEV_REMOVE_HS_STARTED) || (must_delete == true)) { 68462306a36Sopenharmony_ci if (!list_empty(&tgtdev->list)) { 68562306a36Sopenharmony_ci list_del_init(&tgtdev->list); 68662306a36Sopenharmony_ci tgtdev->state = MPI3MR_DEV_DELETED; 68762306a36Sopenharmony_ci mpi3mr_tgtdev_put(tgtdev); 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags); 69162306a36Sopenharmony_ci} 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci/** 69462306a36Sopenharmony_ci * __mpi3mr_get_tgtdev_by_handle -Get tgtdev from device handle 69562306a36Sopenharmony_ci * @mrioc: Adapter instance reference 69662306a36Sopenharmony_ci * @handle: Device handle 69762306a36Sopenharmony_ci * 69862306a36Sopenharmony_ci * Accessor to retrieve target device from the device handle. 69962306a36Sopenharmony_ci * Non Lock version 70062306a36Sopenharmony_ci * 70162306a36Sopenharmony_ci * Return: Target device reference. 70262306a36Sopenharmony_ci */ 70362306a36Sopenharmony_cistatic struct mpi3mr_tgt_dev *__mpi3mr_get_tgtdev_by_handle( 70462306a36Sopenharmony_ci struct mpi3mr_ioc *mrioc, u16 handle) 70562306a36Sopenharmony_ci{ 70662306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgtdev; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci assert_spin_locked(&mrioc->tgtdev_lock); 70962306a36Sopenharmony_ci list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list) 71062306a36Sopenharmony_ci if (tgtdev->dev_handle == handle) 71162306a36Sopenharmony_ci goto found_tgtdev; 71262306a36Sopenharmony_ci return NULL; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_cifound_tgtdev: 71562306a36Sopenharmony_ci mpi3mr_tgtdev_get(tgtdev); 71662306a36Sopenharmony_ci return tgtdev; 71762306a36Sopenharmony_ci} 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci/** 72062306a36Sopenharmony_ci * mpi3mr_get_tgtdev_by_handle -Get tgtdev from device handle 72162306a36Sopenharmony_ci * @mrioc: Adapter instance reference 72262306a36Sopenharmony_ci * @handle: Device handle 72362306a36Sopenharmony_ci * 72462306a36Sopenharmony_ci * Accessor to retrieve target device from the device handle. 72562306a36Sopenharmony_ci * Lock version 72662306a36Sopenharmony_ci * 72762306a36Sopenharmony_ci * Return: Target device reference. 72862306a36Sopenharmony_ci */ 72962306a36Sopenharmony_cistruct mpi3mr_tgt_dev *mpi3mr_get_tgtdev_by_handle( 73062306a36Sopenharmony_ci struct mpi3mr_ioc *mrioc, u16 handle) 73162306a36Sopenharmony_ci{ 73262306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgtdev; 73362306a36Sopenharmony_ci unsigned long flags; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci spin_lock_irqsave(&mrioc->tgtdev_lock, flags); 73662306a36Sopenharmony_ci tgtdev = __mpi3mr_get_tgtdev_by_handle(mrioc, handle); 73762306a36Sopenharmony_ci spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags); 73862306a36Sopenharmony_ci return tgtdev; 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci/** 74262306a36Sopenharmony_ci * __mpi3mr_get_tgtdev_by_perst_id -Get tgtdev from persist ID 74362306a36Sopenharmony_ci * @mrioc: Adapter instance reference 74462306a36Sopenharmony_ci * @persist_id: Persistent ID 74562306a36Sopenharmony_ci * 74662306a36Sopenharmony_ci * Accessor to retrieve target device from the Persistent ID. 74762306a36Sopenharmony_ci * Non Lock version 74862306a36Sopenharmony_ci * 74962306a36Sopenharmony_ci * Return: Target device reference. 75062306a36Sopenharmony_ci */ 75162306a36Sopenharmony_cistatic struct mpi3mr_tgt_dev *__mpi3mr_get_tgtdev_by_perst_id( 75262306a36Sopenharmony_ci struct mpi3mr_ioc *mrioc, u16 persist_id) 75362306a36Sopenharmony_ci{ 75462306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgtdev; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci assert_spin_locked(&mrioc->tgtdev_lock); 75762306a36Sopenharmony_ci list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list) 75862306a36Sopenharmony_ci if (tgtdev->perst_id == persist_id) 75962306a36Sopenharmony_ci goto found_tgtdev; 76062306a36Sopenharmony_ci return NULL; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_cifound_tgtdev: 76362306a36Sopenharmony_ci mpi3mr_tgtdev_get(tgtdev); 76462306a36Sopenharmony_ci return tgtdev; 76562306a36Sopenharmony_ci} 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci/** 76862306a36Sopenharmony_ci * mpi3mr_get_tgtdev_by_perst_id -Get tgtdev from persistent ID 76962306a36Sopenharmony_ci * @mrioc: Adapter instance reference 77062306a36Sopenharmony_ci * @persist_id: Persistent ID 77162306a36Sopenharmony_ci * 77262306a36Sopenharmony_ci * Accessor to retrieve target device from the Persistent ID. 77362306a36Sopenharmony_ci * Lock version 77462306a36Sopenharmony_ci * 77562306a36Sopenharmony_ci * Return: Target device reference. 77662306a36Sopenharmony_ci */ 77762306a36Sopenharmony_cistatic struct mpi3mr_tgt_dev *mpi3mr_get_tgtdev_by_perst_id( 77862306a36Sopenharmony_ci struct mpi3mr_ioc *mrioc, u16 persist_id) 77962306a36Sopenharmony_ci{ 78062306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgtdev; 78162306a36Sopenharmony_ci unsigned long flags; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci spin_lock_irqsave(&mrioc->tgtdev_lock, flags); 78462306a36Sopenharmony_ci tgtdev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, persist_id); 78562306a36Sopenharmony_ci spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags); 78662306a36Sopenharmony_ci return tgtdev; 78762306a36Sopenharmony_ci} 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci/** 79062306a36Sopenharmony_ci * __mpi3mr_get_tgtdev_from_tgtpriv -Get tgtdev from tgt private 79162306a36Sopenharmony_ci * @mrioc: Adapter instance reference 79262306a36Sopenharmony_ci * @tgt_priv: Target private data 79362306a36Sopenharmony_ci * 79462306a36Sopenharmony_ci * Accessor to return target device from the target private 79562306a36Sopenharmony_ci * data. Non Lock version 79662306a36Sopenharmony_ci * 79762306a36Sopenharmony_ci * Return: Target device reference. 79862306a36Sopenharmony_ci */ 79962306a36Sopenharmony_cistatic struct mpi3mr_tgt_dev *__mpi3mr_get_tgtdev_from_tgtpriv( 80062306a36Sopenharmony_ci struct mpi3mr_ioc *mrioc, struct mpi3mr_stgt_priv_data *tgt_priv) 80162306a36Sopenharmony_ci{ 80262306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgtdev; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci assert_spin_locked(&mrioc->tgtdev_lock); 80562306a36Sopenharmony_ci tgtdev = tgt_priv->tgt_dev; 80662306a36Sopenharmony_ci if (tgtdev) 80762306a36Sopenharmony_ci mpi3mr_tgtdev_get(tgtdev); 80862306a36Sopenharmony_ci return tgtdev; 80962306a36Sopenharmony_ci} 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci/** 81262306a36Sopenharmony_ci * mpi3mr_set_io_divert_for_all_vd_in_tg -set divert for TG VDs 81362306a36Sopenharmony_ci * @mrioc: Adapter instance reference 81462306a36Sopenharmony_ci * @tg: Throttle group information pointer 81562306a36Sopenharmony_ci * @divert_value: 1 or 0 81662306a36Sopenharmony_ci * 81762306a36Sopenharmony_ci * Accessor to set io_divert flag for each device associated 81862306a36Sopenharmony_ci * with the given throttle group with the given value. 81962306a36Sopenharmony_ci * 82062306a36Sopenharmony_ci * Return: None. 82162306a36Sopenharmony_ci */ 82262306a36Sopenharmony_cistatic void mpi3mr_set_io_divert_for_all_vd_in_tg(struct mpi3mr_ioc *mrioc, 82362306a36Sopenharmony_ci struct mpi3mr_throttle_group_info *tg, u8 divert_value) 82462306a36Sopenharmony_ci{ 82562306a36Sopenharmony_ci unsigned long flags; 82662306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgtdev; 82762306a36Sopenharmony_ci struct mpi3mr_stgt_priv_data *tgt_priv; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci spin_lock_irqsave(&mrioc->tgtdev_lock, flags); 83062306a36Sopenharmony_ci list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list) { 83162306a36Sopenharmony_ci if (tgtdev->starget && tgtdev->starget->hostdata) { 83262306a36Sopenharmony_ci tgt_priv = tgtdev->starget->hostdata; 83362306a36Sopenharmony_ci if (tgt_priv->throttle_group == tg) 83462306a36Sopenharmony_ci tgt_priv->io_divert = divert_value; 83562306a36Sopenharmony_ci } 83662306a36Sopenharmony_ci } 83762306a36Sopenharmony_ci spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags); 83862306a36Sopenharmony_ci} 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci/** 84162306a36Sopenharmony_ci * mpi3mr_print_device_event_notice - print notice related to post processing of 84262306a36Sopenharmony_ci * device event after controller reset. 84362306a36Sopenharmony_ci * 84462306a36Sopenharmony_ci * @mrioc: Adapter instance reference 84562306a36Sopenharmony_ci * @device_add: true for device add event and false for device removal event 84662306a36Sopenharmony_ci * 84762306a36Sopenharmony_ci * Return: None. 84862306a36Sopenharmony_ci */ 84962306a36Sopenharmony_civoid mpi3mr_print_device_event_notice(struct mpi3mr_ioc *mrioc, 85062306a36Sopenharmony_ci bool device_add) 85162306a36Sopenharmony_ci{ 85262306a36Sopenharmony_ci ioc_notice(mrioc, "Device %s was in progress before the reset and\n", 85362306a36Sopenharmony_ci (device_add ? "addition" : "removal")); 85462306a36Sopenharmony_ci ioc_notice(mrioc, "completed after reset, verify whether the exposed devices\n"); 85562306a36Sopenharmony_ci ioc_notice(mrioc, "are matched with attached devices for correctness\n"); 85662306a36Sopenharmony_ci} 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci/** 85962306a36Sopenharmony_ci * mpi3mr_remove_tgtdev_from_host - Remove dev from upper layers 86062306a36Sopenharmony_ci * @mrioc: Adapter instance reference 86162306a36Sopenharmony_ci * @tgtdev: Target device structure 86262306a36Sopenharmony_ci * 86362306a36Sopenharmony_ci * Checks whether the device is exposed to upper layers and if it 86462306a36Sopenharmony_ci * is then remove the device from upper layers by calling 86562306a36Sopenharmony_ci * scsi_remove_target(). 86662306a36Sopenharmony_ci * 86762306a36Sopenharmony_ci * Return: 0 on success, non zero on failure. 86862306a36Sopenharmony_ci */ 86962306a36Sopenharmony_civoid mpi3mr_remove_tgtdev_from_host(struct mpi3mr_ioc *mrioc, 87062306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgtdev) 87162306a36Sopenharmony_ci{ 87262306a36Sopenharmony_ci struct mpi3mr_stgt_priv_data *tgt_priv; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci ioc_info(mrioc, "%s :Removing handle(0x%04x), wwid(0x%016llx)\n", 87562306a36Sopenharmony_ci __func__, tgtdev->dev_handle, (unsigned long long)tgtdev->wwid); 87662306a36Sopenharmony_ci if (tgtdev->starget && tgtdev->starget->hostdata) { 87762306a36Sopenharmony_ci tgt_priv = tgtdev->starget->hostdata; 87862306a36Sopenharmony_ci atomic_set(&tgt_priv->block_io, 0); 87962306a36Sopenharmony_ci tgt_priv->dev_handle = MPI3MR_INVALID_DEV_HANDLE; 88062306a36Sopenharmony_ci } 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci if (!mrioc->sas_transport_enabled || (tgtdev->dev_type != 88362306a36Sopenharmony_ci MPI3_DEVICE_DEVFORM_SAS_SATA) || tgtdev->non_stl) { 88462306a36Sopenharmony_ci if (tgtdev->starget) { 88562306a36Sopenharmony_ci if (mrioc->current_event) 88662306a36Sopenharmony_ci mrioc->current_event->pending_at_sml = 1; 88762306a36Sopenharmony_ci scsi_remove_target(&tgtdev->starget->dev); 88862306a36Sopenharmony_ci tgtdev->host_exposed = 0; 88962306a36Sopenharmony_ci if (mrioc->current_event) { 89062306a36Sopenharmony_ci mrioc->current_event->pending_at_sml = 0; 89162306a36Sopenharmony_ci if (mrioc->current_event->discard) { 89262306a36Sopenharmony_ci mpi3mr_print_device_event_notice(mrioc, 89362306a36Sopenharmony_ci false); 89462306a36Sopenharmony_ci return; 89562306a36Sopenharmony_ci } 89662306a36Sopenharmony_ci } 89762306a36Sopenharmony_ci } 89862306a36Sopenharmony_ci } else 89962306a36Sopenharmony_ci mpi3mr_remove_tgtdev_from_sas_transport(mrioc, tgtdev); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci ioc_info(mrioc, "%s :Removed handle(0x%04x), wwid(0x%016llx)\n", 90262306a36Sopenharmony_ci __func__, tgtdev->dev_handle, (unsigned long long)tgtdev->wwid); 90362306a36Sopenharmony_ci} 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci/** 90662306a36Sopenharmony_ci * mpi3mr_report_tgtdev_to_host - Expose device to upper layers 90762306a36Sopenharmony_ci * @mrioc: Adapter instance reference 90862306a36Sopenharmony_ci * @perst_id: Persistent ID of the device 90962306a36Sopenharmony_ci * 91062306a36Sopenharmony_ci * Checks whether the device can be exposed to upper layers and 91162306a36Sopenharmony_ci * if it is not then expose the device to upper layers by 91262306a36Sopenharmony_ci * calling scsi_scan_target(). 91362306a36Sopenharmony_ci * 91462306a36Sopenharmony_ci * Return: 0 on success, non zero on failure. 91562306a36Sopenharmony_ci */ 91662306a36Sopenharmony_cistatic int mpi3mr_report_tgtdev_to_host(struct mpi3mr_ioc *mrioc, 91762306a36Sopenharmony_ci u16 perst_id) 91862306a36Sopenharmony_ci{ 91962306a36Sopenharmony_ci int retval = 0; 92062306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgtdev; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci if (mrioc->reset_in_progress) 92362306a36Sopenharmony_ci return -1; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci tgtdev = mpi3mr_get_tgtdev_by_perst_id(mrioc, perst_id); 92662306a36Sopenharmony_ci if (!tgtdev) { 92762306a36Sopenharmony_ci retval = -1; 92862306a36Sopenharmony_ci goto out; 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci if (tgtdev->is_hidden || tgtdev->host_exposed) { 93162306a36Sopenharmony_ci retval = -1; 93262306a36Sopenharmony_ci goto out; 93362306a36Sopenharmony_ci } 93462306a36Sopenharmony_ci if (!mrioc->sas_transport_enabled || (tgtdev->dev_type != 93562306a36Sopenharmony_ci MPI3_DEVICE_DEVFORM_SAS_SATA) || tgtdev->non_stl){ 93662306a36Sopenharmony_ci tgtdev->host_exposed = 1; 93762306a36Sopenharmony_ci if (mrioc->current_event) 93862306a36Sopenharmony_ci mrioc->current_event->pending_at_sml = 1; 93962306a36Sopenharmony_ci scsi_scan_target(&mrioc->shost->shost_gendev, 94062306a36Sopenharmony_ci mrioc->scsi_device_channel, tgtdev->perst_id, 94162306a36Sopenharmony_ci SCAN_WILD_CARD, SCSI_SCAN_INITIAL); 94262306a36Sopenharmony_ci if (!tgtdev->starget) 94362306a36Sopenharmony_ci tgtdev->host_exposed = 0; 94462306a36Sopenharmony_ci if (mrioc->current_event) { 94562306a36Sopenharmony_ci mrioc->current_event->pending_at_sml = 0; 94662306a36Sopenharmony_ci if (mrioc->current_event->discard) { 94762306a36Sopenharmony_ci mpi3mr_print_device_event_notice(mrioc, true); 94862306a36Sopenharmony_ci goto out; 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci } else 95262306a36Sopenharmony_ci mpi3mr_report_tgtdev_to_sas_transport(mrioc, tgtdev); 95362306a36Sopenharmony_ciout: 95462306a36Sopenharmony_ci if (tgtdev) 95562306a36Sopenharmony_ci mpi3mr_tgtdev_put(tgtdev); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci return retval; 95862306a36Sopenharmony_ci} 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci/** 96162306a36Sopenharmony_ci * mpi3mr_change_queue_depth- Change QD callback handler 96262306a36Sopenharmony_ci * @sdev: SCSI device reference 96362306a36Sopenharmony_ci * @q_depth: Queue depth 96462306a36Sopenharmony_ci * 96562306a36Sopenharmony_ci * Validate and limit QD and call scsi_change_queue_depth. 96662306a36Sopenharmony_ci * 96762306a36Sopenharmony_ci * Return: return value of scsi_change_queue_depth 96862306a36Sopenharmony_ci */ 96962306a36Sopenharmony_cistatic int mpi3mr_change_queue_depth(struct scsi_device *sdev, 97062306a36Sopenharmony_ci int q_depth) 97162306a36Sopenharmony_ci{ 97262306a36Sopenharmony_ci struct scsi_target *starget = scsi_target(sdev); 97362306a36Sopenharmony_ci struct Scsi_Host *shost = dev_to_shost(&starget->dev); 97462306a36Sopenharmony_ci int retval = 0; 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci if (!sdev->tagged_supported) 97762306a36Sopenharmony_ci q_depth = 1; 97862306a36Sopenharmony_ci if (q_depth > shost->can_queue) 97962306a36Sopenharmony_ci q_depth = shost->can_queue; 98062306a36Sopenharmony_ci else if (!q_depth) 98162306a36Sopenharmony_ci q_depth = MPI3MR_DEFAULT_SDEV_QD; 98262306a36Sopenharmony_ci retval = scsi_change_queue_depth(sdev, q_depth); 98362306a36Sopenharmony_ci sdev->max_queue_depth = sdev->queue_depth; 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci return retval; 98662306a36Sopenharmony_ci} 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci/** 98962306a36Sopenharmony_ci * mpi3mr_update_sdev - Update SCSI device information 99062306a36Sopenharmony_ci * @sdev: SCSI device reference 99162306a36Sopenharmony_ci * @data: target device reference 99262306a36Sopenharmony_ci * 99362306a36Sopenharmony_ci * This is an iterator function called for each SCSI device in a 99462306a36Sopenharmony_ci * target to update the target specific information into each 99562306a36Sopenharmony_ci * SCSI device. 99662306a36Sopenharmony_ci * 99762306a36Sopenharmony_ci * Return: Nothing. 99862306a36Sopenharmony_ci */ 99962306a36Sopenharmony_cistatic void 100062306a36Sopenharmony_cimpi3mr_update_sdev(struct scsi_device *sdev, void *data) 100162306a36Sopenharmony_ci{ 100262306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgtdev; 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci tgtdev = (struct mpi3mr_tgt_dev *)data; 100562306a36Sopenharmony_ci if (!tgtdev) 100662306a36Sopenharmony_ci return; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci mpi3mr_change_queue_depth(sdev, tgtdev->q_depth); 100962306a36Sopenharmony_ci switch (tgtdev->dev_type) { 101062306a36Sopenharmony_ci case MPI3_DEVICE_DEVFORM_PCIE: 101162306a36Sopenharmony_ci /*The block layer hw sector size = 512*/ 101262306a36Sopenharmony_ci if ((tgtdev->dev_spec.pcie_inf.dev_info & 101362306a36Sopenharmony_ci MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) == 101462306a36Sopenharmony_ci MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) { 101562306a36Sopenharmony_ci blk_queue_max_hw_sectors(sdev->request_queue, 101662306a36Sopenharmony_ci tgtdev->dev_spec.pcie_inf.mdts / 512); 101762306a36Sopenharmony_ci if (tgtdev->dev_spec.pcie_inf.pgsz == 0) 101862306a36Sopenharmony_ci blk_queue_virt_boundary(sdev->request_queue, 101962306a36Sopenharmony_ci ((1 << MPI3MR_DEFAULT_PGSZEXP) - 1)); 102062306a36Sopenharmony_ci else 102162306a36Sopenharmony_ci blk_queue_virt_boundary(sdev->request_queue, 102262306a36Sopenharmony_ci ((1 << tgtdev->dev_spec.pcie_inf.pgsz) - 1)); 102362306a36Sopenharmony_ci } 102462306a36Sopenharmony_ci break; 102562306a36Sopenharmony_ci default: 102662306a36Sopenharmony_ci break; 102762306a36Sopenharmony_ci } 102862306a36Sopenharmony_ci} 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci/** 103162306a36Sopenharmony_ci * mpi3mr_rfresh_tgtdevs - Refresh target device exposure 103262306a36Sopenharmony_ci * @mrioc: Adapter instance reference 103362306a36Sopenharmony_ci * 103462306a36Sopenharmony_ci * This is executed post controller reset to identify any 103562306a36Sopenharmony_ci * missing devices during reset and remove from the upper layers 103662306a36Sopenharmony_ci * or expose any newly detected device to the upper layers. 103762306a36Sopenharmony_ci * 103862306a36Sopenharmony_ci * Return: Nothing. 103962306a36Sopenharmony_ci */ 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_civoid mpi3mr_rfresh_tgtdevs(struct mpi3mr_ioc *mrioc) 104262306a36Sopenharmony_ci{ 104362306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgtdev, *tgtdev_next; 104462306a36Sopenharmony_ci struct mpi3mr_stgt_priv_data *tgt_priv; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci dprint_reset(mrioc, "refresh target devices: check for removals\n"); 104762306a36Sopenharmony_ci list_for_each_entry_safe(tgtdev, tgtdev_next, &mrioc->tgtdev_list, 104862306a36Sopenharmony_ci list) { 104962306a36Sopenharmony_ci if ((tgtdev->dev_handle == MPI3MR_INVALID_DEV_HANDLE) && 105062306a36Sopenharmony_ci tgtdev->is_hidden && 105162306a36Sopenharmony_ci tgtdev->host_exposed && tgtdev->starget && 105262306a36Sopenharmony_ci tgtdev->starget->hostdata) { 105362306a36Sopenharmony_ci tgt_priv = tgtdev->starget->hostdata; 105462306a36Sopenharmony_ci tgt_priv->dev_removed = 1; 105562306a36Sopenharmony_ci atomic_set(&tgt_priv->block_io, 0); 105662306a36Sopenharmony_ci } 105762306a36Sopenharmony_ci } 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci list_for_each_entry_safe(tgtdev, tgtdev_next, &mrioc->tgtdev_list, 106062306a36Sopenharmony_ci list) { 106162306a36Sopenharmony_ci if (tgtdev->dev_handle == MPI3MR_INVALID_DEV_HANDLE) { 106262306a36Sopenharmony_ci dprint_reset(mrioc, "removing target device with perst_id(%d)\n", 106362306a36Sopenharmony_ci tgtdev->perst_id); 106462306a36Sopenharmony_ci if (tgtdev->host_exposed) 106562306a36Sopenharmony_ci mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev); 106662306a36Sopenharmony_ci mpi3mr_tgtdev_del_from_list(mrioc, tgtdev, true); 106762306a36Sopenharmony_ci mpi3mr_tgtdev_put(tgtdev); 106862306a36Sopenharmony_ci } else if (tgtdev->is_hidden & tgtdev->host_exposed) { 106962306a36Sopenharmony_ci dprint_reset(mrioc, "hiding target device with perst_id(%d)\n", 107062306a36Sopenharmony_ci tgtdev->perst_id); 107162306a36Sopenharmony_ci mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev); 107262306a36Sopenharmony_ci } 107362306a36Sopenharmony_ci } 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci tgtdev = NULL; 107662306a36Sopenharmony_ci list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list) { 107762306a36Sopenharmony_ci if ((tgtdev->dev_handle != MPI3MR_INVALID_DEV_HANDLE) && 107862306a36Sopenharmony_ci !tgtdev->is_hidden) { 107962306a36Sopenharmony_ci if (!tgtdev->host_exposed) 108062306a36Sopenharmony_ci mpi3mr_report_tgtdev_to_host(mrioc, 108162306a36Sopenharmony_ci tgtdev->perst_id); 108262306a36Sopenharmony_ci else if (tgtdev->starget) 108362306a36Sopenharmony_ci starget_for_each_device(tgtdev->starget, 108462306a36Sopenharmony_ci (void *)tgtdev, mpi3mr_update_sdev); 108562306a36Sopenharmony_ci } 108662306a36Sopenharmony_ci } 108762306a36Sopenharmony_ci} 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci/** 109062306a36Sopenharmony_ci * mpi3mr_update_tgtdev - DevStatusChange evt bottomhalf 109162306a36Sopenharmony_ci * @mrioc: Adapter instance reference 109262306a36Sopenharmony_ci * @tgtdev: Target device internal structure 109362306a36Sopenharmony_ci * @dev_pg0: New device page0 109462306a36Sopenharmony_ci * @is_added: Flag to indicate the device is just added 109562306a36Sopenharmony_ci * 109662306a36Sopenharmony_ci * Update the information from the device page0 into the driver 109762306a36Sopenharmony_ci * cached target device structure. 109862306a36Sopenharmony_ci * 109962306a36Sopenharmony_ci * Return: Nothing. 110062306a36Sopenharmony_ci */ 110162306a36Sopenharmony_cistatic void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc, 110262306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgtdev, struct mpi3_device_page0 *dev_pg0, 110362306a36Sopenharmony_ci bool is_added) 110462306a36Sopenharmony_ci{ 110562306a36Sopenharmony_ci u16 flags = 0; 110662306a36Sopenharmony_ci struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data = NULL; 110762306a36Sopenharmony_ci struct mpi3mr_enclosure_node *enclosure_dev = NULL; 110862306a36Sopenharmony_ci u8 prot_mask = 0; 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci tgtdev->perst_id = le16_to_cpu(dev_pg0->persistent_id); 111162306a36Sopenharmony_ci tgtdev->dev_handle = le16_to_cpu(dev_pg0->dev_handle); 111262306a36Sopenharmony_ci tgtdev->dev_type = dev_pg0->device_form; 111362306a36Sopenharmony_ci tgtdev->io_unit_port = dev_pg0->io_unit_port; 111462306a36Sopenharmony_ci tgtdev->encl_handle = le16_to_cpu(dev_pg0->enclosure_handle); 111562306a36Sopenharmony_ci tgtdev->parent_handle = le16_to_cpu(dev_pg0->parent_dev_handle); 111662306a36Sopenharmony_ci tgtdev->slot = le16_to_cpu(dev_pg0->slot); 111762306a36Sopenharmony_ci tgtdev->q_depth = le16_to_cpu(dev_pg0->queue_depth); 111862306a36Sopenharmony_ci tgtdev->wwid = le64_to_cpu(dev_pg0->wwid); 111962306a36Sopenharmony_ci tgtdev->devpg0_flag = le16_to_cpu(dev_pg0->flags); 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci if (tgtdev->encl_handle) 112262306a36Sopenharmony_ci enclosure_dev = mpi3mr_enclosure_find_by_handle(mrioc, 112362306a36Sopenharmony_ci tgtdev->encl_handle); 112462306a36Sopenharmony_ci if (enclosure_dev) 112562306a36Sopenharmony_ci tgtdev->enclosure_logical_id = le64_to_cpu( 112662306a36Sopenharmony_ci enclosure_dev->pg0.enclosure_logical_id); 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci flags = tgtdev->devpg0_flag; 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci tgtdev->is_hidden = (flags & MPI3_DEVICE0_FLAGS_HIDDEN); 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci if (is_added == true) 113362306a36Sopenharmony_ci tgtdev->io_throttle_enabled = 113462306a36Sopenharmony_ci (flags & MPI3_DEVICE0_FLAGS_IO_THROTTLING_REQUIRED) ? 1 : 0; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci switch (flags & MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_MASK) { 113762306a36Sopenharmony_ci case MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_256_LB: 113862306a36Sopenharmony_ci tgtdev->wslen = MPI3MR_WRITE_SAME_MAX_LEN_256_BLKS; 113962306a36Sopenharmony_ci break; 114062306a36Sopenharmony_ci case MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_2048_LB: 114162306a36Sopenharmony_ci tgtdev->wslen = MPI3MR_WRITE_SAME_MAX_LEN_2048_BLKS; 114262306a36Sopenharmony_ci break; 114362306a36Sopenharmony_ci case MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_NO_LIMIT: 114462306a36Sopenharmony_ci default: 114562306a36Sopenharmony_ci tgtdev->wslen = 0; 114662306a36Sopenharmony_ci break; 114762306a36Sopenharmony_ci } 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci if (tgtdev->starget && tgtdev->starget->hostdata) { 115062306a36Sopenharmony_ci scsi_tgt_priv_data = (struct mpi3mr_stgt_priv_data *) 115162306a36Sopenharmony_ci tgtdev->starget->hostdata; 115262306a36Sopenharmony_ci scsi_tgt_priv_data->perst_id = tgtdev->perst_id; 115362306a36Sopenharmony_ci scsi_tgt_priv_data->dev_handle = tgtdev->dev_handle; 115462306a36Sopenharmony_ci scsi_tgt_priv_data->dev_type = tgtdev->dev_type; 115562306a36Sopenharmony_ci scsi_tgt_priv_data->io_throttle_enabled = 115662306a36Sopenharmony_ci tgtdev->io_throttle_enabled; 115762306a36Sopenharmony_ci if (is_added == true) 115862306a36Sopenharmony_ci atomic_set(&scsi_tgt_priv_data->block_io, 0); 115962306a36Sopenharmony_ci scsi_tgt_priv_data->wslen = tgtdev->wslen; 116062306a36Sopenharmony_ci } 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci switch (dev_pg0->access_status) { 116362306a36Sopenharmony_ci case MPI3_DEVICE0_ASTATUS_NO_ERRORS: 116462306a36Sopenharmony_ci case MPI3_DEVICE0_ASTATUS_PREPARE: 116562306a36Sopenharmony_ci case MPI3_DEVICE0_ASTATUS_NEEDS_INITIALIZATION: 116662306a36Sopenharmony_ci case MPI3_DEVICE0_ASTATUS_DEVICE_MISSING_DELAY: 116762306a36Sopenharmony_ci break; 116862306a36Sopenharmony_ci default: 116962306a36Sopenharmony_ci tgtdev->is_hidden = 1; 117062306a36Sopenharmony_ci break; 117162306a36Sopenharmony_ci } 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci switch (tgtdev->dev_type) { 117462306a36Sopenharmony_ci case MPI3_DEVICE_DEVFORM_SAS_SATA: 117562306a36Sopenharmony_ci { 117662306a36Sopenharmony_ci struct mpi3_device0_sas_sata_format *sasinf = 117762306a36Sopenharmony_ci &dev_pg0->device_specific.sas_sata_format; 117862306a36Sopenharmony_ci u16 dev_info = le16_to_cpu(sasinf->device_info); 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci tgtdev->dev_spec.sas_sata_inf.dev_info = dev_info; 118162306a36Sopenharmony_ci tgtdev->dev_spec.sas_sata_inf.sas_address = 118262306a36Sopenharmony_ci le64_to_cpu(sasinf->sas_address); 118362306a36Sopenharmony_ci tgtdev->dev_spec.sas_sata_inf.phy_id = sasinf->phy_num; 118462306a36Sopenharmony_ci tgtdev->dev_spec.sas_sata_inf.attached_phy_id = 118562306a36Sopenharmony_ci sasinf->attached_phy_identifier; 118662306a36Sopenharmony_ci if ((dev_info & MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK) != 118762306a36Sopenharmony_ci MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_END_DEVICE) 118862306a36Sopenharmony_ci tgtdev->is_hidden = 1; 118962306a36Sopenharmony_ci else if (!(dev_info & (MPI3_SAS_DEVICE_INFO_STP_SATA_TARGET | 119062306a36Sopenharmony_ci MPI3_SAS_DEVICE_INFO_SSP_TARGET))) 119162306a36Sopenharmony_ci tgtdev->is_hidden = 1; 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci if (((tgtdev->devpg0_flag & 119462306a36Sopenharmony_ci MPI3_DEVICE0_FLAGS_ATT_METHOD_DIR_ATTACHED) 119562306a36Sopenharmony_ci && (tgtdev->devpg0_flag & 119662306a36Sopenharmony_ci MPI3_DEVICE0_FLAGS_ATT_METHOD_VIRTUAL)) || 119762306a36Sopenharmony_ci (tgtdev->parent_handle == 0xFFFF)) 119862306a36Sopenharmony_ci tgtdev->non_stl = 1; 119962306a36Sopenharmony_ci if (tgtdev->dev_spec.sas_sata_inf.hba_port) 120062306a36Sopenharmony_ci tgtdev->dev_spec.sas_sata_inf.hba_port->port_id = 120162306a36Sopenharmony_ci dev_pg0->io_unit_port; 120262306a36Sopenharmony_ci break; 120362306a36Sopenharmony_ci } 120462306a36Sopenharmony_ci case MPI3_DEVICE_DEVFORM_PCIE: 120562306a36Sopenharmony_ci { 120662306a36Sopenharmony_ci struct mpi3_device0_pcie_format *pcieinf = 120762306a36Sopenharmony_ci &dev_pg0->device_specific.pcie_format; 120862306a36Sopenharmony_ci u16 dev_info = le16_to_cpu(pcieinf->device_info); 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci tgtdev->dev_spec.pcie_inf.dev_info = dev_info; 121162306a36Sopenharmony_ci tgtdev->dev_spec.pcie_inf.capb = 121262306a36Sopenharmony_ci le32_to_cpu(pcieinf->capabilities); 121362306a36Sopenharmony_ci tgtdev->dev_spec.pcie_inf.mdts = MPI3MR_DEFAULT_MDTS; 121462306a36Sopenharmony_ci /* 2^12 = 4096 */ 121562306a36Sopenharmony_ci tgtdev->dev_spec.pcie_inf.pgsz = 12; 121662306a36Sopenharmony_ci if (dev_pg0->access_status == MPI3_DEVICE0_ASTATUS_NO_ERRORS) { 121762306a36Sopenharmony_ci tgtdev->dev_spec.pcie_inf.mdts = 121862306a36Sopenharmony_ci le32_to_cpu(pcieinf->maximum_data_transfer_size); 121962306a36Sopenharmony_ci tgtdev->dev_spec.pcie_inf.pgsz = pcieinf->page_size; 122062306a36Sopenharmony_ci tgtdev->dev_spec.pcie_inf.reset_to = 122162306a36Sopenharmony_ci max_t(u8, pcieinf->controller_reset_to, 122262306a36Sopenharmony_ci MPI3MR_INTADMCMD_TIMEOUT); 122362306a36Sopenharmony_ci tgtdev->dev_spec.pcie_inf.abort_to = 122462306a36Sopenharmony_ci max_t(u8, pcieinf->nvme_abort_to, 122562306a36Sopenharmony_ci MPI3MR_INTADMCMD_TIMEOUT); 122662306a36Sopenharmony_ci } 122762306a36Sopenharmony_ci if (tgtdev->dev_spec.pcie_inf.mdts > (1024 * 1024)) 122862306a36Sopenharmony_ci tgtdev->dev_spec.pcie_inf.mdts = (1024 * 1024); 122962306a36Sopenharmony_ci if (((dev_info & MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) != 123062306a36Sopenharmony_ci MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) && 123162306a36Sopenharmony_ci ((dev_info & MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) != 123262306a36Sopenharmony_ci MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_SCSI_DEVICE)) 123362306a36Sopenharmony_ci tgtdev->is_hidden = 1; 123462306a36Sopenharmony_ci tgtdev->non_stl = 1; 123562306a36Sopenharmony_ci if (!mrioc->shost) 123662306a36Sopenharmony_ci break; 123762306a36Sopenharmony_ci prot_mask = scsi_host_get_prot(mrioc->shost); 123862306a36Sopenharmony_ci if (prot_mask & SHOST_DIX_TYPE0_PROTECTION) { 123962306a36Sopenharmony_ci scsi_host_set_prot(mrioc->shost, prot_mask & 0x77); 124062306a36Sopenharmony_ci ioc_info(mrioc, 124162306a36Sopenharmony_ci "%s : Disabling DIX0 prot capability\n", __func__); 124262306a36Sopenharmony_ci ioc_info(mrioc, 124362306a36Sopenharmony_ci "because HBA does not support DIX0 operation on NVME drives\n"); 124462306a36Sopenharmony_ci } 124562306a36Sopenharmony_ci break; 124662306a36Sopenharmony_ci } 124762306a36Sopenharmony_ci case MPI3_DEVICE_DEVFORM_VD: 124862306a36Sopenharmony_ci { 124962306a36Sopenharmony_ci struct mpi3_device0_vd_format *vdinf = 125062306a36Sopenharmony_ci &dev_pg0->device_specific.vd_format; 125162306a36Sopenharmony_ci struct mpi3mr_throttle_group_info *tg = NULL; 125262306a36Sopenharmony_ci u16 vdinf_io_throttle_group = 125362306a36Sopenharmony_ci le16_to_cpu(vdinf->io_throttle_group); 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci tgtdev->dev_spec.vd_inf.state = vdinf->vd_state; 125662306a36Sopenharmony_ci if (vdinf->vd_state == MPI3_DEVICE0_VD_STATE_OFFLINE) 125762306a36Sopenharmony_ci tgtdev->is_hidden = 1; 125862306a36Sopenharmony_ci tgtdev->non_stl = 1; 125962306a36Sopenharmony_ci tgtdev->dev_spec.vd_inf.tg_id = vdinf_io_throttle_group; 126062306a36Sopenharmony_ci tgtdev->dev_spec.vd_inf.tg_high = 126162306a36Sopenharmony_ci le16_to_cpu(vdinf->io_throttle_group_high) * 2048; 126262306a36Sopenharmony_ci tgtdev->dev_spec.vd_inf.tg_low = 126362306a36Sopenharmony_ci le16_to_cpu(vdinf->io_throttle_group_low) * 2048; 126462306a36Sopenharmony_ci if (vdinf_io_throttle_group < mrioc->num_io_throttle_group) { 126562306a36Sopenharmony_ci tg = mrioc->throttle_groups + vdinf_io_throttle_group; 126662306a36Sopenharmony_ci tg->id = vdinf_io_throttle_group; 126762306a36Sopenharmony_ci tg->high = tgtdev->dev_spec.vd_inf.tg_high; 126862306a36Sopenharmony_ci tg->low = tgtdev->dev_spec.vd_inf.tg_low; 126962306a36Sopenharmony_ci tg->qd_reduction = 127062306a36Sopenharmony_ci tgtdev->dev_spec.vd_inf.tg_qd_reduction; 127162306a36Sopenharmony_ci if (is_added == true) 127262306a36Sopenharmony_ci tg->fw_qd = tgtdev->q_depth; 127362306a36Sopenharmony_ci tg->modified_qd = tgtdev->q_depth; 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci tgtdev->dev_spec.vd_inf.tg = tg; 127662306a36Sopenharmony_ci if (scsi_tgt_priv_data) 127762306a36Sopenharmony_ci scsi_tgt_priv_data->throttle_group = tg; 127862306a36Sopenharmony_ci break; 127962306a36Sopenharmony_ci } 128062306a36Sopenharmony_ci default: 128162306a36Sopenharmony_ci break; 128262306a36Sopenharmony_ci } 128362306a36Sopenharmony_ci} 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci/** 128662306a36Sopenharmony_ci * mpi3mr_devstatuschg_evt_bh - DevStatusChange evt bottomhalf 128762306a36Sopenharmony_ci * @mrioc: Adapter instance reference 128862306a36Sopenharmony_ci * @fwevt: Firmware event information. 128962306a36Sopenharmony_ci * 129062306a36Sopenharmony_ci * Process Device status Change event and based on device's new 129162306a36Sopenharmony_ci * information, either expose the device to the upper layers, or 129262306a36Sopenharmony_ci * remove the device from upper layers. 129362306a36Sopenharmony_ci * 129462306a36Sopenharmony_ci * Return: Nothing. 129562306a36Sopenharmony_ci */ 129662306a36Sopenharmony_cistatic void mpi3mr_devstatuschg_evt_bh(struct mpi3mr_ioc *mrioc, 129762306a36Sopenharmony_ci struct mpi3mr_fwevt *fwevt) 129862306a36Sopenharmony_ci{ 129962306a36Sopenharmony_ci u16 dev_handle = 0; 130062306a36Sopenharmony_ci u8 uhide = 0, delete = 0, cleanup = 0; 130162306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgtdev = NULL; 130262306a36Sopenharmony_ci struct mpi3_event_data_device_status_change *evtdata = 130362306a36Sopenharmony_ci (struct mpi3_event_data_device_status_change *)fwevt->event_data; 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci dev_handle = le16_to_cpu(evtdata->dev_handle); 130662306a36Sopenharmony_ci ioc_info(mrioc, 130762306a36Sopenharmony_ci "%s :device status change: handle(0x%04x): reason code(0x%x)\n", 130862306a36Sopenharmony_ci __func__, dev_handle, evtdata->reason_code); 130962306a36Sopenharmony_ci switch (evtdata->reason_code) { 131062306a36Sopenharmony_ci case MPI3_EVENT_DEV_STAT_RC_HIDDEN: 131162306a36Sopenharmony_ci delete = 1; 131262306a36Sopenharmony_ci break; 131362306a36Sopenharmony_ci case MPI3_EVENT_DEV_STAT_RC_NOT_HIDDEN: 131462306a36Sopenharmony_ci uhide = 1; 131562306a36Sopenharmony_ci break; 131662306a36Sopenharmony_ci case MPI3_EVENT_DEV_STAT_RC_VD_NOT_RESPONDING: 131762306a36Sopenharmony_ci delete = 1; 131862306a36Sopenharmony_ci cleanup = 1; 131962306a36Sopenharmony_ci break; 132062306a36Sopenharmony_ci default: 132162306a36Sopenharmony_ci ioc_info(mrioc, "%s :Unhandled reason code(0x%x)\n", __func__, 132262306a36Sopenharmony_ci evtdata->reason_code); 132362306a36Sopenharmony_ci break; 132462306a36Sopenharmony_ci } 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle); 132762306a36Sopenharmony_ci if (!tgtdev) 132862306a36Sopenharmony_ci goto out; 132962306a36Sopenharmony_ci if (uhide) { 133062306a36Sopenharmony_ci tgtdev->is_hidden = 0; 133162306a36Sopenharmony_ci if (!tgtdev->host_exposed) 133262306a36Sopenharmony_ci mpi3mr_report_tgtdev_to_host(mrioc, tgtdev->perst_id); 133362306a36Sopenharmony_ci } 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci if (delete) 133662306a36Sopenharmony_ci mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev); 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci if (cleanup) { 133962306a36Sopenharmony_ci mpi3mr_tgtdev_del_from_list(mrioc, tgtdev, false); 134062306a36Sopenharmony_ci mpi3mr_tgtdev_put(tgtdev); 134162306a36Sopenharmony_ci } 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ciout: 134462306a36Sopenharmony_ci if (tgtdev) 134562306a36Sopenharmony_ci mpi3mr_tgtdev_put(tgtdev); 134662306a36Sopenharmony_ci} 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci/** 134962306a36Sopenharmony_ci * mpi3mr_devinfochg_evt_bh - DeviceInfoChange evt bottomhalf 135062306a36Sopenharmony_ci * @mrioc: Adapter instance reference 135162306a36Sopenharmony_ci * @dev_pg0: New device page0 135262306a36Sopenharmony_ci * 135362306a36Sopenharmony_ci * Process Device Info Change event and based on device's new 135462306a36Sopenharmony_ci * information, either expose the device to the upper layers, or 135562306a36Sopenharmony_ci * remove the device from upper layers or update the details of 135662306a36Sopenharmony_ci * the device. 135762306a36Sopenharmony_ci * 135862306a36Sopenharmony_ci * Return: Nothing. 135962306a36Sopenharmony_ci */ 136062306a36Sopenharmony_cistatic void mpi3mr_devinfochg_evt_bh(struct mpi3mr_ioc *mrioc, 136162306a36Sopenharmony_ci struct mpi3_device_page0 *dev_pg0) 136262306a36Sopenharmony_ci{ 136362306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgtdev = NULL; 136462306a36Sopenharmony_ci u16 dev_handle = 0, perst_id = 0; 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci perst_id = le16_to_cpu(dev_pg0->persistent_id); 136762306a36Sopenharmony_ci dev_handle = le16_to_cpu(dev_pg0->dev_handle); 136862306a36Sopenharmony_ci ioc_info(mrioc, 136962306a36Sopenharmony_ci "%s :Device info change: handle(0x%04x): persist_id(0x%x)\n", 137062306a36Sopenharmony_ci __func__, dev_handle, perst_id); 137162306a36Sopenharmony_ci tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle); 137262306a36Sopenharmony_ci if (!tgtdev) 137362306a36Sopenharmony_ci goto out; 137462306a36Sopenharmony_ci mpi3mr_update_tgtdev(mrioc, tgtdev, dev_pg0, false); 137562306a36Sopenharmony_ci if (!tgtdev->is_hidden && !tgtdev->host_exposed) 137662306a36Sopenharmony_ci mpi3mr_report_tgtdev_to_host(mrioc, perst_id); 137762306a36Sopenharmony_ci if (tgtdev->is_hidden && tgtdev->host_exposed) 137862306a36Sopenharmony_ci mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev); 137962306a36Sopenharmony_ci if (!tgtdev->is_hidden && tgtdev->host_exposed && tgtdev->starget) 138062306a36Sopenharmony_ci starget_for_each_device(tgtdev->starget, (void *)tgtdev, 138162306a36Sopenharmony_ci mpi3mr_update_sdev); 138262306a36Sopenharmony_ciout: 138362306a36Sopenharmony_ci if (tgtdev) 138462306a36Sopenharmony_ci mpi3mr_tgtdev_put(tgtdev); 138562306a36Sopenharmony_ci} 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci/** 138862306a36Sopenharmony_ci * mpi3mr_free_enclosure_list - release enclosures 138962306a36Sopenharmony_ci * @mrioc: Adapter instance reference 139062306a36Sopenharmony_ci * 139162306a36Sopenharmony_ci * Free memory allocated during encloure add. 139262306a36Sopenharmony_ci * 139362306a36Sopenharmony_ci * Return nothing. 139462306a36Sopenharmony_ci */ 139562306a36Sopenharmony_civoid mpi3mr_free_enclosure_list(struct mpi3mr_ioc *mrioc) 139662306a36Sopenharmony_ci{ 139762306a36Sopenharmony_ci struct mpi3mr_enclosure_node *enclosure_dev, *enclosure_dev_next; 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci list_for_each_entry_safe(enclosure_dev, 140062306a36Sopenharmony_ci enclosure_dev_next, &mrioc->enclosure_list, list) { 140162306a36Sopenharmony_ci list_del(&enclosure_dev->list); 140262306a36Sopenharmony_ci kfree(enclosure_dev); 140362306a36Sopenharmony_ci } 140462306a36Sopenharmony_ci} 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci/** 140762306a36Sopenharmony_ci * mpi3mr_enclosure_find_by_handle - enclosure search by handle 140862306a36Sopenharmony_ci * @mrioc: Adapter instance reference 140962306a36Sopenharmony_ci * @handle: Firmware device handle of the enclosure 141062306a36Sopenharmony_ci * 141162306a36Sopenharmony_ci * This searches for enclosure device based on handle, then returns the 141262306a36Sopenharmony_ci * enclosure object. 141362306a36Sopenharmony_ci * 141462306a36Sopenharmony_ci * Return: Enclosure object reference or NULL 141562306a36Sopenharmony_ci */ 141662306a36Sopenharmony_cistruct mpi3mr_enclosure_node *mpi3mr_enclosure_find_by_handle( 141762306a36Sopenharmony_ci struct mpi3mr_ioc *mrioc, u16 handle) 141862306a36Sopenharmony_ci{ 141962306a36Sopenharmony_ci struct mpi3mr_enclosure_node *enclosure_dev, *r = NULL; 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci list_for_each_entry(enclosure_dev, &mrioc->enclosure_list, list) { 142262306a36Sopenharmony_ci if (le16_to_cpu(enclosure_dev->pg0.enclosure_handle) != handle) 142362306a36Sopenharmony_ci continue; 142462306a36Sopenharmony_ci r = enclosure_dev; 142562306a36Sopenharmony_ci goto out; 142662306a36Sopenharmony_ci } 142762306a36Sopenharmony_ciout: 142862306a36Sopenharmony_ci return r; 142962306a36Sopenharmony_ci} 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci/** 143262306a36Sopenharmony_ci * mpi3mr_encldev_add_chg_evt_debug - debug for enclosure event 143362306a36Sopenharmony_ci * @mrioc: Adapter instance reference 143462306a36Sopenharmony_ci * @encl_pg0: Enclosure page 0. 143562306a36Sopenharmony_ci * @is_added: Added event or not 143662306a36Sopenharmony_ci * 143762306a36Sopenharmony_ci * Return nothing. 143862306a36Sopenharmony_ci */ 143962306a36Sopenharmony_cistatic void mpi3mr_encldev_add_chg_evt_debug(struct mpi3mr_ioc *mrioc, 144062306a36Sopenharmony_ci struct mpi3_enclosure_page0 *encl_pg0, u8 is_added) 144162306a36Sopenharmony_ci{ 144262306a36Sopenharmony_ci char *reason_str = NULL; 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci if (!(mrioc->logging_level & MPI3_DEBUG_EVENT_WORK_TASK)) 144562306a36Sopenharmony_ci return; 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci if (is_added) 144862306a36Sopenharmony_ci reason_str = "enclosure added"; 144962306a36Sopenharmony_ci else 145062306a36Sopenharmony_ci reason_str = "enclosure dev status changed"; 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci ioc_info(mrioc, 145362306a36Sopenharmony_ci "%s: handle(0x%04x), enclosure logical id(0x%016llx)\n", 145462306a36Sopenharmony_ci reason_str, le16_to_cpu(encl_pg0->enclosure_handle), 145562306a36Sopenharmony_ci (unsigned long long)le64_to_cpu(encl_pg0->enclosure_logical_id)); 145662306a36Sopenharmony_ci ioc_info(mrioc, 145762306a36Sopenharmony_ci "number of slots(%d), port(%d), flags(0x%04x), present(%d)\n", 145862306a36Sopenharmony_ci le16_to_cpu(encl_pg0->num_slots), encl_pg0->io_unit_port, 145962306a36Sopenharmony_ci le16_to_cpu(encl_pg0->flags), 146062306a36Sopenharmony_ci ((le16_to_cpu(encl_pg0->flags) & 146162306a36Sopenharmony_ci MPI3_ENCLS0_FLAGS_ENCL_DEV_PRESENT_MASK) >> 4)); 146262306a36Sopenharmony_ci} 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci/** 146562306a36Sopenharmony_ci * mpi3mr_encldev_add_chg_evt_bh - Enclosure evt bottomhalf 146662306a36Sopenharmony_ci * @mrioc: Adapter instance reference 146762306a36Sopenharmony_ci * @fwevt: Firmware event reference 146862306a36Sopenharmony_ci * 146962306a36Sopenharmony_ci * Prints information about the Enclosure device status or 147062306a36Sopenharmony_ci * Enclosure add events if logging is enabled and add or remove 147162306a36Sopenharmony_ci * the enclosure from the controller's internal list of 147262306a36Sopenharmony_ci * enclosures. 147362306a36Sopenharmony_ci * 147462306a36Sopenharmony_ci * Return: Nothing. 147562306a36Sopenharmony_ci */ 147662306a36Sopenharmony_cistatic void mpi3mr_encldev_add_chg_evt_bh(struct mpi3mr_ioc *mrioc, 147762306a36Sopenharmony_ci struct mpi3mr_fwevt *fwevt) 147862306a36Sopenharmony_ci{ 147962306a36Sopenharmony_ci struct mpi3mr_enclosure_node *enclosure_dev = NULL; 148062306a36Sopenharmony_ci struct mpi3_enclosure_page0 *encl_pg0; 148162306a36Sopenharmony_ci u16 encl_handle; 148262306a36Sopenharmony_ci u8 added, present; 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci encl_pg0 = (struct mpi3_enclosure_page0 *) fwevt->event_data; 148562306a36Sopenharmony_ci added = (fwevt->event_id == MPI3_EVENT_ENCL_DEVICE_ADDED) ? 1 : 0; 148662306a36Sopenharmony_ci mpi3mr_encldev_add_chg_evt_debug(mrioc, encl_pg0, added); 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci encl_handle = le16_to_cpu(encl_pg0->enclosure_handle); 149062306a36Sopenharmony_ci present = ((le16_to_cpu(encl_pg0->flags) & 149162306a36Sopenharmony_ci MPI3_ENCLS0_FLAGS_ENCL_DEV_PRESENT_MASK) >> 4); 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci if (encl_handle) 149462306a36Sopenharmony_ci enclosure_dev = mpi3mr_enclosure_find_by_handle(mrioc, 149562306a36Sopenharmony_ci encl_handle); 149662306a36Sopenharmony_ci if (!enclosure_dev && present) { 149762306a36Sopenharmony_ci enclosure_dev = 149862306a36Sopenharmony_ci kzalloc(sizeof(struct mpi3mr_enclosure_node), 149962306a36Sopenharmony_ci GFP_KERNEL); 150062306a36Sopenharmony_ci if (!enclosure_dev) 150162306a36Sopenharmony_ci return; 150262306a36Sopenharmony_ci list_add_tail(&enclosure_dev->list, 150362306a36Sopenharmony_ci &mrioc->enclosure_list); 150462306a36Sopenharmony_ci } 150562306a36Sopenharmony_ci if (enclosure_dev) { 150662306a36Sopenharmony_ci if (!present) { 150762306a36Sopenharmony_ci list_del(&enclosure_dev->list); 150862306a36Sopenharmony_ci kfree(enclosure_dev); 150962306a36Sopenharmony_ci } else 151062306a36Sopenharmony_ci memcpy(&enclosure_dev->pg0, encl_pg0, 151162306a36Sopenharmony_ci sizeof(enclosure_dev->pg0)); 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci } 151462306a36Sopenharmony_ci} 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci/** 151762306a36Sopenharmony_ci * mpi3mr_sastopochg_evt_debug - SASTopoChange details 151862306a36Sopenharmony_ci * @mrioc: Adapter instance reference 151962306a36Sopenharmony_ci * @event_data: SAS topology change list event data 152062306a36Sopenharmony_ci * 152162306a36Sopenharmony_ci * Prints information about the SAS topology change event. 152262306a36Sopenharmony_ci * 152362306a36Sopenharmony_ci * Return: Nothing. 152462306a36Sopenharmony_ci */ 152562306a36Sopenharmony_cistatic void 152662306a36Sopenharmony_cimpi3mr_sastopochg_evt_debug(struct mpi3mr_ioc *mrioc, 152762306a36Sopenharmony_ci struct mpi3_event_data_sas_topology_change_list *event_data) 152862306a36Sopenharmony_ci{ 152962306a36Sopenharmony_ci int i; 153062306a36Sopenharmony_ci u16 handle; 153162306a36Sopenharmony_ci u8 reason_code, phy_number; 153262306a36Sopenharmony_ci char *status_str = NULL; 153362306a36Sopenharmony_ci u8 link_rate, prev_link_rate; 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci switch (event_data->exp_status) { 153662306a36Sopenharmony_ci case MPI3_EVENT_SAS_TOPO_ES_NOT_RESPONDING: 153762306a36Sopenharmony_ci status_str = "remove"; 153862306a36Sopenharmony_ci break; 153962306a36Sopenharmony_ci case MPI3_EVENT_SAS_TOPO_ES_RESPONDING: 154062306a36Sopenharmony_ci status_str = "responding"; 154162306a36Sopenharmony_ci break; 154262306a36Sopenharmony_ci case MPI3_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING: 154362306a36Sopenharmony_ci status_str = "remove delay"; 154462306a36Sopenharmony_ci break; 154562306a36Sopenharmony_ci case MPI3_EVENT_SAS_TOPO_ES_NO_EXPANDER: 154662306a36Sopenharmony_ci status_str = "direct attached"; 154762306a36Sopenharmony_ci break; 154862306a36Sopenharmony_ci default: 154962306a36Sopenharmony_ci status_str = "unknown status"; 155062306a36Sopenharmony_ci break; 155162306a36Sopenharmony_ci } 155262306a36Sopenharmony_ci ioc_info(mrioc, "%s :sas topology change: (%s)\n", 155362306a36Sopenharmony_ci __func__, status_str); 155462306a36Sopenharmony_ci ioc_info(mrioc, 155562306a36Sopenharmony_ci "%s :\texpander_handle(0x%04x), port(%d), enclosure_handle(0x%04x) start_phy(%02d), num_entries(%d)\n", 155662306a36Sopenharmony_ci __func__, le16_to_cpu(event_data->expander_dev_handle), 155762306a36Sopenharmony_ci event_data->io_unit_port, 155862306a36Sopenharmony_ci le16_to_cpu(event_data->enclosure_handle), 155962306a36Sopenharmony_ci event_data->start_phy_num, event_data->num_entries); 156062306a36Sopenharmony_ci for (i = 0; i < event_data->num_entries; i++) { 156162306a36Sopenharmony_ci handle = le16_to_cpu(event_data->phy_entry[i].attached_dev_handle); 156262306a36Sopenharmony_ci if (!handle) 156362306a36Sopenharmony_ci continue; 156462306a36Sopenharmony_ci phy_number = event_data->start_phy_num + i; 156562306a36Sopenharmony_ci reason_code = event_data->phy_entry[i].status & 156662306a36Sopenharmony_ci MPI3_EVENT_SAS_TOPO_PHY_RC_MASK; 156762306a36Sopenharmony_ci switch (reason_code) { 156862306a36Sopenharmony_ci case MPI3_EVENT_SAS_TOPO_PHY_RC_TARG_NOT_RESPONDING: 156962306a36Sopenharmony_ci status_str = "target remove"; 157062306a36Sopenharmony_ci break; 157162306a36Sopenharmony_ci case MPI3_EVENT_SAS_TOPO_PHY_RC_DELAY_NOT_RESPONDING: 157262306a36Sopenharmony_ci status_str = "delay target remove"; 157362306a36Sopenharmony_ci break; 157462306a36Sopenharmony_ci case MPI3_EVENT_SAS_TOPO_PHY_RC_PHY_CHANGED: 157562306a36Sopenharmony_ci status_str = "link status change"; 157662306a36Sopenharmony_ci break; 157762306a36Sopenharmony_ci case MPI3_EVENT_SAS_TOPO_PHY_RC_NO_CHANGE: 157862306a36Sopenharmony_ci status_str = "link status no change"; 157962306a36Sopenharmony_ci break; 158062306a36Sopenharmony_ci case MPI3_EVENT_SAS_TOPO_PHY_RC_RESPONDING: 158162306a36Sopenharmony_ci status_str = "target responding"; 158262306a36Sopenharmony_ci break; 158362306a36Sopenharmony_ci default: 158462306a36Sopenharmony_ci status_str = "unknown"; 158562306a36Sopenharmony_ci break; 158662306a36Sopenharmony_ci } 158762306a36Sopenharmony_ci link_rate = event_data->phy_entry[i].link_rate >> 4; 158862306a36Sopenharmony_ci prev_link_rate = event_data->phy_entry[i].link_rate & 0xF; 158962306a36Sopenharmony_ci ioc_info(mrioc, 159062306a36Sopenharmony_ci "%s :\tphy(%02d), attached_handle(0x%04x): %s: link rate: new(0x%02x), old(0x%02x)\n", 159162306a36Sopenharmony_ci __func__, phy_number, handle, status_str, link_rate, 159262306a36Sopenharmony_ci prev_link_rate); 159362306a36Sopenharmony_ci } 159462306a36Sopenharmony_ci} 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci/** 159762306a36Sopenharmony_ci * mpi3mr_sastopochg_evt_bh - SASTopologyChange evt bottomhalf 159862306a36Sopenharmony_ci * @mrioc: Adapter instance reference 159962306a36Sopenharmony_ci * @fwevt: Firmware event reference 160062306a36Sopenharmony_ci * 160162306a36Sopenharmony_ci * Prints information about the SAS topology change event and 160262306a36Sopenharmony_ci * for "not responding" event code, removes the device from the 160362306a36Sopenharmony_ci * upper layers. 160462306a36Sopenharmony_ci * 160562306a36Sopenharmony_ci * Return: Nothing. 160662306a36Sopenharmony_ci */ 160762306a36Sopenharmony_cistatic void mpi3mr_sastopochg_evt_bh(struct mpi3mr_ioc *mrioc, 160862306a36Sopenharmony_ci struct mpi3mr_fwevt *fwevt) 160962306a36Sopenharmony_ci{ 161062306a36Sopenharmony_ci struct mpi3_event_data_sas_topology_change_list *event_data = 161162306a36Sopenharmony_ci (struct mpi3_event_data_sas_topology_change_list *)fwevt->event_data; 161262306a36Sopenharmony_ci int i; 161362306a36Sopenharmony_ci u16 handle; 161462306a36Sopenharmony_ci u8 reason_code; 161562306a36Sopenharmony_ci u64 exp_sas_address = 0, parent_sas_address = 0; 161662306a36Sopenharmony_ci struct mpi3mr_hba_port *hba_port = NULL; 161762306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgtdev = NULL; 161862306a36Sopenharmony_ci struct mpi3mr_sas_node *sas_expander = NULL; 161962306a36Sopenharmony_ci unsigned long flags; 162062306a36Sopenharmony_ci u8 link_rate, prev_link_rate, parent_phy_number; 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci mpi3mr_sastopochg_evt_debug(mrioc, event_data); 162362306a36Sopenharmony_ci if (mrioc->sas_transport_enabled) { 162462306a36Sopenharmony_ci hba_port = mpi3mr_get_hba_port_by_id(mrioc, 162562306a36Sopenharmony_ci event_data->io_unit_port); 162662306a36Sopenharmony_ci if (le16_to_cpu(event_data->expander_dev_handle)) { 162762306a36Sopenharmony_ci spin_lock_irqsave(&mrioc->sas_node_lock, flags); 162862306a36Sopenharmony_ci sas_expander = __mpi3mr_expander_find_by_handle(mrioc, 162962306a36Sopenharmony_ci le16_to_cpu(event_data->expander_dev_handle)); 163062306a36Sopenharmony_ci if (sas_expander) { 163162306a36Sopenharmony_ci exp_sas_address = sas_expander->sas_address; 163262306a36Sopenharmony_ci hba_port = sas_expander->hba_port; 163362306a36Sopenharmony_ci } 163462306a36Sopenharmony_ci spin_unlock_irqrestore(&mrioc->sas_node_lock, flags); 163562306a36Sopenharmony_ci parent_sas_address = exp_sas_address; 163662306a36Sopenharmony_ci } else 163762306a36Sopenharmony_ci parent_sas_address = mrioc->sas_hba.sas_address; 163862306a36Sopenharmony_ci } 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_ci for (i = 0; i < event_data->num_entries; i++) { 164162306a36Sopenharmony_ci if (fwevt->discard) 164262306a36Sopenharmony_ci return; 164362306a36Sopenharmony_ci handle = le16_to_cpu(event_data->phy_entry[i].attached_dev_handle); 164462306a36Sopenharmony_ci if (!handle) 164562306a36Sopenharmony_ci continue; 164662306a36Sopenharmony_ci tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, handle); 164762306a36Sopenharmony_ci if (!tgtdev) 164862306a36Sopenharmony_ci continue; 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ci reason_code = event_data->phy_entry[i].status & 165162306a36Sopenharmony_ci MPI3_EVENT_SAS_TOPO_PHY_RC_MASK; 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci switch (reason_code) { 165462306a36Sopenharmony_ci case MPI3_EVENT_SAS_TOPO_PHY_RC_TARG_NOT_RESPONDING: 165562306a36Sopenharmony_ci if (tgtdev->host_exposed) 165662306a36Sopenharmony_ci mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev); 165762306a36Sopenharmony_ci mpi3mr_tgtdev_del_from_list(mrioc, tgtdev, false); 165862306a36Sopenharmony_ci mpi3mr_tgtdev_put(tgtdev); 165962306a36Sopenharmony_ci break; 166062306a36Sopenharmony_ci case MPI3_EVENT_SAS_TOPO_PHY_RC_RESPONDING: 166162306a36Sopenharmony_ci case MPI3_EVENT_SAS_TOPO_PHY_RC_PHY_CHANGED: 166262306a36Sopenharmony_ci case MPI3_EVENT_SAS_TOPO_PHY_RC_NO_CHANGE: 166362306a36Sopenharmony_ci { 166462306a36Sopenharmony_ci if (!mrioc->sas_transport_enabled || tgtdev->non_stl 166562306a36Sopenharmony_ci || tgtdev->is_hidden) 166662306a36Sopenharmony_ci break; 166762306a36Sopenharmony_ci link_rate = event_data->phy_entry[i].link_rate >> 4; 166862306a36Sopenharmony_ci prev_link_rate = event_data->phy_entry[i].link_rate & 0xF; 166962306a36Sopenharmony_ci if (link_rate == prev_link_rate) 167062306a36Sopenharmony_ci break; 167162306a36Sopenharmony_ci if (!parent_sas_address) 167262306a36Sopenharmony_ci break; 167362306a36Sopenharmony_ci parent_phy_number = event_data->start_phy_num + i; 167462306a36Sopenharmony_ci mpi3mr_update_links(mrioc, parent_sas_address, handle, 167562306a36Sopenharmony_ci parent_phy_number, link_rate, hba_port); 167662306a36Sopenharmony_ci break; 167762306a36Sopenharmony_ci } 167862306a36Sopenharmony_ci default: 167962306a36Sopenharmony_ci break; 168062306a36Sopenharmony_ci } 168162306a36Sopenharmony_ci if (tgtdev) 168262306a36Sopenharmony_ci mpi3mr_tgtdev_put(tgtdev); 168362306a36Sopenharmony_ci } 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci if (mrioc->sas_transport_enabled && (event_data->exp_status == 168662306a36Sopenharmony_ci MPI3_EVENT_SAS_TOPO_ES_NOT_RESPONDING)) { 168762306a36Sopenharmony_ci if (sas_expander) 168862306a36Sopenharmony_ci mpi3mr_expander_remove(mrioc, exp_sas_address, 168962306a36Sopenharmony_ci hba_port); 169062306a36Sopenharmony_ci } 169162306a36Sopenharmony_ci} 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci/** 169462306a36Sopenharmony_ci * mpi3mr_pcietopochg_evt_debug - PCIeTopoChange details 169562306a36Sopenharmony_ci * @mrioc: Adapter instance reference 169662306a36Sopenharmony_ci * @event_data: PCIe topology change list event data 169762306a36Sopenharmony_ci * 169862306a36Sopenharmony_ci * Prints information about the PCIe topology change event. 169962306a36Sopenharmony_ci * 170062306a36Sopenharmony_ci * Return: Nothing. 170162306a36Sopenharmony_ci */ 170262306a36Sopenharmony_cistatic void 170362306a36Sopenharmony_cimpi3mr_pcietopochg_evt_debug(struct mpi3mr_ioc *mrioc, 170462306a36Sopenharmony_ci struct mpi3_event_data_pcie_topology_change_list *event_data) 170562306a36Sopenharmony_ci{ 170662306a36Sopenharmony_ci int i; 170762306a36Sopenharmony_ci u16 handle; 170862306a36Sopenharmony_ci u16 reason_code; 170962306a36Sopenharmony_ci u8 port_number; 171062306a36Sopenharmony_ci char *status_str = NULL; 171162306a36Sopenharmony_ci u8 link_rate, prev_link_rate; 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci switch (event_data->switch_status) { 171462306a36Sopenharmony_ci case MPI3_EVENT_PCIE_TOPO_SS_NOT_RESPONDING: 171562306a36Sopenharmony_ci status_str = "remove"; 171662306a36Sopenharmony_ci break; 171762306a36Sopenharmony_ci case MPI3_EVENT_PCIE_TOPO_SS_RESPONDING: 171862306a36Sopenharmony_ci status_str = "responding"; 171962306a36Sopenharmony_ci break; 172062306a36Sopenharmony_ci case MPI3_EVENT_PCIE_TOPO_SS_DELAY_NOT_RESPONDING: 172162306a36Sopenharmony_ci status_str = "remove delay"; 172262306a36Sopenharmony_ci break; 172362306a36Sopenharmony_ci case MPI3_EVENT_PCIE_TOPO_SS_NO_PCIE_SWITCH: 172462306a36Sopenharmony_ci status_str = "direct attached"; 172562306a36Sopenharmony_ci break; 172662306a36Sopenharmony_ci default: 172762306a36Sopenharmony_ci status_str = "unknown status"; 172862306a36Sopenharmony_ci break; 172962306a36Sopenharmony_ci } 173062306a36Sopenharmony_ci ioc_info(mrioc, "%s :pcie topology change: (%s)\n", 173162306a36Sopenharmony_ci __func__, status_str); 173262306a36Sopenharmony_ci ioc_info(mrioc, 173362306a36Sopenharmony_ci "%s :\tswitch_handle(0x%04x), enclosure_handle(0x%04x) start_port(%02d), num_entries(%d)\n", 173462306a36Sopenharmony_ci __func__, le16_to_cpu(event_data->switch_dev_handle), 173562306a36Sopenharmony_ci le16_to_cpu(event_data->enclosure_handle), 173662306a36Sopenharmony_ci event_data->start_port_num, event_data->num_entries); 173762306a36Sopenharmony_ci for (i = 0; i < event_data->num_entries; i++) { 173862306a36Sopenharmony_ci handle = 173962306a36Sopenharmony_ci le16_to_cpu(event_data->port_entry[i].attached_dev_handle); 174062306a36Sopenharmony_ci if (!handle) 174162306a36Sopenharmony_ci continue; 174262306a36Sopenharmony_ci port_number = event_data->start_port_num + i; 174362306a36Sopenharmony_ci reason_code = event_data->port_entry[i].port_status; 174462306a36Sopenharmony_ci switch (reason_code) { 174562306a36Sopenharmony_ci case MPI3_EVENT_PCIE_TOPO_PS_NOT_RESPONDING: 174662306a36Sopenharmony_ci status_str = "target remove"; 174762306a36Sopenharmony_ci break; 174862306a36Sopenharmony_ci case MPI3_EVENT_PCIE_TOPO_PS_DELAY_NOT_RESPONDING: 174962306a36Sopenharmony_ci status_str = "delay target remove"; 175062306a36Sopenharmony_ci break; 175162306a36Sopenharmony_ci case MPI3_EVENT_PCIE_TOPO_PS_PORT_CHANGED: 175262306a36Sopenharmony_ci status_str = "link status change"; 175362306a36Sopenharmony_ci break; 175462306a36Sopenharmony_ci case MPI3_EVENT_PCIE_TOPO_PS_NO_CHANGE: 175562306a36Sopenharmony_ci status_str = "link status no change"; 175662306a36Sopenharmony_ci break; 175762306a36Sopenharmony_ci case MPI3_EVENT_PCIE_TOPO_PS_RESPONDING: 175862306a36Sopenharmony_ci status_str = "target responding"; 175962306a36Sopenharmony_ci break; 176062306a36Sopenharmony_ci default: 176162306a36Sopenharmony_ci status_str = "unknown"; 176262306a36Sopenharmony_ci break; 176362306a36Sopenharmony_ci } 176462306a36Sopenharmony_ci link_rate = event_data->port_entry[i].current_port_info & 176562306a36Sopenharmony_ci MPI3_EVENT_PCIE_TOPO_PI_RATE_MASK; 176662306a36Sopenharmony_ci prev_link_rate = event_data->port_entry[i].previous_port_info & 176762306a36Sopenharmony_ci MPI3_EVENT_PCIE_TOPO_PI_RATE_MASK; 176862306a36Sopenharmony_ci ioc_info(mrioc, 176962306a36Sopenharmony_ci "%s :\tport(%02d), attached_handle(0x%04x): %s: link rate: new(0x%02x), old(0x%02x)\n", 177062306a36Sopenharmony_ci __func__, port_number, handle, status_str, link_rate, 177162306a36Sopenharmony_ci prev_link_rate); 177262306a36Sopenharmony_ci } 177362306a36Sopenharmony_ci} 177462306a36Sopenharmony_ci 177562306a36Sopenharmony_ci/** 177662306a36Sopenharmony_ci * mpi3mr_pcietopochg_evt_bh - PCIeTopologyChange evt bottomhalf 177762306a36Sopenharmony_ci * @mrioc: Adapter instance reference 177862306a36Sopenharmony_ci * @fwevt: Firmware event reference 177962306a36Sopenharmony_ci * 178062306a36Sopenharmony_ci * Prints information about the PCIe topology change event and 178162306a36Sopenharmony_ci * for "not responding" event code, removes the device from the 178262306a36Sopenharmony_ci * upper layers. 178362306a36Sopenharmony_ci * 178462306a36Sopenharmony_ci * Return: Nothing. 178562306a36Sopenharmony_ci */ 178662306a36Sopenharmony_cistatic void mpi3mr_pcietopochg_evt_bh(struct mpi3mr_ioc *mrioc, 178762306a36Sopenharmony_ci struct mpi3mr_fwevt *fwevt) 178862306a36Sopenharmony_ci{ 178962306a36Sopenharmony_ci struct mpi3_event_data_pcie_topology_change_list *event_data = 179062306a36Sopenharmony_ci (struct mpi3_event_data_pcie_topology_change_list *)fwevt->event_data; 179162306a36Sopenharmony_ci int i; 179262306a36Sopenharmony_ci u16 handle; 179362306a36Sopenharmony_ci u8 reason_code; 179462306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgtdev = NULL; 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci mpi3mr_pcietopochg_evt_debug(mrioc, event_data); 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci for (i = 0; i < event_data->num_entries; i++) { 179962306a36Sopenharmony_ci if (fwevt->discard) 180062306a36Sopenharmony_ci return; 180162306a36Sopenharmony_ci handle = 180262306a36Sopenharmony_ci le16_to_cpu(event_data->port_entry[i].attached_dev_handle); 180362306a36Sopenharmony_ci if (!handle) 180462306a36Sopenharmony_ci continue; 180562306a36Sopenharmony_ci tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, handle); 180662306a36Sopenharmony_ci if (!tgtdev) 180762306a36Sopenharmony_ci continue; 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci reason_code = event_data->port_entry[i].port_status; 181062306a36Sopenharmony_ci 181162306a36Sopenharmony_ci switch (reason_code) { 181262306a36Sopenharmony_ci case MPI3_EVENT_PCIE_TOPO_PS_NOT_RESPONDING: 181362306a36Sopenharmony_ci if (tgtdev->host_exposed) 181462306a36Sopenharmony_ci mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev); 181562306a36Sopenharmony_ci mpi3mr_tgtdev_del_from_list(mrioc, tgtdev, false); 181662306a36Sopenharmony_ci mpi3mr_tgtdev_put(tgtdev); 181762306a36Sopenharmony_ci break; 181862306a36Sopenharmony_ci default: 181962306a36Sopenharmony_ci break; 182062306a36Sopenharmony_ci } 182162306a36Sopenharmony_ci if (tgtdev) 182262306a36Sopenharmony_ci mpi3mr_tgtdev_put(tgtdev); 182362306a36Sopenharmony_ci } 182462306a36Sopenharmony_ci} 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_ci/** 182762306a36Sopenharmony_ci * mpi3mr_logdata_evt_bh - Log data event bottomhalf 182862306a36Sopenharmony_ci * @mrioc: Adapter instance reference 182962306a36Sopenharmony_ci * @fwevt: Firmware event reference 183062306a36Sopenharmony_ci * 183162306a36Sopenharmony_ci * Extracts the event data and calls application interfacing 183262306a36Sopenharmony_ci * function to process the event further. 183362306a36Sopenharmony_ci * 183462306a36Sopenharmony_ci * Return: Nothing. 183562306a36Sopenharmony_ci */ 183662306a36Sopenharmony_cistatic void mpi3mr_logdata_evt_bh(struct mpi3mr_ioc *mrioc, 183762306a36Sopenharmony_ci struct mpi3mr_fwevt *fwevt) 183862306a36Sopenharmony_ci{ 183962306a36Sopenharmony_ci mpi3mr_app_save_logdata(mrioc, fwevt->event_data, 184062306a36Sopenharmony_ci fwevt->event_data_size); 184162306a36Sopenharmony_ci} 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci/** 184462306a36Sopenharmony_ci * mpi3mr_update_sdev_qd - Update SCSI device queue depath 184562306a36Sopenharmony_ci * @sdev: SCSI device reference 184662306a36Sopenharmony_ci * @data: Queue depth reference 184762306a36Sopenharmony_ci * 184862306a36Sopenharmony_ci * This is an iterator function called for each SCSI device in a 184962306a36Sopenharmony_ci * target to update the QD of each SCSI device. 185062306a36Sopenharmony_ci * 185162306a36Sopenharmony_ci * Return: Nothing. 185262306a36Sopenharmony_ci */ 185362306a36Sopenharmony_cistatic void mpi3mr_update_sdev_qd(struct scsi_device *sdev, void *data) 185462306a36Sopenharmony_ci{ 185562306a36Sopenharmony_ci u16 *q_depth = (u16 *)data; 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci scsi_change_queue_depth(sdev, (int)*q_depth); 185862306a36Sopenharmony_ci sdev->max_queue_depth = sdev->queue_depth; 185962306a36Sopenharmony_ci} 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci/** 186262306a36Sopenharmony_ci * mpi3mr_set_qd_for_all_vd_in_tg -set QD for TG VDs 186362306a36Sopenharmony_ci * @mrioc: Adapter instance reference 186462306a36Sopenharmony_ci * @tg: Throttle group information pointer 186562306a36Sopenharmony_ci * 186662306a36Sopenharmony_ci * Accessor to reduce QD for each device associated with the 186762306a36Sopenharmony_ci * given throttle group. 186862306a36Sopenharmony_ci * 186962306a36Sopenharmony_ci * Return: None. 187062306a36Sopenharmony_ci */ 187162306a36Sopenharmony_cistatic void mpi3mr_set_qd_for_all_vd_in_tg(struct mpi3mr_ioc *mrioc, 187262306a36Sopenharmony_ci struct mpi3mr_throttle_group_info *tg) 187362306a36Sopenharmony_ci{ 187462306a36Sopenharmony_ci unsigned long flags; 187562306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgtdev; 187662306a36Sopenharmony_ci struct mpi3mr_stgt_priv_data *tgt_priv; 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_ci spin_lock_irqsave(&mrioc->tgtdev_lock, flags); 188062306a36Sopenharmony_ci list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list) { 188162306a36Sopenharmony_ci if (tgtdev->starget && tgtdev->starget->hostdata) { 188262306a36Sopenharmony_ci tgt_priv = tgtdev->starget->hostdata; 188362306a36Sopenharmony_ci if (tgt_priv->throttle_group == tg) { 188462306a36Sopenharmony_ci dprint_event_bh(mrioc, 188562306a36Sopenharmony_ci "updating qd due to throttling for persist_id(%d) original_qd(%d), reduced_qd (%d)\n", 188662306a36Sopenharmony_ci tgt_priv->perst_id, tgtdev->q_depth, 188762306a36Sopenharmony_ci tg->modified_qd); 188862306a36Sopenharmony_ci starget_for_each_device(tgtdev->starget, 188962306a36Sopenharmony_ci (void *)&tg->modified_qd, 189062306a36Sopenharmony_ci mpi3mr_update_sdev_qd); 189162306a36Sopenharmony_ci } 189262306a36Sopenharmony_ci } 189362306a36Sopenharmony_ci } 189462306a36Sopenharmony_ci spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags); 189562306a36Sopenharmony_ci} 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_ci/** 189862306a36Sopenharmony_ci * mpi3mr_fwevt_bh - Firmware event bottomhalf handler 189962306a36Sopenharmony_ci * @mrioc: Adapter instance reference 190062306a36Sopenharmony_ci * @fwevt: Firmware event reference 190162306a36Sopenharmony_ci * 190262306a36Sopenharmony_ci * Identifies the firmware event and calls corresponding bottomg 190362306a36Sopenharmony_ci * half handler and sends event acknowledgment if required. 190462306a36Sopenharmony_ci * 190562306a36Sopenharmony_ci * Return: Nothing. 190662306a36Sopenharmony_ci */ 190762306a36Sopenharmony_cistatic void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc, 190862306a36Sopenharmony_ci struct mpi3mr_fwevt *fwevt) 190962306a36Sopenharmony_ci{ 191062306a36Sopenharmony_ci struct mpi3_device_page0 *dev_pg0 = NULL; 191162306a36Sopenharmony_ci u16 perst_id, handle, dev_info; 191262306a36Sopenharmony_ci struct mpi3_device0_sas_sata_format *sasinf = NULL; 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ci mpi3mr_fwevt_del_from_list(mrioc, fwevt); 191562306a36Sopenharmony_ci mrioc->current_event = fwevt; 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci if (mrioc->stop_drv_processing) 191862306a36Sopenharmony_ci goto out; 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci if (mrioc->unrecoverable) { 192162306a36Sopenharmony_ci dprint_event_bh(mrioc, 192262306a36Sopenharmony_ci "ignoring event(0x%02x) in bottom half handler due to unrecoverable controller\n", 192362306a36Sopenharmony_ci fwevt->event_id); 192462306a36Sopenharmony_ci goto out; 192562306a36Sopenharmony_ci } 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_ci if (!fwevt->process_evt) 192862306a36Sopenharmony_ci goto evt_ack; 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci switch (fwevt->event_id) { 193162306a36Sopenharmony_ci case MPI3_EVENT_DEVICE_ADDED: 193262306a36Sopenharmony_ci { 193362306a36Sopenharmony_ci dev_pg0 = (struct mpi3_device_page0 *)fwevt->event_data; 193462306a36Sopenharmony_ci perst_id = le16_to_cpu(dev_pg0->persistent_id); 193562306a36Sopenharmony_ci handle = le16_to_cpu(dev_pg0->dev_handle); 193662306a36Sopenharmony_ci if (perst_id != MPI3_DEVICE0_PERSISTENTID_INVALID) 193762306a36Sopenharmony_ci mpi3mr_report_tgtdev_to_host(mrioc, perst_id); 193862306a36Sopenharmony_ci else if (mrioc->sas_transport_enabled && 193962306a36Sopenharmony_ci (dev_pg0->device_form == MPI3_DEVICE_DEVFORM_SAS_SATA)) { 194062306a36Sopenharmony_ci sasinf = &dev_pg0->device_specific.sas_sata_format; 194162306a36Sopenharmony_ci dev_info = le16_to_cpu(sasinf->device_info); 194262306a36Sopenharmony_ci if (!mrioc->sas_hba.num_phys) 194362306a36Sopenharmony_ci mpi3mr_sas_host_add(mrioc); 194462306a36Sopenharmony_ci else 194562306a36Sopenharmony_ci mpi3mr_sas_host_refresh(mrioc); 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ci if (mpi3mr_is_expander_device(dev_info)) 194862306a36Sopenharmony_ci mpi3mr_expander_add(mrioc, handle); 194962306a36Sopenharmony_ci } 195062306a36Sopenharmony_ci break; 195162306a36Sopenharmony_ci } 195262306a36Sopenharmony_ci case MPI3_EVENT_DEVICE_INFO_CHANGED: 195362306a36Sopenharmony_ci { 195462306a36Sopenharmony_ci dev_pg0 = (struct mpi3_device_page0 *)fwevt->event_data; 195562306a36Sopenharmony_ci perst_id = le16_to_cpu(dev_pg0->persistent_id); 195662306a36Sopenharmony_ci if (perst_id != MPI3_DEVICE0_PERSISTENTID_INVALID) 195762306a36Sopenharmony_ci mpi3mr_devinfochg_evt_bh(mrioc, dev_pg0); 195862306a36Sopenharmony_ci break; 195962306a36Sopenharmony_ci } 196062306a36Sopenharmony_ci case MPI3_EVENT_DEVICE_STATUS_CHANGE: 196162306a36Sopenharmony_ci { 196262306a36Sopenharmony_ci mpi3mr_devstatuschg_evt_bh(mrioc, fwevt); 196362306a36Sopenharmony_ci break; 196462306a36Sopenharmony_ci } 196562306a36Sopenharmony_ci case MPI3_EVENT_ENCL_DEVICE_ADDED: 196662306a36Sopenharmony_ci case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE: 196762306a36Sopenharmony_ci { 196862306a36Sopenharmony_ci mpi3mr_encldev_add_chg_evt_bh(mrioc, fwevt); 196962306a36Sopenharmony_ci break; 197062306a36Sopenharmony_ci } 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST: 197362306a36Sopenharmony_ci { 197462306a36Sopenharmony_ci mpi3mr_sastopochg_evt_bh(mrioc, fwevt); 197562306a36Sopenharmony_ci break; 197662306a36Sopenharmony_ci } 197762306a36Sopenharmony_ci case MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST: 197862306a36Sopenharmony_ci { 197962306a36Sopenharmony_ci mpi3mr_pcietopochg_evt_bh(mrioc, fwevt); 198062306a36Sopenharmony_ci break; 198162306a36Sopenharmony_ci } 198262306a36Sopenharmony_ci case MPI3_EVENT_LOG_DATA: 198362306a36Sopenharmony_ci { 198462306a36Sopenharmony_ci mpi3mr_logdata_evt_bh(mrioc, fwevt); 198562306a36Sopenharmony_ci break; 198662306a36Sopenharmony_ci } 198762306a36Sopenharmony_ci case MPI3MR_DRIVER_EVENT_TG_QD_REDUCTION: 198862306a36Sopenharmony_ci { 198962306a36Sopenharmony_ci struct mpi3mr_throttle_group_info *tg; 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_ci tg = *(struct mpi3mr_throttle_group_info **)fwevt->event_data; 199262306a36Sopenharmony_ci dprint_event_bh(mrioc, 199362306a36Sopenharmony_ci "qd reduction event processed for tg_id(%d) reduction_needed(%d)\n", 199462306a36Sopenharmony_ci tg->id, tg->need_qd_reduction); 199562306a36Sopenharmony_ci if (tg->need_qd_reduction) { 199662306a36Sopenharmony_ci mpi3mr_set_qd_for_all_vd_in_tg(mrioc, tg); 199762306a36Sopenharmony_ci tg->need_qd_reduction = 0; 199862306a36Sopenharmony_ci } 199962306a36Sopenharmony_ci break; 200062306a36Sopenharmony_ci } 200162306a36Sopenharmony_ci case MPI3_EVENT_WAIT_FOR_DEVICES_TO_REFRESH: 200262306a36Sopenharmony_ci { 200362306a36Sopenharmony_ci while (mrioc->device_refresh_on) 200462306a36Sopenharmony_ci msleep(500); 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_ci dprint_event_bh(mrioc, 200762306a36Sopenharmony_ci "scan for non responding and newly added devices after soft reset started\n"); 200862306a36Sopenharmony_ci if (mrioc->sas_transport_enabled) { 200962306a36Sopenharmony_ci mpi3mr_refresh_sas_ports(mrioc); 201062306a36Sopenharmony_ci mpi3mr_refresh_expanders(mrioc); 201162306a36Sopenharmony_ci } 201262306a36Sopenharmony_ci mpi3mr_rfresh_tgtdevs(mrioc); 201362306a36Sopenharmony_ci ioc_info(mrioc, 201462306a36Sopenharmony_ci "scan for non responding and newly added devices after soft reset completed\n"); 201562306a36Sopenharmony_ci break; 201662306a36Sopenharmony_ci } 201762306a36Sopenharmony_ci default: 201862306a36Sopenharmony_ci break; 201962306a36Sopenharmony_ci } 202062306a36Sopenharmony_ci 202162306a36Sopenharmony_cievt_ack: 202262306a36Sopenharmony_ci if (fwevt->send_ack) 202362306a36Sopenharmony_ci mpi3mr_process_event_ack(mrioc, fwevt->event_id, 202462306a36Sopenharmony_ci fwevt->evt_ctx); 202562306a36Sopenharmony_ciout: 202662306a36Sopenharmony_ci /* Put fwevt reference count to neutralize kref_init increment */ 202762306a36Sopenharmony_ci mpi3mr_fwevt_put(fwevt); 202862306a36Sopenharmony_ci mrioc->current_event = NULL; 202962306a36Sopenharmony_ci} 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci/** 203262306a36Sopenharmony_ci * mpi3mr_fwevt_worker - Firmware event worker 203362306a36Sopenharmony_ci * @work: Work struct containing firmware event 203462306a36Sopenharmony_ci * 203562306a36Sopenharmony_ci * Extracts the firmware event and calls mpi3mr_fwevt_bh. 203662306a36Sopenharmony_ci * 203762306a36Sopenharmony_ci * Return: Nothing. 203862306a36Sopenharmony_ci */ 203962306a36Sopenharmony_cistatic void mpi3mr_fwevt_worker(struct work_struct *work) 204062306a36Sopenharmony_ci{ 204162306a36Sopenharmony_ci struct mpi3mr_fwevt *fwevt = container_of(work, struct mpi3mr_fwevt, 204262306a36Sopenharmony_ci work); 204362306a36Sopenharmony_ci mpi3mr_fwevt_bh(fwevt->mrioc, fwevt); 204462306a36Sopenharmony_ci /* 204562306a36Sopenharmony_ci * Put fwevt reference count after 204662306a36Sopenharmony_ci * dequeuing it from worker queue 204762306a36Sopenharmony_ci */ 204862306a36Sopenharmony_ci mpi3mr_fwevt_put(fwevt); 204962306a36Sopenharmony_ci} 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci/** 205262306a36Sopenharmony_ci * mpi3mr_create_tgtdev - Create and add a target device 205362306a36Sopenharmony_ci * @mrioc: Adapter instance reference 205462306a36Sopenharmony_ci * @dev_pg0: Device Page 0 data 205562306a36Sopenharmony_ci * 205662306a36Sopenharmony_ci * If the device specified by the device page 0 data is not 205762306a36Sopenharmony_ci * present in the driver's internal list, allocate the memory 205862306a36Sopenharmony_ci * for the device, populate the data and add to the list, else 205962306a36Sopenharmony_ci * update the device data. The key is persistent ID. 206062306a36Sopenharmony_ci * 206162306a36Sopenharmony_ci * Return: 0 on success, -ENOMEM on memory allocation failure 206262306a36Sopenharmony_ci */ 206362306a36Sopenharmony_cistatic int mpi3mr_create_tgtdev(struct mpi3mr_ioc *mrioc, 206462306a36Sopenharmony_ci struct mpi3_device_page0 *dev_pg0) 206562306a36Sopenharmony_ci{ 206662306a36Sopenharmony_ci int retval = 0; 206762306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgtdev = NULL; 206862306a36Sopenharmony_ci u16 perst_id = 0; 206962306a36Sopenharmony_ci unsigned long flags; 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_ci perst_id = le16_to_cpu(dev_pg0->persistent_id); 207262306a36Sopenharmony_ci if (perst_id == MPI3_DEVICE0_PERSISTENTID_INVALID) 207362306a36Sopenharmony_ci return retval; 207462306a36Sopenharmony_ci 207562306a36Sopenharmony_ci spin_lock_irqsave(&mrioc->tgtdev_lock, flags); 207662306a36Sopenharmony_ci tgtdev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, perst_id); 207762306a36Sopenharmony_ci if (tgtdev) 207862306a36Sopenharmony_ci tgtdev->state = MPI3MR_DEV_CREATED; 207962306a36Sopenharmony_ci spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags); 208062306a36Sopenharmony_ci 208162306a36Sopenharmony_ci if (tgtdev) { 208262306a36Sopenharmony_ci mpi3mr_update_tgtdev(mrioc, tgtdev, dev_pg0, true); 208362306a36Sopenharmony_ci mpi3mr_tgtdev_put(tgtdev); 208462306a36Sopenharmony_ci } else { 208562306a36Sopenharmony_ci tgtdev = mpi3mr_alloc_tgtdev(); 208662306a36Sopenharmony_ci if (!tgtdev) 208762306a36Sopenharmony_ci return -ENOMEM; 208862306a36Sopenharmony_ci mpi3mr_update_tgtdev(mrioc, tgtdev, dev_pg0, true); 208962306a36Sopenharmony_ci mpi3mr_tgtdev_add_to_list(mrioc, tgtdev); 209062306a36Sopenharmony_ci } 209162306a36Sopenharmony_ci 209262306a36Sopenharmony_ci return retval; 209362306a36Sopenharmony_ci} 209462306a36Sopenharmony_ci 209562306a36Sopenharmony_ci/** 209662306a36Sopenharmony_ci * mpi3mr_flush_delayed_cmd_lists - Flush pending commands 209762306a36Sopenharmony_ci * @mrioc: Adapter instance reference 209862306a36Sopenharmony_ci * 209962306a36Sopenharmony_ci * Flush pending commands in the delayed lists due to a 210062306a36Sopenharmony_ci * controller reset or driver removal as a cleanup. 210162306a36Sopenharmony_ci * 210262306a36Sopenharmony_ci * Return: Nothing 210362306a36Sopenharmony_ci */ 210462306a36Sopenharmony_civoid mpi3mr_flush_delayed_cmd_lists(struct mpi3mr_ioc *mrioc) 210562306a36Sopenharmony_ci{ 210662306a36Sopenharmony_ci struct delayed_dev_rmhs_node *_rmhs_node; 210762306a36Sopenharmony_ci struct delayed_evt_ack_node *_evtack_node; 210862306a36Sopenharmony_ci 210962306a36Sopenharmony_ci dprint_reset(mrioc, "flushing delayed dev_remove_hs commands\n"); 211062306a36Sopenharmony_ci while (!list_empty(&mrioc->delayed_rmhs_list)) { 211162306a36Sopenharmony_ci _rmhs_node = list_entry(mrioc->delayed_rmhs_list.next, 211262306a36Sopenharmony_ci struct delayed_dev_rmhs_node, list); 211362306a36Sopenharmony_ci list_del(&_rmhs_node->list); 211462306a36Sopenharmony_ci kfree(_rmhs_node); 211562306a36Sopenharmony_ci } 211662306a36Sopenharmony_ci dprint_reset(mrioc, "flushing delayed event ack commands\n"); 211762306a36Sopenharmony_ci while (!list_empty(&mrioc->delayed_evtack_cmds_list)) { 211862306a36Sopenharmony_ci _evtack_node = list_entry(mrioc->delayed_evtack_cmds_list.next, 211962306a36Sopenharmony_ci struct delayed_evt_ack_node, list); 212062306a36Sopenharmony_ci list_del(&_evtack_node->list); 212162306a36Sopenharmony_ci kfree(_evtack_node); 212262306a36Sopenharmony_ci } 212362306a36Sopenharmony_ci} 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_ci/** 212662306a36Sopenharmony_ci * mpi3mr_dev_rmhs_complete_iou - Device removal IOUC completion 212762306a36Sopenharmony_ci * @mrioc: Adapter instance reference 212862306a36Sopenharmony_ci * @drv_cmd: Internal command tracker 212962306a36Sopenharmony_ci * 213062306a36Sopenharmony_ci * Issues a target reset TM to the firmware from the device 213162306a36Sopenharmony_ci * removal TM pend list or retry the removal handshake sequence 213262306a36Sopenharmony_ci * based on the IOU control request IOC status. 213362306a36Sopenharmony_ci * 213462306a36Sopenharmony_ci * Return: Nothing 213562306a36Sopenharmony_ci */ 213662306a36Sopenharmony_cistatic void mpi3mr_dev_rmhs_complete_iou(struct mpi3mr_ioc *mrioc, 213762306a36Sopenharmony_ci struct mpi3mr_drv_cmd *drv_cmd) 213862306a36Sopenharmony_ci{ 213962306a36Sopenharmony_ci u16 cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN; 214062306a36Sopenharmony_ci struct delayed_dev_rmhs_node *delayed_dev_rmhs = NULL; 214162306a36Sopenharmony_ci 214262306a36Sopenharmony_ci if (drv_cmd->state & MPI3MR_CMD_RESET) 214362306a36Sopenharmony_ci goto clear_drv_cmd; 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci ioc_info(mrioc, 214662306a36Sopenharmony_ci "%s :dev_rmhs_iouctrl_complete:handle(0x%04x), ioc_status(0x%04x), loginfo(0x%08x)\n", 214762306a36Sopenharmony_ci __func__, drv_cmd->dev_handle, drv_cmd->ioc_status, 214862306a36Sopenharmony_ci drv_cmd->ioc_loginfo); 214962306a36Sopenharmony_ci if (drv_cmd->ioc_status != MPI3_IOCSTATUS_SUCCESS) { 215062306a36Sopenharmony_ci if (drv_cmd->retry_count < MPI3MR_DEV_RMHS_RETRY_COUNT) { 215162306a36Sopenharmony_ci drv_cmd->retry_count++; 215262306a36Sopenharmony_ci ioc_info(mrioc, 215362306a36Sopenharmony_ci "%s :dev_rmhs_iouctrl_complete: handle(0x%04x)retrying handshake retry=%d\n", 215462306a36Sopenharmony_ci __func__, drv_cmd->dev_handle, 215562306a36Sopenharmony_ci drv_cmd->retry_count); 215662306a36Sopenharmony_ci mpi3mr_dev_rmhs_send_tm(mrioc, drv_cmd->dev_handle, 215762306a36Sopenharmony_ci drv_cmd, drv_cmd->iou_rc); 215862306a36Sopenharmony_ci return; 215962306a36Sopenharmony_ci } 216062306a36Sopenharmony_ci ioc_err(mrioc, 216162306a36Sopenharmony_ci "%s :dev removal handshake failed after all retries: handle(0x%04x)\n", 216262306a36Sopenharmony_ci __func__, drv_cmd->dev_handle); 216362306a36Sopenharmony_ci } else { 216462306a36Sopenharmony_ci ioc_info(mrioc, 216562306a36Sopenharmony_ci "%s :dev removal handshake completed successfully: handle(0x%04x)\n", 216662306a36Sopenharmony_ci __func__, drv_cmd->dev_handle); 216762306a36Sopenharmony_ci clear_bit(drv_cmd->dev_handle, mrioc->removepend_bitmap); 216862306a36Sopenharmony_ci } 216962306a36Sopenharmony_ci 217062306a36Sopenharmony_ci if (!list_empty(&mrioc->delayed_rmhs_list)) { 217162306a36Sopenharmony_ci delayed_dev_rmhs = list_entry(mrioc->delayed_rmhs_list.next, 217262306a36Sopenharmony_ci struct delayed_dev_rmhs_node, list); 217362306a36Sopenharmony_ci drv_cmd->dev_handle = delayed_dev_rmhs->handle; 217462306a36Sopenharmony_ci drv_cmd->retry_count = 0; 217562306a36Sopenharmony_ci drv_cmd->iou_rc = delayed_dev_rmhs->iou_rc; 217662306a36Sopenharmony_ci ioc_info(mrioc, 217762306a36Sopenharmony_ci "%s :dev_rmhs_iouctrl_complete: processing delayed TM: handle(0x%04x)\n", 217862306a36Sopenharmony_ci __func__, drv_cmd->dev_handle); 217962306a36Sopenharmony_ci mpi3mr_dev_rmhs_send_tm(mrioc, drv_cmd->dev_handle, drv_cmd, 218062306a36Sopenharmony_ci drv_cmd->iou_rc); 218162306a36Sopenharmony_ci list_del(&delayed_dev_rmhs->list); 218262306a36Sopenharmony_ci kfree(delayed_dev_rmhs); 218362306a36Sopenharmony_ci return; 218462306a36Sopenharmony_ci } 218562306a36Sopenharmony_ci 218662306a36Sopenharmony_ciclear_drv_cmd: 218762306a36Sopenharmony_ci drv_cmd->state = MPI3MR_CMD_NOTUSED; 218862306a36Sopenharmony_ci drv_cmd->callback = NULL; 218962306a36Sopenharmony_ci drv_cmd->retry_count = 0; 219062306a36Sopenharmony_ci drv_cmd->dev_handle = MPI3MR_INVALID_DEV_HANDLE; 219162306a36Sopenharmony_ci clear_bit(cmd_idx, mrioc->devrem_bitmap); 219262306a36Sopenharmony_ci} 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_ci/** 219562306a36Sopenharmony_ci * mpi3mr_dev_rmhs_complete_tm - Device removal TM completion 219662306a36Sopenharmony_ci * @mrioc: Adapter instance reference 219762306a36Sopenharmony_ci * @drv_cmd: Internal command tracker 219862306a36Sopenharmony_ci * 219962306a36Sopenharmony_ci * Issues a target reset TM to the firmware from the device 220062306a36Sopenharmony_ci * removal TM pend list or issue IO unit control request as 220162306a36Sopenharmony_ci * part of device removal or hidden acknowledgment handshake. 220262306a36Sopenharmony_ci * 220362306a36Sopenharmony_ci * Return: Nothing 220462306a36Sopenharmony_ci */ 220562306a36Sopenharmony_cistatic void mpi3mr_dev_rmhs_complete_tm(struct mpi3mr_ioc *mrioc, 220662306a36Sopenharmony_ci struct mpi3mr_drv_cmd *drv_cmd) 220762306a36Sopenharmony_ci{ 220862306a36Sopenharmony_ci struct mpi3_iounit_control_request iou_ctrl; 220962306a36Sopenharmony_ci u16 cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN; 221062306a36Sopenharmony_ci struct mpi3_scsi_task_mgmt_reply *tm_reply = NULL; 221162306a36Sopenharmony_ci int retval; 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci if (drv_cmd->state & MPI3MR_CMD_RESET) 221462306a36Sopenharmony_ci goto clear_drv_cmd; 221562306a36Sopenharmony_ci 221662306a36Sopenharmony_ci if (drv_cmd->state & MPI3MR_CMD_REPLY_VALID) 221762306a36Sopenharmony_ci tm_reply = (struct mpi3_scsi_task_mgmt_reply *)drv_cmd->reply; 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_ci if (tm_reply) 222062306a36Sopenharmony_ci pr_info(IOCNAME 222162306a36Sopenharmony_ci "dev_rmhs_tr_complete:handle(0x%04x), ioc_status(0x%04x), loginfo(0x%08x), term_count(%d)\n", 222262306a36Sopenharmony_ci mrioc->name, drv_cmd->dev_handle, drv_cmd->ioc_status, 222362306a36Sopenharmony_ci drv_cmd->ioc_loginfo, 222462306a36Sopenharmony_ci le32_to_cpu(tm_reply->termination_count)); 222562306a36Sopenharmony_ci 222662306a36Sopenharmony_ci pr_info(IOCNAME "Issuing IOU CTL: handle(0x%04x) dev_rmhs idx(%d)\n", 222762306a36Sopenharmony_ci mrioc->name, drv_cmd->dev_handle, cmd_idx); 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ci memset(&iou_ctrl, 0, sizeof(iou_ctrl)); 223062306a36Sopenharmony_ci 223162306a36Sopenharmony_ci drv_cmd->state = MPI3MR_CMD_PENDING; 223262306a36Sopenharmony_ci drv_cmd->is_waiting = 0; 223362306a36Sopenharmony_ci drv_cmd->callback = mpi3mr_dev_rmhs_complete_iou; 223462306a36Sopenharmony_ci iou_ctrl.operation = drv_cmd->iou_rc; 223562306a36Sopenharmony_ci iou_ctrl.param16[0] = cpu_to_le16(drv_cmd->dev_handle); 223662306a36Sopenharmony_ci iou_ctrl.host_tag = cpu_to_le16(drv_cmd->host_tag); 223762306a36Sopenharmony_ci iou_ctrl.function = MPI3_FUNCTION_IO_UNIT_CONTROL; 223862306a36Sopenharmony_ci 223962306a36Sopenharmony_ci retval = mpi3mr_admin_request_post(mrioc, &iou_ctrl, sizeof(iou_ctrl), 224062306a36Sopenharmony_ci 1); 224162306a36Sopenharmony_ci if (retval) { 224262306a36Sopenharmony_ci pr_err(IOCNAME "Issue DevRmHsTMIOUCTL: Admin post failed\n", 224362306a36Sopenharmony_ci mrioc->name); 224462306a36Sopenharmony_ci goto clear_drv_cmd; 224562306a36Sopenharmony_ci } 224662306a36Sopenharmony_ci 224762306a36Sopenharmony_ci return; 224862306a36Sopenharmony_ciclear_drv_cmd: 224962306a36Sopenharmony_ci drv_cmd->state = MPI3MR_CMD_NOTUSED; 225062306a36Sopenharmony_ci drv_cmd->callback = NULL; 225162306a36Sopenharmony_ci drv_cmd->dev_handle = MPI3MR_INVALID_DEV_HANDLE; 225262306a36Sopenharmony_ci drv_cmd->retry_count = 0; 225362306a36Sopenharmony_ci clear_bit(cmd_idx, mrioc->devrem_bitmap); 225462306a36Sopenharmony_ci} 225562306a36Sopenharmony_ci 225662306a36Sopenharmony_ci/** 225762306a36Sopenharmony_ci * mpi3mr_dev_rmhs_send_tm - Issue TM for device removal 225862306a36Sopenharmony_ci * @mrioc: Adapter instance reference 225962306a36Sopenharmony_ci * @handle: Device handle 226062306a36Sopenharmony_ci * @cmdparam: Internal command tracker 226162306a36Sopenharmony_ci * @iou_rc: IO unit reason code 226262306a36Sopenharmony_ci * 226362306a36Sopenharmony_ci * Issues a target reset TM to the firmware or add it to a pend 226462306a36Sopenharmony_ci * list as part of device removal or hidden acknowledgment 226562306a36Sopenharmony_ci * handshake. 226662306a36Sopenharmony_ci * 226762306a36Sopenharmony_ci * Return: Nothing 226862306a36Sopenharmony_ci */ 226962306a36Sopenharmony_cistatic void mpi3mr_dev_rmhs_send_tm(struct mpi3mr_ioc *mrioc, u16 handle, 227062306a36Sopenharmony_ci struct mpi3mr_drv_cmd *cmdparam, u8 iou_rc) 227162306a36Sopenharmony_ci{ 227262306a36Sopenharmony_ci struct mpi3_scsi_task_mgmt_request tm_req; 227362306a36Sopenharmony_ci int retval = 0; 227462306a36Sopenharmony_ci u16 cmd_idx = MPI3MR_NUM_DEVRMCMD; 227562306a36Sopenharmony_ci u8 retrycount = 5; 227662306a36Sopenharmony_ci struct mpi3mr_drv_cmd *drv_cmd = cmdparam; 227762306a36Sopenharmony_ci struct delayed_dev_rmhs_node *delayed_dev_rmhs = NULL; 227862306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgtdev = NULL; 227962306a36Sopenharmony_ci unsigned long flags; 228062306a36Sopenharmony_ci 228162306a36Sopenharmony_ci spin_lock_irqsave(&mrioc->tgtdev_lock, flags); 228262306a36Sopenharmony_ci tgtdev = __mpi3mr_get_tgtdev_by_handle(mrioc, handle); 228362306a36Sopenharmony_ci if (tgtdev && (iou_rc == MPI3_CTRL_OP_REMOVE_DEVICE)) 228462306a36Sopenharmony_ci tgtdev->state = MPI3MR_DEV_REMOVE_HS_STARTED; 228562306a36Sopenharmony_ci spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags); 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_ci if (drv_cmd) 228862306a36Sopenharmony_ci goto issue_cmd; 228962306a36Sopenharmony_ci do { 229062306a36Sopenharmony_ci cmd_idx = find_first_zero_bit(mrioc->devrem_bitmap, 229162306a36Sopenharmony_ci MPI3MR_NUM_DEVRMCMD); 229262306a36Sopenharmony_ci if (cmd_idx < MPI3MR_NUM_DEVRMCMD) { 229362306a36Sopenharmony_ci if (!test_and_set_bit(cmd_idx, mrioc->devrem_bitmap)) 229462306a36Sopenharmony_ci break; 229562306a36Sopenharmony_ci cmd_idx = MPI3MR_NUM_DEVRMCMD; 229662306a36Sopenharmony_ci } 229762306a36Sopenharmony_ci } while (retrycount--); 229862306a36Sopenharmony_ci 229962306a36Sopenharmony_ci if (cmd_idx >= MPI3MR_NUM_DEVRMCMD) { 230062306a36Sopenharmony_ci delayed_dev_rmhs = kzalloc(sizeof(*delayed_dev_rmhs), 230162306a36Sopenharmony_ci GFP_ATOMIC); 230262306a36Sopenharmony_ci if (!delayed_dev_rmhs) 230362306a36Sopenharmony_ci return; 230462306a36Sopenharmony_ci INIT_LIST_HEAD(&delayed_dev_rmhs->list); 230562306a36Sopenharmony_ci delayed_dev_rmhs->handle = handle; 230662306a36Sopenharmony_ci delayed_dev_rmhs->iou_rc = iou_rc; 230762306a36Sopenharmony_ci list_add_tail(&delayed_dev_rmhs->list, 230862306a36Sopenharmony_ci &mrioc->delayed_rmhs_list); 230962306a36Sopenharmony_ci ioc_info(mrioc, "%s :DevRmHs: tr:handle(0x%04x) is postponed\n", 231062306a36Sopenharmony_ci __func__, handle); 231162306a36Sopenharmony_ci return; 231262306a36Sopenharmony_ci } 231362306a36Sopenharmony_ci drv_cmd = &mrioc->dev_rmhs_cmds[cmd_idx]; 231462306a36Sopenharmony_ci 231562306a36Sopenharmony_ciissue_cmd: 231662306a36Sopenharmony_ci cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN; 231762306a36Sopenharmony_ci ioc_info(mrioc, 231862306a36Sopenharmony_ci "%s :Issuing TR TM: for devhandle 0x%04x with dev_rmhs %d\n", 231962306a36Sopenharmony_ci __func__, handle, cmd_idx); 232062306a36Sopenharmony_ci 232162306a36Sopenharmony_ci memset(&tm_req, 0, sizeof(tm_req)); 232262306a36Sopenharmony_ci if (drv_cmd->state & MPI3MR_CMD_PENDING) { 232362306a36Sopenharmony_ci ioc_err(mrioc, "%s :Issue TM: Command is in use\n", __func__); 232462306a36Sopenharmony_ci goto out; 232562306a36Sopenharmony_ci } 232662306a36Sopenharmony_ci drv_cmd->state = MPI3MR_CMD_PENDING; 232762306a36Sopenharmony_ci drv_cmd->is_waiting = 0; 232862306a36Sopenharmony_ci drv_cmd->callback = mpi3mr_dev_rmhs_complete_tm; 232962306a36Sopenharmony_ci drv_cmd->dev_handle = handle; 233062306a36Sopenharmony_ci drv_cmd->iou_rc = iou_rc; 233162306a36Sopenharmony_ci tm_req.dev_handle = cpu_to_le16(handle); 233262306a36Sopenharmony_ci tm_req.task_type = MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET; 233362306a36Sopenharmony_ci tm_req.host_tag = cpu_to_le16(drv_cmd->host_tag); 233462306a36Sopenharmony_ci tm_req.task_host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INVALID); 233562306a36Sopenharmony_ci tm_req.function = MPI3_FUNCTION_SCSI_TASK_MGMT; 233662306a36Sopenharmony_ci 233762306a36Sopenharmony_ci set_bit(handle, mrioc->removepend_bitmap); 233862306a36Sopenharmony_ci retval = mpi3mr_admin_request_post(mrioc, &tm_req, sizeof(tm_req), 1); 233962306a36Sopenharmony_ci if (retval) { 234062306a36Sopenharmony_ci ioc_err(mrioc, "%s :Issue DevRmHsTM: Admin Post failed\n", 234162306a36Sopenharmony_ci __func__); 234262306a36Sopenharmony_ci goto out_failed; 234362306a36Sopenharmony_ci } 234462306a36Sopenharmony_ciout: 234562306a36Sopenharmony_ci return; 234662306a36Sopenharmony_ciout_failed: 234762306a36Sopenharmony_ci drv_cmd->state = MPI3MR_CMD_NOTUSED; 234862306a36Sopenharmony_ci drv_cmd->callback = NULL; 234962306a36Sopenharmony_ci drv_cmd->dev_handle = MPI3MR_INVALID_DEV_HANDLE; 235062306a36Sopenharmony_ci drv_cmd->retry_count = 0; 235162306a36Sopenharmony_ci clear_bit(cmd_idx, mrioc->devrem_bitmap); 235262306a36Sopenharmony_ci} 235362306a36Sopenharmony_ci 235462306a36Sopenharmony_ci/** 235562306a36Sopenharmony_ci * mpi3mr_complete_evt_ack - event ack request completion 235662306a36Sopenharmony_ci * @mrioc: Adapter instance reference 235762306a36Sopenharmony_ci * @drv_cmd: Internal command tracker 235862306a36Sopenharmony_ci * 235962306a36Sopenharmony_ci * This is the completion handler for non blocking event 236062306a36Sopenharmony_ci * acknowledgment sent to the firmware and this will issue any 236162306a36Sopenharmony_ci * pending event acknowledgment request. 236262306a36Sopenharmony_ci * 236362306a36Sopenharmony_ci * Return: Nothing 236462306a36Sopenharmony_ci */ 236562306a36Sopenharmony_cistatic void mpi3mr_complete_evt_ack(struct mpi3mr_ioc *mrioc, 236662306a36Sopenharmony_ci struct mpi3mr_drv_cmd *drv_cmd) 236762306a36Sopenharmony_ci{ 236862306a36Sopenharmony_ci u16 cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_EVTACKCMD_MIN; 236962306a36Sopenharmony_ci struct delayed_evt_ack_node *delayed_evtack = NULL; 237062306a36Sopenharmony_ci 237162306a36Sopenharmony_ci if (drv_cmd->state & MPI3MR_CMD_RESET) 237262306a36Sopenharmony_ci goto clear_drv_cmd; 237362306a36Sopenharmony_ci 237462306a36Sopenharmony_ci if (drv_cmd->ioc_status != MPI3_IOCSTATUS_SUCCESS) { 237562306a36Sopenharmony_ci dprint_event_th(mrioc, 237662306a36Sopenharmony_ci "immediate event ack failed with ioc_status(0x%04x) log_info(0x%08x)\n", 237762306a36Sopenharmony_ci (drv_cmd->ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 237862306a36Sopenharmony_ci drv_cmd->ioc_loginfo); 237962306a36Sopenharmony_ci } 238062306a36Sopenharmony_ci 238162306a36Sopenharmony_ci if (!list_empty(&mrioc->delayed_evtack_cmds_list)) { 238262306a36Sopenharmony_ci delayed_evtack = 238362306a36Sopenharmony_ci list_entry(mrioc->delayed_evtack_cmds_list.next, 238462306a36Sopenharmony_ci struct delayed_evt_ack_node, list); 238562306a36Sopenharmony_ci mpi3mr_send_event_ack(mrioc, delayed_evtack->event, drv_cmd, 238662306a36Sopenharmony_ci delayed_evtack->event_ctx); 238762306a36Sopenharmony_ci list_del(&delayed_evtack->list); 238862306a36Sopenharmony_ci kfree(delayed_evtack); 238962306a36Sopenharmony_ci return; 239062306a36Sopenharmony_ci } 239162306a36Sopenharmony_ciclear_drv_cmd: 239262306a36Sopenharmony_ci drv_cmd->state = MPI3MR_CMD_NOTUSED; 239362306a36Sopenharmony_ci drv_cmd->callback = NULL; 239462306a36Sopenharmony_ci clear_bit(cmd_idx, mrioc->evtack_cmds_bitmap); 239562306a36Sopenharmony_ci} 239662306a36Sopenharmony_ci 239762306a36Sopenharmony_ci/** 239862306a36Sopenharmony_ci * mpi3mr_send_event_ack - Issue event acknwoledgment request 239962306a36Sopenharmony_ci * @mrioc: Adapter instance reference 240062306a36Sopenharmony_ci * @event: MPI3 event id 240162306a36Sopenharmony_ci * @cmdparam: Internal command tracker 240262306a36Sopenharmony_ci * @event_ctx: event context 240362306a36Sopenharmony_ci * 240462306a36Sopenharmony_ci * Issues event acknowledgment request to the firmware if there 240562306a36Sopenharmony_ci * is a free command to send the event ack else it to a pend 240662306a36Sopenharmony_ci * list so that it will be processed on a completion of a prior 240762306a36Sopenharmony_ci * event acknowledgment . 240862306a36Sopenharmony_ci * 240962306a36Sopenharmony_ci * Return: Nothing 241062306a36Sopenharmony_ci */ 241162306a36Sopenharmony_cistatic void mpi3mr_send_event_ack(struct mpi3mr_ioc *mrioc, u8 event, 241262306a36Sopenharmony_ci struct mpi3mr_drv_cmd *cmdparam, u32 event_ctx) 241362306a36Sopenharmony_ci{ 241462306a36Sopenharmony_ci struct mpi3_event_ack_request evtack_req; 241562306a36Sopenharmony_ci int retval = 0; 241662306a36Sopenharmony_ci u8 retrycount = 5; 241762306a36Sopenharmony_ci u16 cmd_idx = MPI3MR_NUM_EVTACKCMD; 241862306a36Sopenharmony_ci struct mpi3mr_drv_cmd *drv_cmd = cmdparam; 241962306a36Sopenharmony_ci struct delayed_evt_ack_node *delayed_evtack = NULL; 242062306a36Sopenharmony_ci 242162306a36Sopenharmony_ci if (drv_cmd) { 242262306a36Sopenharmony_ci dprint_event_th(mrioc, 242362306a36Sopenharmony_ci "sending delayed event ack in the top half for event(0x%02x), event_ctx(0x%08x)\n", 242462306a36Sopenharmony_ci event, event_ctx); 242562306a36Sopenharmony_ci goto issue_cmd; 242662306a36Sopenharmony_ci } 242762306a36Sopenharmony_ci dprint_event_th(mrioc, 242862306a36Sopenharmony_ci "sending event ack in the top half for event(0x%02x), event_ctx(0x%08x)\n", 242962306a36Sopenharmony_ci event, event_ctx); 243062306a36Sopenharmony_ci do { 243162306a36Sopenharmony_ci cmd_idx = find_first_zero_bit(mrioc->evtack_cmds_bitmap, 243262306a36Sopenharmony_ci MPI3MR_NUM_EVTACKCMD); 243362306a36Sopenharmony_ci if (cmd_idx < MPI3MR_NUM_EVTACKCMD) { 243462306a36Sopenharmony_ci if (!test_and_set_bit(cmd_idx, 243562306a36Sopenharmony_ci mrioc->evtack_cmds_bitmap)) 243662306a36Sopenharmony_ci break; 243762306a36Sopenharmony_ci cmd_idx = MPI3MR_NUM_EVTACKCMD; 243862306a36Sopenharmony_ci } 243962306a36Sopenharmony_ci } while (retrycount--); 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_ci if (cmd_idx >= MPI3MR_NUM_EVTACKCMD) { 244262306a36Sopenharmony_ci delayed_evtack = kzalloc(sizeof(*delayed_evtack), 244362306a36Sopenharmony_ci GFP_ATOMIC); 244462306a36Sopenharmony_ci if (!delayed_evtack) 244562306a36Sopenharmony_ci return; 244662306a36Sopenharmony_ci INIT_LIST_HEAD(&delayed_evtack->list); 244762306a36Sopenharmony_ci delayed_evtack->event = event; 244862306a36Sopenharmony_ci delayed_evtack->event_ctx = event_ctx; 244962306a36Sopenharmony_ci list_add_tail(&delayed_evtack->list, 245062306a36Sopenharmony_ci &mrioc->delayed_evtack_cmds_list); 245162306a36Sopenharmony_ci dprint_event_th(mrioc, 245262306a36Sopenharmony_ci "event ack in the top half for event(0x%02x), event_ctx(0x%08x) is postponed\n", 245362306a36Sopenharmony_ci event, event_ctx); 245462306a36Sopenharmony_ci return; 245562306a36Sopenharmony_ci } 245662306a36Sopenharmony_ci drv_cmd = &mrioc->evtack_cmds[cmd_idx]; 245762306a36Sopenharmony_ci 245862306a36Sopenharmony_ciissue_cmd: 245962306a36Sopenharmony_ci cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_EVTACKCMD_MIN; 246062306a36Sopenharmony_ci 246162306a36Sopenharmony_ci memset(&evtack_req, 0, sizeof(evtack_req)); 246262306a36Sopenharmony_ci if (drv_cmd->state & MPI3MR_CMD_PENDING) { 246362306a36Sopenharmony_ci dprint_event_th(mrioc, 246462306a36Sopenharmony_ci "sending event ack failed due to command in use\n"); 246562306a36Sopenharmony_ci goto out; 246662306a36Sopenharmony_ci } 246762306a36Sopenharmony_ci drv_cmd->state = MPI3MR_CMD_PENDING; 246862306a36Sopenharmony_ci drv_cmd->is_waiting = 0; 246962306a36Sopenharmony_ci drv_cmd->callback = mpi3mr_complete_evt_ack; 247062306a36Sopenharmony_ci evtack_req.host_tag = cpu_to_le16(drv_cmd->host_tag); 247162306a36Sopenharmony_ci evtack_req.function = MPI3_FUNCTION_EVENT_ACK; 247262306a36Sopenharmony_ci evtack_req.event = event; 247362306a36Sopenharmony_ci evtack_req.event_context = cpu_to_le32(event_ctx); 247462306a36Sopenharmony_ci retval = mpi3mr_admin_request_post(mrioc, &evtack_req, 247562306a36Sopenharmony_ci sizeof(evtack_req), 1); 247662306a36Sopenharmony_ci if (retval) { 247762306a36Sopenharmony_ci dprint_event_th(mrioc, 247862306a36Sopenharmony_ci "posting event ack request is failed\n"); 247962306a36Sopenharmony_ci goto out_failed; 248062306a36Sopenharmony_ci } 248162306a36Sopenharmony_ci 248262306a36Sopenharmony_ci dprint_event_th(mrioc, 248362306a36Sopenharmony_ci "event ack in the top half for event(0x%02x), event_ctx(0x%08x) is posted\n", 248462306a36Sopenharmony_ci event, event_ctx); 248562306a36Sopenharmony_ciout: 248662306a36Sopenharmony_ci return; 248762306a36Sopenharmony_ciout_failed: 248862306a36Sopenharmony_ci drv_cmd->state = MPI3MR_CMD_NOTUSED; 248962306a36Sopenharmony_ci drv_cmd->callback = NULL; 249062306a36Sopenharmony_ci clear_bit(cmd_idx, mrioc->evtack_cmds_bitmap); 249162306a36Sopenharmony_ci} 249262306a36Sopenharmony_ci 249362306a36Sopenharmony_ci/** 249462306a36Sopenharmony_ci * mpi3mr_pcietopochg_evt_th - PCIETopologyChange evt tophalf 249562306a36Sopenharmony_ci * @mrioc: Adapter instance reference 249662306a36Sopenharmony_ci * @event_reply: event data 249762306a36Sopenharmony_ci * 249862306a36Sopenharmony_ci * Checks for the reason code and based on that either block I/O 249962306a36Sopenharmony_ci * to device, or unblock I/O to the device, or start the device 250062306a36Sopenharmony_ci * removal handshake with reason as remove with the firmware for 250162306a36Sopenharmony_ci * PCIe devices. 250262306a36Sopenharmony_ci * 250362306a36Sopenharmony_ci * Return: Nothing 250462306a36Sopenharmony_ci */ 250562306a36Sopenharmony_cistatic void mpi3mr_pcietopochg_evt_th(struct mpi3mr_ioc *mrioc, 250662306a36Sopenharmony_ci struct mpi3_event_notification_reply *event_reply) 250762306a36Sopenharmony_ci{ 250862306a36Sopenharmony_ci struct mpi3_event_data_pcie_topology_change_list *topo_evt = 250962306a36Sopenharmony_ci (struct mpi3_event_data_pcie_topology_change_list *)event_reply->event_data; 251062306a36Sopenharmony_ci int i; 251162306a36Sopenharmony_ci u16 handle; 251262306a36Sopenharmony_ci u8 reason_code; 251362306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgtdev = NULL; 251462306a36Sopenharmony_ci struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data = NULL; 251562306a36Sopenharmony_ci 251662306a36Sopenharmony_ci for (i = 0; i < topo_evt->num_entries; i++) { 251762306a36Sopenharmony_ci handle = le16_to_cpu(topo_evt->port_entry[i].attached_dev_handle); 251862306a36Sopenharmony_ci if (!handle) 251962306a36Sopenharmony_ci continue; 252062306a36Sopenharmony_ci reason_code = topo_evt->port_entry[i].port_status; 252162306a36Sopenharmony_ci scsi_tgt_priv_data = NULL; 252262306a36Sopenharmony_ci tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, handle); 252362306a36Sopenharmony_ci if (tgtdev && tgtdev->starget && tgtdev->starget->hostdata) 252462306a36Sopenharmony_ci scsi_tgt_priv_data = (struct mpi3mr_stgt_priv_data *) 252562306a36Sopenharmony_ci tgtdev->starget->hostdata; 252662306a36Sopenharmony_ci switch (reason_code) { 252762306a36Sopenharmony_ci case MPI3_EVENT_PCIE_TOPO_PS_NOT_RESPONDING: 252862306a36Sopenharmony_ci if (scsi_tgt_priv_data) { 252962306a36Sopenharmony_ci scsi_tgt_priv_data->dev_removed = 1; 253062306a36Sopenharmony_ci scsi_tgt_priv_data->dev_removedelay = 0; 253162306a36Sopenharmony_ci atomic_set(&scsi_tgt_priv_data->block_io, 0); 253262306a36Sopenharmony_ci } 253362306a36Sopenharmony_ci mpi3mr_dev_rmhs_send_tm(mrioc, handle, NULL, 253462306a36Sopenharmony_ci MPI3_CTRL_OP_REMOVE_DEVICE); 253562306a36Sopenharmony_ci break; 253662306a36Sopenharmony_ci case MPI3_EVENT_PCIE_TOPO_PS_DELAY_NOT_RESPONDING: 253762306a36Sopenharmony_ci if (scsi_tgt_priv_data) { 253862306a36Sopenharmony_ci scsi_tgt_priv_data->dev_removedelay = 1; 253962306a36Sopenharmony_ci atomic_inc(&scsi_tgt_priv_data->block_io); 254062306a36Sopenharmony_ci } 254162306a36Sopenharmony_ci break; 254262306a36Sopenharmony_ci case MPI3_EVENT_PCIE_TOPO_PS_RESPONDING: 254362306a36Sopenharmony_ci if (scsi_tgt_priv_data && 254462306a36Sopenharmony_ci scsi_tgt_priv_data->dev_removedelay) { 254562306a36Sopenharmony_ci scsi_tgt_priv_data->dev_removedelay = 0; 254662306a36Sopenharmony_ci atomic_dec_if_positive 254762306a36Sopenharmony_ci (&scsi_tgt_priv_data->block_io); 254862306a36Sopenharmony_ci } 254962306a36Sopenharmony_ci break; 255062306a36Sopenharmony_ci case MPI3_EVENT_PCIE_TOPO_PS_PORT_CHANGED: 255162306a36Sopenharmony_ci default: 255262306a36Sopenharmony_ci break; 255362306a36Sopenharmony_ci } 255462306a36Sopenharmony_ci if (tgtdev) 255562306a36Sopenharmony_ci mpi3mr_tgtdev_put(tgtdev); 255662306a36Sopenharmony_ci } 255762306a36Sopenharmony_ci} 255862306a36Sopenharmony_ci 255962306a36Sopenharmony_ci/** 256062306a36Sopenharmony_ci * mpi3mr_sastopochg_evt_th - SASTopologyChange evt tophalf 256162306a36Sopenharmony_ci * @mrioc: Adapter instance reference 256262306a36Sopenharmony_ci * @event_reply: event data 256362306a36Sopenharmony_ci * 256462306a36Sopenharmony_ci * Checks for the reason code and based on that either block I/O 256562306a36Sopenharmony_ci * to device, or unblock I/O to the device, or start the device 256662306a36Sopenharmony_ci * removal handshake with reason as remove with the firmware for 256762306a36Sopenharmony_ci * SAS/SATA devices. 256862306a36Sopenharmony_ci * 256962306a36Sopenharmony_ci * Return: Nothing 257062306a36Sopenharmony_ci */ 257162306a36Sopenharmony_cistatic void mpi3mr_sastopochg_evt_th(struct mpi3mr_ioc *mrioc, 257262306a36Sopenharmony_ci struct mpi3_event_notification_reply *event_reply) 257362306a36Sopenharmony_ci{ 257462306a36Sopenharmony_ci struct mpi3_event_data_sas_topology_change_list *topo_evt = 257562306a36Sopenharmony_ci (struct mpi3_event_data_sas_topology_change_list *)event_reply->event_data; 257662306a36Sopenharmony_ci int i; 257762306a36Sopenharmony_ci u16 handle; 257862306a36Sopenharmony_ci u8 reason_code; 257962306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgtdev = NULL; 258062306a36Sopenharmony_ci struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data = NULL; 258162306a36Sopenharmony_ci 258262306a36Sopenharmony_ci for (i = 0; i < topo_evt->num_entries; i++) { 258362306a36Sopenharmony_ci handle = le16_to_cpu(topo_evt->phy_entry[i].attached_dev_handle); 258462306a36Sopenharmony_ci if (!handle) 258562306a36Sopenharmony_ci continue; 258662306a36Sopenharmony_ci reason_code = topo_evt->phy_entry[i].status & 258762306a36Sopenharmony_ci MPI3_EVENT_SAS_TOPO_PHY_RC_MASK; 258862306a36Sopenharmony_ci scsi_tgt_priv_data = NULL; 258962306a36Sopenharmony_ci tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, handle); 259062306a36Sopenharmony_ci if (tgtdev && tgtdev->starget && tgtdev->starget->hostdata) 259162306a36Sopenharmony_ci scsi_tgt_priv_data = (struct mpi3mr_stgt_priv_data *) 259262306a36Sopenharmony_ci tgtdev->starget->hostdata; 259362306a36Sopenharmony_ci switch (reason_code) { 259462306a36Sopenharmony_ci case MPI3_EVENT_SAS_TOPO_PHY_RC_TARG_NOT_RESPONDING: 259562306a36Sopenharmony_ci if (scsi_tgt_priv_data) { 259662306a36Sopenharmony_ci scsi_tgt_priv_data->dev_removed = 1; 259762306a36Sopenharmony_ci scsi_tgt_priv_data->dev_removedelay = 0; 259862306a36Sopenharmony_ci atomic_set(&scsi_tgt_priv_data->block_io, 0); 259962306a36Sopenharmony_ci } 260062306a36Sopenharmony_ci mpi3mr_dev_rmhs_send_tm(mrioc, handle, NULL, 260162306a36Sopenharmony_ci MPI3_CTRL_OP_REMOVE_DEVICE); 260262306a36Sopenharmony_ci break; 260362306a36Sopenharmony_ci case MPI3_EVENT_SAS_TOPO_PHY_RC_DELAY_NOT_RESPONDING: 260462306a36Sopenharmony_ci if (scsi_tgt_priv_data) { 260562306a36Sopenharmony_ci scsi_tgt_priv_data->dev_removedelay = 1; 260662306a36Sopenharmony_ci atomic_inc(&scsi_tgt_priv_data->block_io); 260762306a36Sopenharmony_ci } 260862306a36Sopenharmony_ci break; 260962306a36Sopenharmony_ci case MPI3_EVENT_SAS_TOPO_PHY_RC_RESPONDING: 261062306a36Sopenharmony_ci if (scsi_tgt_priv_data && 261162306a36Sopenharmony_ci scsi_tgt_priv_data->dev_removedelay) { 261262306a36Sopenharmony_ci scsi_tgt_priv_data->dev_removedelay = 0; 261362306a36Sopenharmony_ci atomic_dec_if_positive 261462306a36Sopenharmony_ci (&scsi_tgt_priv_data->block_io); 261562306a36Sopenharmony_ci } 261662306a36Sopenharmony_ci break; 261762306a36Sopenharmony_ci case MPI3_EVENT_SAS_TOPO_PHY_RC_PHY_CHANGED: 261862306a36Sopenharmony_ci default: 261962306a36Sopenharmony_ci break; 262062306a36Sopenharmony_ci } 262162306a36Sopenharmony_ci if (tgtdev) 262262306a36Sopenharmony_ci mpi3mr_tgtdev_put(tgtdev); 262362306a36Sopenharmony_ci } 262462306a36Sopenharmony_ci} 262562306a36Sopenharmony_ci 262662306a36Sopenharmony_ci/** 262762306a36Sopenharmony_ci * mpi3mr_devstatuschg_evt_th - DeviceStatusChange evt tophalf 262862306a36Sopenharmony_ci * @mrioc: Adapter instance reference 262962306a36Sopenharmony_ci * @event_reply: event data 263062306a36Sopenharmony_ci * 263162306a36Sopenharmony_ci * Checks for the reason code and based on that either block I/O 263262306a36Sopenharmony_ci * to device, or unblock I/O to the device, or start the device 263362306a36Sopenharmony_ci * removal handshake with reason as remove/hide acknowledgment 263462306a36Sopenharmony_ci * with the firmware. 263562306a36Sopenharmony_ci * 263662306a36Sopenharmony_ci * Return: Nothing 263762306a36Sopenharmony_ci */ 263862306a36Sopenharmony_cistatic void mpi3mr_devstatuschg_evt_th(struct mpi3mr_ioc *mrioc, 263962306a36Sopenharmony_ci struct mpi3_event_notification_reply *event_reply) 264062306a36Sopenharmony_ci{ 264162306a36Sopenharmony_ci u16 dev_handle = 0; 264262306a36Sopenharmony_ci u8 ublock = 0, block = 0, hide = 0, delete = 0, remove = 0; 264362306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgtdev = NULL; 264462306a36Sopenharmony_ci struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data = NULL; 264562306a36Sopenharmony_ci struct mpi3_event_data_device_status_change *evtdata = 264662306a36Sopenharmony_ci (struct mpi3_event_data_device_status_change *)event_reply->event_data; 264762306a36Sopenharmony_ci 264862306a36Sopenharmony_ci if (mrioc->stop_drv_processing) 264962306a36Sopenharmony_ci goto out; 265062306a36Sopenharmony_ci 265162306a36Sopenharmony_ci dev_handle = le16_to_cpu(evtdata->dev_handle); 265262306a36Sopenharmony_ci 265362306a36Sopenharmony_ci switch (evtdata->reason_code) { 265462306a36Sopenharmony_ci case MPI3_EVENT_DEV_STAT_RC_INT_DEVICE_RESET_STRT: 265562306a36Sopenharmony_ci case MPI3_EVENT_DEV_STAT_RC_INT_IT_NEXUS_RESET_STRT: 265662306a36Sopenharmony_ci block = 1; 265762306a36Sopenharmony_ci break; 265862306a36Sopenharmony_ci case MPI3_EVENT_DEV_STAT_RC_HIDDEN: 265962306a36Sopenharmony_ci delete = 1; 266062306a36Sopenharmony_ci hide = 1; 266162306a36Sopenharmony_ci break; 266262306a36Sopenharmony_ci case MPI3_EVENT_DEV_STAT_RC_VD_NOT_RESPONDING: 266362306a36Sopenharmony_ci delete = 1; 266462306a36Sopenharmony_ci remove = 1; 266562306a36Sopenharmony_ci break; 266662306a36Sopenharmony_ci case MPI3_EVENT_DEV_STAT_RC_INT_DEVICE_RESET_CMP: 266762306a36Sopenharmony_ci case MPI3_EVENT_DEV_STAT_RC_INT_IT_NEXUS_RESET_CMP: 266862306a36Sopenharmony_ci ublock = 1; 266962306a36Sopenharmony_ci break; 267062306a36Sopenharmony_ci default: 267162306a36Sopenharmony_ci break; 267262306a36Sopenharmony_ci } 267362306a36Sopenharmony_ci 267462306a36Sopenharmony_ci tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle); 267562306a36Sopenharmony_ci if (!tgtdev) 267662306a36Sopenharmony_ci goto out; 267762306a36Sopenharmony_ci if (hide) 267862306a36Sopenharmony_ci tgtdev->is_hidden = hide; 267962306a36Sopenharmony_ci if (tgtdev->starget && tgtdev->starget->hostdata) { 268062306a36Sopenharmony_ci scsi_tgt_priv_data = (struct mpi3mr_stgt_priv_data *) 268162306a36Sopenharmony_ci tgtdev->starget->hostdata; 268262306a36Sopenharmony_ci if (block) 268362306a36Sopenharmony_ci atomic_inc(&scsi_tgt_priv_data->block_io); 268462306a36Sopenharmony_ci if (delete) 268562306a36Sopenharmony_ci scsi_tgt_priv_data->dev_removed = 1; 268662306a36Sopenharmony_ci if (ublock) 268762306a36Sopenharmony_ci atomic_dec_if_positive(&scsi_tgt_priv_data->block_io); 268862306a36Sopenharmony_ci } 268962306a36Sopenharmony_ci if (remove) 269062306a36Sopenharmony_ci mpi3mr_dev_rmhs_send_tm(mrioc, dev_handle, NULL, 269162306a36Sopenharmony_ci MPI3_CTRL_OP_REMOVE_DEVICE); 269262306a36Sopenharmony_ci if (hide) 269362306a36Sopenharmony_ci mpi3mr_dev_rmhs_send_tm(mrioc, dev_handle, NULL, 269462306a36Sopenharmony_ci MPI3_CTRL_OP_HIDDEN_ACK); 269562306a36Sopenharmony_ci 269662306a36Sopenharmony_ciout: 269762306a36Sopenharmony_ci if (tgtdev) 269862306a36Sopenharmony_ci mpi3mr_tgtdev_put(tgtdev); 269962306a36Sopenharmony_ci} 270062306a36Sopenharmony_ci 270162306a36Sopenharmony_ci/** 270262306a36Sopenharmony_ci * mpi3mr_preparereset_evt_th - Prepare for reset event tophalf 270362306a36Sopenharmony_ci * @mrioc: Adapter instance reference 270462306a36Sopenharmony_ci * @event_reply: event data 270562306a36Sopenharmony_ci * 270662306a36Sopenharmony_ci * Blocks and unblocks host level I/O based on the reason code 270762306a36Sopenharmony_ci * 270862306a36Sopenharmony_ci * Return: Nothing 270962306a36Sopenharmony_ci */ 271062306a36Sopenharmony_cistatic void mpi3mr_preparereset_evt_th(struct mpi3mr_ioc *mrioc, 271162306a36Sopenharmony_ci struct mpi3_event_notification_reply *event_reply) 271262306a36Sopenharmony_ci{ 271362306a36Sopenharmony_ci struct mpi3_event_data_prepare_for_reset *evtdata = 271462306a36Sopenharmony_ci (struct mpi3_event_data_prepare_for_reset *)event_reply->event_data; 271562306a36Sopenharmony_ci 271662306a36Sopenharmony_ci if (evtdata->reason_code == MPI3_EVENT_PREPARE_RESET_RC_START) { 271762306a36Sopenharmony_ci dprint_event_th(mrioc, 271862306a36Sopenharmony_ci "prepare for reset event top half with rc=start\n"); 271962306a36Sopenharmony_ci if (mrioc->prepare_for_reset) 272062306a36Sopenharmony_ci return; 272162306a36Sopenharmony_ci mrioc->prepare_for_reset = 1; 272262306a36Sopenharmony_ci mrioc->prepare_for_reset_timeout_counter = 0; 272362306a36Sopenharmony_ci } else if (evtdata->reason_code == MPI3_EVENT_PREPARE_RESET_RC_ABORT) { 272462306a36Sopenharmony_ci dprint_event_th(mrioc, 272562306a36Sopenharmony_ci "prepare for reset top half with rc=abort\n"); 272662306a36Sopenharmony_ci mrioc->prepare_for_reset = 0; 272762306a36Sopenharmony_ci mrioc->prepare_for_reset_timeout_counter = 0; 272862306a36Sopenharmony_ci } 272962306a36Sopenharmony_ci if ((event_reply->msg_flags & MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_MASK) 273062306a36Sopenharmony_ci == MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_REQUIRED) 273162306a36Sopenharmony_ci mpi3mr_send_event_ack(mrioc, event_reply->event, NULL, 273262306a36Sopenharmony_ci le32_to_cpu(event_reply->event_context)); 273362306a36Sopenharmony_ci} 273462306a36Sopenharmony_ci 273562306a36Sopenharmony_ci/** 273662306a36Sopenharmony_ci * mpi3mr_energypackchg_evt_th - Energy pack change evt tophalf 273762306a36Sopenharmony_ci * @mrioc: Adapter instance reference 273862306a36Sopenharmony_ci * @event_reply: event data 273962306a36Sopenharmony_ci * 274062306a36Sopenharmony_ci * Identifies the new shutdown timeout value and update. 274162306a36Sopenharmony_ci * 274262306a36Sopenharmony_ci * Return: Nothing 274362306a36Sopenharmony_ci */ 274462306a36Sopenharmony_cistatic void mpi3mr_energypackchg_evt_th(struct mpi3mr_ioc *mrioc, 274562306a36Sopenharmony_ci struct mpi3_event_notification_reply *event_reply) 274662306a36Sopenharmony_ci{ 274762306a36Sopenharmony_ci struct mpi3_event_data_energy_pack_change *evtdata = 274862306a36Sopenharmony_ci (struct mpi3_event_data_energy_pack_change *)event_reply->event_data; 274962306a36Sopenharmony_ci u16 shutdown_timeout = le16_to_cpu(evtdata->shutdown_timeout); 275062306a36Sopenharmony_ci 275162306a36Sopenharmony_ci if (shutdown_timeout <= 0) { 275262306a36Sopenharmony_ci ioc_warn(mrioc, 275362306a36Sopenharmony_ci "%s :Invalid Shutdown Timeout received = %d\n", 275462306a36Sopenharmony_ci __func__, shutdown_timeout); 275562306a36Sopenharmony_ci return; 275662306a36Sopenharmony_ci } 275762306a36Sopenharmony_ci 275862306a36Sopenharmony_ci ioc_info(mrioc, 275962306a36Sopenharmony_ci "%s :Previous Shutdown Timeout Value = %d New Shutdown Timeout Value = %d\n", 276062306a36Sopenharmony_ci __func__, mrioc->facts.shutdown_timeout, shutdown_timeout); 276162306a36Sopenharmony_ci mrioc->facts.shutdown_timeout = shutdown_timeout; 276262306a36Sopenharmony_ci} 276362306a36Sopenharmony_ci 276462306a36Sopenharmony_ci/** 276562306a36Sopenharmony_ci * mpi3mr_cablemgmt_evt_th - Cable management event tophalf 276662306a36Sopenharmony_ci * @mrioc: Adapter instance reference 276762306a36Sopenharmony_ci * @event_reply: event data 276862306a36Sopenharmony_ci * 276962306a36Sopenharmony_ci * Displays Cable manegemt event details. 277062306a36Sopenharmony_ci * 277162306a36Sopenharmony_ci * Return: Nothing 277262306a36Sopenharmony_ci */ 277362306a36Sopenharmony_cistatic void mpi3mr_cablemgmt_evt_th(struct mpi3mr_ioc *mrioc, 277462306a36Sopenharmony_ci struct mpi3_event_notification_reply *event_reply) 277562306a36Sopenharmony_ci{ 277662306a36Sopenharmony_ci struct mpi3_event_data_cable_management *evtdata = 277762306a36Sopenharmony_ci (struct mpi3_event_data_cable_management *)event_reply->event_data; 277862306a36Sopenharmony_ci 277962306a36Sopenharmony_ci switch (evtdata->status) { 278062306a36Sopenharmony_ci case MPI3_EVENT_CABLE_MGMT_STATUS_INSUFFICIENT_POWER: 278162306a36Sopenharmony_ci { 278262306a36Sopenharmony_ci ioc_info(mrioc, "An active cable with receptacle_id %d cannot be powered.\n" 278362306a36Sopenharmony_ci "Devices connected to this cable are not detected.\n" 278462306a36Sopenharmony_ci "This cable requires %d mW of power.\n", 278562306a36Sopenharmony_ci evtdata->receptacle_id, 278662306a36Sopenharmony_ci le32_to_cpu(evtdata->active_cable_power_requirement)); 278762306a36Sopenharmony_ci break; 278862306a36Sopenharmony_ci } 278962306a36Sopenharmony_ci case MPI3_EVENT_CABLE_MGMT_STATUS_DEGRADED: 279062306a36Sopenharmony_ci { 279162306a36Sopenharmony_ci ioc_info(mrioc, "A cable with receptacle_id %d is not running at optimal speed\n", 279262306a36Sopenharmony_ci evtdata->receptacle_id); 279362306a36Sopenharmony_ci break; 279462306a36Sopenharmony_ci } 279562306a36Sopenharmony_ci default: 279662306a36Sopenharmony_ci break; 279762306a36Sopenharmony_ci } 279862306a36Sopenharmony_ci} 279962306a36Sopenharmony_ci 280062306a36Sopenharmony_ci/** 280162306a36Sopenharmony_ci * mpi3mr_add_event_wait_for_device_refresh - Add Wait for Device Refresh Event 280262306a36Sopenharmony_ci * @mrioc: Adapter instance reference 280362306a36Sopenharmony_ci * 280462306a36Sopenharmony_ci * Add driver specific event to make sure that the driver won't process the 280562306a36Sopenharmony_ci * events until all the devices are refreshed during soft reset. 280662306a36Sopenharmony_ci * 280762306a36Sopenharmony_ci * Return: Nothing 280862306a36Sopenharmony_ci */ 280962306a36Sopenharmony_civoid mpi3mr_add_event_wait_for_device_refresh(struct mpi3mr_ioc *mrioc) 281062306a36Sopenharmony_ci{ 281162306a36Sopenharmony_ci struct mpi3mr_fwevt *fwevt = NULL; 281262306a36Sopenharmony_ci 281362306a36Sopenharmony_ci fwevt = mpi3mr_alloc_fwevt(0); 281462306a36Sopenharmony_ci if (!fwevt) { 281562306a36Sopenharmony_ci dprint_event_th(mrioc, 281662306a36Sopenharmony_ci "failed to schedule bottom half handler for event(0x%02x)\n", 281762306a36Sopenharmony_ci MPI3_EVENT_WAIT_FOR_DEVICES_TO_REFRESH); 281862306a36Sopenharmony_ci return; 281962306a36Sopenharmony_ci } 282062306a36Sopenharmony_ci fwevt->mrioc = mrioc; 282162306a36Sopenharmony_ci fwevt->event_id = MPI3_EVENT_WAIT_FOR_DEVICES_TO_REFRESH; 282262306a36Sopenharmony_ci fwevt->send_ack = 0; 282362306a36Sopenharmony_ci fwevt->process_evt = 1; 282462306a36Sopenharmony_ci fwevt->evt_ctx = 0; 282562306a36Sopenharmony_ci fwevt->event_data_size = 0; 282662306a36Sopenharmony_ci mpi3mr_fwevt_add_to_list(mrioc, fwevt); 282762306a36Sopenharmony_ci} 282862306a36Sopenharmony_ci 282962306a36Sopenharmony_ci/** 283062306a36Sopenharmony_ci * mpi3mr_os_handle_events - Firmware event handler 283162306a36Sopenharmony_ci * @mrioc: Adapter instance reference 283262306a36Sopenharmony_ci * @event_reply: event data 283362306a36Sopenharmony_ci * 283462306a36Sopenharmony_ci * Identify whteher the event has to handled and acknowledged 283562306a36Sopenharmony_ci * and either process the event in the tophalf and/or schedule a 283662306a36Sopenharmony_ci * bottom half through mpi3mr_fwevt_worker. 283762306a36Sopenharmony_ci * 283862306a36Sopenharmony_ci * Return: Nothing 283962306a36Sopenharmony_ci */ 284062306a36Sopenharmony_civoid mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc, 284162306a36Sopenharmony_ci struct mpi3_event_notification_reply *event_reply) 284262306a36Sopenharmony_ci{ 284362306a36Sopenharmony_ci u16 evt_type, sz; 284462306a36Sopenharmony_ci struct mpi3mr_fwevt *fwevt = NULL; 284562306a36Sopenharmony_ci bool ack_req = 0, process_evt_bh = 0; 284662306a36Sopenharmony_ci 284762306a36Sopenharmony_ci if (mrioc->stop_drv_processing) 284862306a36Sopenharmony_ci return; 284962306a36Sopenharmony_ci 285062306a36Sopenharmony_ci if ((event_reply->msg_flags & MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_MASK) 285162306a36Sopenharmony_ci == MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_REQUIRED) 285262306a36Sopenharmony_ci ack_req = 1; 285362306a36Sopenharmony_ci 285462306a36Sopenharmony_ci evt_type = event_reply->event; 285562306a36Sopenharmony_ci 285662306a36Sopenharmony_ci switch (evt_type) { 285762306a36Sopenharmony_ci case MPI3_EVENT_DEVICE_ADDED: 285862306a36Sopenharmony_ci { 285962306a36Sopenharmony_ci struct mpi3_device_page0 *dev_pg0 = 286062306a36Sopenharmony_ci (struct mpi3_device_page0 *)event_reply->event_data; 286162306a36Sopenharmony_ci if (mpi3mr_create_tgtdev(mrioc, dev_pg0)) 286262306a36Sopenharmony_ci ioc_err(mrioc, 286362306a36Sopenharmony_ci "%s :Failed to add device in the device add event\n", 286462306a36Sopenharmony_ci __func__); 286562306a36Sopenharmony_ci else 286662306a36Sopenharmony_ci process_evt_bh = 1; 286762306a36Sopenharmony_ci break; 286862306a36Sopenharmony_ci } 286962306a36Sopenharmony_ci case MPI3_EVENT_DEVICE_STATUS_CHANGE: 287062306a36Sopenharmony_ci { 287162306a36Sopenharmony_ci process_evt_bh = 1; 287262306a36Sopenharmony_ci mpi3mr_devstatuschg_evt_th(mrioc, event_reply); 287362306a36Sopenharmony_ci break; 287462306a36Sopenharmony_ci } 287562306a36Sopenharmony_ci case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST: 287662306a36Sopenharmony_ci { 287762306a36Sopenharmony_ci process_evt_bh = 1; 287862306a36Sopenharmony_ci mpi3mr_sastopochg_evt_th(mrioc, event_reply); 287962306a36Sopenharmony_ci break; 288062306a36Sopenharmony_ci } 288162306a36Sopenharmony_ci case MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST: 288262306a36Sopenharmony_ci { 288362306a36Sopenharmony_ci process_evt_bh = 1; 288462306a36Sopenharmony_ci mpi3mr_pcietopochg_evt_th(mrioc, event_reply); 288562306a36Sopenharmony_ci break; 288662306a36Sopenharmony_ci } 288762306a36Sopenharmony_ci case MPI3_EVENT_PREPARE_FOR_RESET: 288862306a36Sopenharmony_ci { 288962306a36Sopenharmony_ci mpi3mr_preparereset_evt_th(mrioc, event_reply); 289062306a36Sopenharmony_ci ack_req = 0; 289162306a36Sopenharmony_ci break; 289262306a36Sopenharmony_ci } 289362306a36Sopenharmony_ci case MPI3_EVENT_DEVICE_INFO_CHANGED: 289462306a36Sopenharmony_ci case MPI3_EVENT_LOG_DATA: 289562306a36Sopenharmony_ci case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE: 289662306a36Sopenharmony_ci case MPI3_EVENT_ENCL_DEVICE_ADDED: 289762306a36Sopenharmony_ci { 289862306a36Sopenharmony_ci process_evt_bh = 1; 289962306a36Sopenharmony_ci break; 290062306a36Sopenharmony_ci } 290162306a36Sopenharmony_ci case MPI3_EVENT_ENERGY_PACK_CHANGE: 290262306a36Sopenharmony_ci { 290362306a36Sopenharmony_ci mpi3mr_energypackchg_evt_th(mrioc, event_reply); 290462306a36Sopenharmony_ci break; 290562306a36Sopenharmony_ci } 290662306a36Sopenharmony_ci case MPI3_EVENT_CABLE_MGMT: 290762306a36Sopenharmony_ci { 290862306a36Sopenharmony_ci mpi3mr_cablemgmt_evt_th(mrioc, event_reply); 290962306a36Sopenharmony_ci break; 291062306a36Sopenharmony_ci } 291162306a36Sopenharmony_ci case MPI3_EVENT_SAS_DISCOVERY: 291262306a36Sopenharmony_ci case MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR: 291362306a36Sopenharmony_ci case MPI3_EVENT_SAS_BROADCAST_PRIMITIVE: 291462306a36Sopenharmony_ci case MPI3_EVENT_PCIE_ENUMERATION: 291562306a36Sopenharmony_ci break; 291662306a36Sopenharmony_ci default: 291762306a36Sopenharmony_ci ioc_info(mrioc, "%s :event 0x%02x is not handled\n", 291862306a36Sopenharmony_ci __func__, evt_type); 291962306a36Sopenharmony_ci break; 292062306a36Sopenharmony_ci } 292162306a36Sopenharmony_ci if (process_evt_bh || ack_req) { 292262306a36Sopenharmony_ci sz = event_reply->event_data_length * 4; 292362306a36Sopenharmony_ci fwevt = mpi3mr_alloc_fwevt(sz); 292462306a36Sopenharmony_ci if (!fwevt) { 292562306a36Sopenharmony_ci ioc_info(mrioc, "%s :failure at %s:%d/%s()!\n", 292662306a36Sopenharmony_ci __func__, __FILE__, __LINE__, __func__); 292762306a36Sopenharmony_ci return; 292862306a36Sopenharmony_ci } 292962306a36Sopenharmony_ci 293062306a36Sopenharmony_ci memcpy(fwevt->event_data, event_reply->event_data, sz); 293162306a36Sopenharmony_ci fwevt->mrioc = mrioc; 293262306a36Sopenharmony_ci fwevt->event_id = evt_type; 293362306a36Sopenharmony_ci fwevt->send_ack = ack_req; 293462306a36Sopenharmony_ci fwevt->process_evt = process_evt_bh; 293562306a36Sopenharmony_ci fwevt->evt_ctx = le32_to_cpu(event_reply->event_context); 293662306a36Sopenharmony_ci mpi3mr_fwevt_add_to_list(mrioc, fwevt); 293762306a36Sopenharmony_ci } 293862306a36Sopenharmony_ci} 293962306a36Sopenharmony_ci 294062306a36Sopenharmony_ci/** 294162306a36Sopenharmony_ci * mpi3mr_setup_eedp - Setup EEDP information in MPI3 SCSI IO 294262306a36Sopenharmony_ci * @mrioc: Adapter instance reference 294362306a36Sopenharmony_ci * @scmd: SCSI command reference 294462306a36Sopenharmony_ci * @scsiio_req: MPI3 SCSI IO request 294562306a36Sopenharmony_ci * 294662306a36Sopenharmony_ci * Identifies the protection information flags from the SCSI 294762306a36Sopenharmony_ci * command and set appropriate flags in the MPI3 SCSI IO 294862306a36Sopenharmony_ci * request. 294962306a36Sopenharmony_ci * 295062306a36Sopenharmony_ci * Return: Nothing 295162306a36Sopenharmony_ci */ 295262306a36Sopenharmony_cistatic void mpi3mr_setup_eedp(struct mpi3mr_ioc *mrioc, 295362306a36Sopenharmony_ci struct scsi_cmnd *scmd, struct mpi3_scsi_io_request *scsiio_req) 295462306a36Sopenharmony_ci{ 295562306a36Sopenharmony_ci u16 eedp_flags = 0; 295662306a36Sopenharmony_ci unsigned char prot_op = scsi_get_prot_op(scmd); 295762306a36Sopenharmony_ci 295862306a36Sopenharmony_ci switch (prot_op) { 295962306a36Sopenharmony_ci case SCSI_PROT_NORMAL: 296062306a36Sopenharmony_ci return; 296162306a36Sopenharmony_ci case SCSI_PROT_READ_STRIP: 296262306a36Sopenharmony_ci eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_CHECK_REMOVE; 296362306a36Sopenharmony_ci break; 296462306a36Sopenharmony_ci case SCSI_PROT_WRITE_INSERT: 296562306a36Sopenharmony_ci eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_INSERT; 296662306a36Sopenharmony_ci break; 296762306a36Sopenharmony_ci case SCSI_PROT_READ_INSERT: 296862306a36Sopenharmony_ci eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_INSERT; 296962306a36Sopenharmony_ci scsiio_req->msg_flags |= MPI3_SCSIIO_MSGFLAGS_METASGL_VALID; 297062306a36Sopenharmony_ci break; 297162306a36Sopenharmony_ci case SCSI_PROT_WRITE_STRIP: 297262306a36Sopenharmony_ci eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_CHECK_REMOVE; 297362306a36Sopenharmony_ci scsiio_req->msg_flags |= MPI3_SCSIIO_MSGFLAGS_METASGL_VALID; 297462306a36Sopenharmony_ci break; 297562306a36Sopenharmony_ci case SCSI_PROT_READ_PASS: 297662306a36Sopenharmony_ci eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_CHECK; 297762306a36Sopenharmony_ci scsiio_req->msg_flags |= MPI3_SCSIIO_MSGFLAGS_METASGL_VALID; 297862306a36Sopenharmony_ci break; 297962306a36Sopenharmony_ci case SCSI_PROT_WRITE_PASS: 298062306a36Sopenharmony_ci if (scmd->prot_flags & SCSI_PROT_IP_CHECKSUM) { 298162306a36Sopenharmony_ci eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_CHECK_REGEN; 298262306a36Sopenharmony_ci scsiio_req->sgl[0].eedp.application_tag_translation_mask = 298362306a36Sopenharmony_ci 0xffff; 298462306a36Sopenharmony_ci } else 298562306a36Sopenharmony_ci eedp_flags = MPI3_EEDPFLAGS_EEDP_OP_CHECK; 298662306a36Sopenharmony_ci 298762306a36Sopenharmony_ci scsiio_req->msg_flags |= MPI3_SCSIIO_MSGFLAGS_METASGL_VALID; 298862306a36Sopenharmony_ci break; 298962306a36Sopenharmony_ci default: 299062306a36Sopenharmony_ci return; 299162306a36Sopenharmony_ci } 299262306a36Sopenharmony_ci 299362306a36Sopenharmony_ci if (scmd->prot_flags & SCSI_PROT_GUARD_CHECK) 299462306a36Sopenharmony_ci eedp_flags |= MPI3_EEDPFLAGS_CHK_GUARD; 299562306a36Sopenharmony_ci 299662306a36Sopenharmony_ci if (scmd->prot_flags & SCSI_PROT_IP_CHECKSUM) 299762306a36Sopenharmony_ci eedp_flags |= MPI3_EEDPFLAGS_HOST_GUARD_IP_CHKSUM; 299862306a36Sopenharmony_ci 299962306a36Sopenharmony_ci if (scmd->prot_flags & SCSI_PROT_REF_CHECK) { 300062306a36Sopenharmony_ci eedp_flags |= MPI3_EEDPFLAGS_CHK_REF_TAG | 300162306a36Sopenharmony_ci MPI3_EEDPFLAGS_INCR_PRI_REF_TAG; 300262306a36Sopenharmony_ci scsiio_req->cdb.eedp32.primary_reference_tag = 300362306a36Sopenharmony_ci cpu_to_be32(scsi_prot_ref_tag(scmd)); 300462306a36Sopenharmony_ci } 300562306a36Sopenharmony_ci 300662306a36Sopenharmony_ci if (scmd->prot_flags & SCSI_PROT_REF_INCREMENT) 300762306a36Sopenharmony_ci eedp_flags |= MPI3_EEDPFLAGS_INCR_PRI_REF_TAG; 300862306a36Sopenharmony_ci 300962306a36Sopenharmony_ci eedp_flags |= MPI3_EEDPFLAGS_ESC_MODE_APPTAG_DISABLE; 301062306a36Sopenharmony_ci 301162306a36Sopenharmony_ci switch (scsi_prot_interval(scmd)) { 301262306a36Sopenharmony_ci case 512: 301362306a36Sopenharmony_ci scsiio_req->sgl[0].eedp.user_data_size = MPI3_EEDP_UDS_512; 301462306a36Sopenharmony_ci break; 301562306a36Sopenharmony_ci case 520: 301662306a36Sopenharmony_ci scsiio_req->sgl[0].eedp.user_data_size = MPI3_EEDP_UDS_520; 301762306a36Sopenharmony_ci break; 301862306a36Sopenharmony_ci case 4080: 301962306a36Sopenharmony_ci scsiio_req->sgl[0].eedp.user_data_size = MPI3_EEDP_UDS_4080; 302062306a36Sopenharmony_ci break; 302162306a36Sopenharmony_ci case 4088: 302262306a36Sopenharmony_ci scsiio_req->sgl[0].eedp.user_data_size = MPI3_EEDP_UDS_4088; 302362306a36Sopenharmony_ci break; 302462306a36Sopenharmony_ci case 4096: 302562306a36Sopenharmony_ci scsiio_req->sgl[0].eedp.user_data_size = MPI3_EEDP_UDS_4096; 302662306a36Sopenharmony_ci break; 302762306a36Sopenharmony_ci case 4104: 302862306a36Sopenharmony_ci scsiio_req->sgl[0].eedp.user_data_size = MPI3_EEDP_UDS_4104; 302962306a36Sopenharmony_ci break; 303062306a36Sopenharmony_ci case 4160: 303162306a36Sopenharmony_ci scsiio_req->sgl[0].eedp.user_data_size = MPI3_EEDP_UDS_4160; 303262306a36Sopenharmony_ci break; 303362306a36Sopenharmony_ci default: 303462306a36Sopenharmony_ci break; 303562306a36Sopenharmony_ci } 303662306a36Sopenharmony_ci 303762306a36Sopenharmony_ci scsiio_req->sgl[0].eedp.eedp_flags = cpu_to_le16(eedp_flags); 303862306a36Sopenharmony_ci scsiio_req->sgl[0].eedp.flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_EXTENDED; 303962306a36Sopenharmony_ci} 304062306a36Sopenharmony_ci 304162306a36Sopenharmony_ci/** 304262306a36Sopenharmony_ci * mpi3mr_build_sense_buffer - Map sense information 304362306a36Sopenharmony_ci * @desc: Sense type 304462306a36Sopenharmony_ci * @buf: Sense buffer to populate 304562306a36Sopenharmony_ci * @key: Sense key 304662306a36Sopenharmony_ci * @asc: Additional sense code 304762306a36Sopenharmony_ci * @ascq: Additional sense code qualifier 304862306a36Sopenharmony_ci * 304962306a36Sopenharmony_ci * Maps the given sense information into either descriptor or 305062306a36Sopenharmony_ci * fixed format sense data. 305162306a36Sopenharmony_ci * 305262306a36Sopenharmony_ci * Return: Nothing 305362306a36Sopenharmony_ci */ 305462306a36Sopenharmony_cistatic inline void mpi3mr_build_sense_buffer(int desc, u8 *buf, u8 key, 305562306a36Sopenharmony_ci u8 asc, u8 ascq) 305662306a36Sopenharmony_ci{ 305762306a36Sopenharmony_ci if (desc) { 305862306a36Sopenharmony_ci buf[0] = 0x72; /* descriptor, current */ 305962306a36Sopenharmony_ci buf[1] = key; 306062306a36Sopenharmony_ci buf[2] = asc; 306162306a36Sopenharmony_ci buf[3] = ascq; 306262306a36Sopenharmony_ci buf[7] = 0; 306362306a36Sopenharmony_ci } else { 306462306a36Sopenharmony_ci buf[0] = 0x70; /* fixed, current */ 306562306a36Sopenharmony_ci buf[2] = key; 306662306a36Sopenharmony_ci buf[7] = 0xa; 306762306a36Sopenharmony_ci buf[12] = asc; 306862306a36Sopenharmony_ci buf[13] = ascq; 306962306a36Sopenharmony_ci } 307062306a36Sopenharmony_ci} 307162306a36Sopenharmony_ci 307262306a36Sopenharmony_ci/** 307362306a36Sopenharmony_ci * mpi3mr_map_eedp_error - Map EEDP errors from IOC status 307462306a36Sopenharmony_ci * @scmd: SCSI command reference 307562306a36Sopenharmony_ci * @ioc_status: status of MPI3 request 307662306a36Sopenharmony_ci * 307762306a36Sopenharmony_ci * Maps the EEDP error status of the SCSI IO request to sense 307862306a36Sopenharmony_ci * data. 307962306a36Sopenharmony_ci * 308062306a36Sopenharmony_ci * Return: Nothing 308162306a36Sopenharmony_ci */ 308262306a36Sopenharmony_cistatic void mpi3mr_map_eedp_error(struct scsi_cmnd *scmd, 308362306a36Sopenharmony_ci u16 ioc_status) 308462306a36Sopenharmony_ci{ 308562306a36Sopenharmony_ci u8 ascq = 0; 308662306a36Sopenharmony_ci 308762306a36Sopenharmony_ci switch (ioc_status) { 308862306a36Sopenharmony_ci case MPI3_IOCSTATUS_EEDP_GUARD_ERROR: 308962306a36Sopenharmony_ci ascq = 0x01; 309062306a36Sopenharmony_ci break; 309162306a36Sopenharmony_ci case MPI3_IOCSTATUS_EEDP_APP_TAG_ERROR: 309262306a36Sopenharmony_ci ascq = 0x02; 309362306a36Sopenharmony_ci break; 309462306a36Sopenharmony_ci case MPI3_IOCSTATUS_EEDP_REF_TAG_ERROR: 309562306a36Sopenharmony_ci ascq = 0x03; 309662306a36Sopenharmony_ci break; 309762306a36Sopenharmony_ci default: 309862306a36Sopenharmony_ci ascq = 0x00; 309962306a36Sopenharmony_ci break; 310062306a36Sopenharmony_ci } 310162306a36Sopenharmony_ci 310262306a36Sopenharmony_ci mpi3mr_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST, 310362306a36Sopenharmony_ci 0x10, ascq); 310462306a36Sopenharmony_ci scmd->result = (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION; 310562306a36Sopenharmony_ci} 310662306a36Sopenharmony_ci 310762306a36Sopenharmony_ci/** 310862306a36Sopenharmony_ci * mpi3mr_process_op_reply_desc - reply descriptor handler 310962306a36Sopenharmony_ci * @mrioc: Adapter instance reference 311062306a36Sopenharmony_ci * @reply_desc: Operational reply descriptor 311162306a36Sopenharmony_ci * @reply_dma: place holder for reply DMA address 311262306a36Sopenharmony_ci * @qidx: Operational queue index 311362306a36Sopenharmony_ci * 311462306a36Sopenharmony_ci * Process the operational reply descriptor and identifies the 311562306a36Sopenharmony_ci * descriptor type. Based on the descriptor map the MPI3 request 311662306a36Sopenharmony_ci * status to a SCSI command status and calls scsi_done call 311762306a36Sopenharmony_ci * back. 311862306a36Sopenharmony_ci * 311962306a36Sopenharmony_ci * Return: Nothing 312062306a36Sopenharmony_ci */ 312162306a36Sopenharmony_civoid mpi3mr_process_op_reply_desc(struct mpi3mr_ioc *mrioc, 312262306a36Sopenharmony_ci struct mpi3_default_reply_descriptor *reply_desc, u64 *reply_dma, u16 qidx) 312362306a36Sopenharmony_ci{ 312462306a36Sopenharmony_ci u16 reply_desc_type, host_tag = 0; 312562306a36Sopenharmony_ci u16 ioc_status = MPI3_IOCSTATUS_SUCCESS; 312662306a36Sopenharmony_ci u32 ioc_loginfo = 0; 312762306a36Sopenharmony_ci struct mpi3_status_reply_descriptor *status_desc = NULL; 312862306a36Sopenharmony_ci struct mpi3_address_reply_descriptor *addr_desc = NULL; 312962306a36Sopenharmony_ci struct mpi3_success_reply_descriptor *success_desc = NULL; 313062306a36Sopenharmony_ci struct mpi3_scsi_io_reply *scsi_reply = NULL; 313162306a36Sopenharmony_ci struct scsi_cmnd *scmd = NULL; 313262306a36Sopenharmony_ci struct scmd_priv *priv = NULL; 313362306a36Sopenharmony_ci u8 *sense_buf = NULL; 313462306a36Sopenharmony_ci u8 scsi_state = 0, scsi_status = 0, sense_state = 0; 313562306a36Sopenharmony_ci u32 xfer_count = 0, sense_count = 0, resp_data = 0; 313662306a36Sopenharmony_ci u16 dev_handle = 0xFFFF; 313762306a36Sopenharmony_ci struct scsi_sense_hdr sshdr; 313862306a36Sopenharmony_ci struct mpi3mr_stgt_priv_data *stgt_priv_data = NULL; 313962306a36Sopenharmony_ci struct mpi3mr_sdev_priv_data *sdev_priv_data = NULL; 314062306a36Sopenharmony_ci u32 ioc_pend_data_len = 0, tg_pend_data_len = 0, data_len_blks = 0; 314162306a36Sopenharmony_ci struct mpi3mr_throttle_group_info *tg = NULL; 314262306a36Sopenharmony_ci u8 throttle_enabled_dev = 0; 314362306a36Sopenharmony_ci 314462306a36Sopenharmony_ci *reply_dma = 0; 314562306a36Sopenharmony_ci reply_desc_type = le16_to_cpu(reply_desc->reply_flags) & 314662306a36Sopenharmony_ci MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK; 314762306a36Sopenharmony_ci switch (reply_desc_type) { 314862306a36Sopenharmony_ci case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_STATUS: 314962306a36Sopenharmony_ci status_desc = (struct mpi3_status_reply_descriptor *)reply_desc; 315062306a36Sopenharmony_ci host_tag = le16_to_cpu(status_desc->host_tag); 315162306a36Sopenharmony_ci ioc_status = le16_to_cpu(status_desc->ioc_status); 315262306a36Sopenharmony_ci if (ioc_status & 315362306a36Sopenharmony_ci MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL) 315462306a36Sopenharmony_ci ioc_loginfo = le32_to_cpu(status_desc->ioc_log_info); 315562306a36Sopenharmony_ci ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK; 315662306a36Sopenharmony_ci break; 315762306a36Sopenharmony_ci case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY: 315862306a36Sopenharmony_ci addr_desc = (struct mpi3_address_reply_descriptor *)reply_desc; 315962306a36Sopenharmony_ci *reply_dma = le64_to_cpu(addr_desc->reply_frame_address); 316062306a36Sopenharmony_ci scsi_reply = mpi3mr_get_reply_virt_addr(mrioc, 316162306a36Sopenharmony_ci *reply_dma); 316262306a36Sopenharmony_ci if (!scsi_reply) { 316362306a36Sopenharmony_ci panic("%s: scsi_reply is NULL, this shouldn't happen\n", 316462306a36Sopenharmony_ci mrioc->name); 316562306a36Sopenharmony_ci goto out; 316662306a36Sopenharmony_ci } 316762306a36Sopenharmony_ci host_tag = le16_to_cpu(scsi_reply->host_tag); 316862306a36Sopenharmony_ci ioc_status = le16_to_cpu(scsi_reply->ioc_status); 316962306a36Sopenharmony_ci scsi_status = scsi_reply->scsi_status; 317062306a36Sopenharmony_ci scsi_state = scsi_reply->scsi_state; 317162306a36Sopenharmony_ci dev_handle = le16_to_cpu(scsi_reply->dev_handle); 317262306a36Sopenharmony_ci sense_state = (scsi_state & MPI3_SCSI_STATE_SENSE_MASK); 317362306a36Sopenharmony_ci xfer_count = le32_to_cpu(scsi_reply->transfer_count); 317462306a36Sopenharmony_ci sense_count = le32_to_cpu(scsi_reply->sense_count); 317562306a36Sopenharmony_ci resp_data = le32_to_cpu(scsi_reply->response_data); 317662306a36Sopenharmony_ci sense_buf = mpi3mr_get_sensebuf_virt_addr(mrioc, 317762306a36Sopenharmony_ci le64_to_cpu(scsi_reply->sense_data_buffer_address)); 317862306a36Sopenharmony_ci if (ioc_status & 317962306a36Sopenharmony_ci MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL) 318062306a36Sopenharmony_ci ioc_loginfo = le32_to_cpu(scsi_reply->ioc_log_info); 318162306a36Sopenharmony_ci ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK; 318262306a36Sopenharmony_ci if (sense_state == MPI3_SCSI_STATE_SENSE_BUFF_Q_EMPTY) 318362306a36Sopenharmony_ci panic("%s: Ran out of sense buffers\n", mrioc->name); 318462306a36Sopenharmony_ci break; 318562306a36Sopenharmony_ci case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS: 318662306a36Sopenharmony_ci success_desc = (struct mpi3_success_reply_descriptor *)reply_desc; 318762306a36Sopenharmony_ci host_tag = le16_to_cpu(success_desc->host_tag); 318862306a36Sopenharmony_ci break; 318962306a36Sopenharmony_ci default: 319062306a36Sopenharmony_ci break; 319162306a36Sopenharmony_ci } 319262306a36Sopenharmony_ci scmd = mpi3mr_scmd_from_host_tag(mrioc, host_tag, qidx); 319362306a36Sopenharmony_ci if (!scmd) { 319462306a36Sopenharmony_ci panic("%s: Cannot Identify scmd for host_tag 0x%x\n", 319562306a36Sopenharmony_ci mrioc->name, host_tag); 319662306a36Sopenharmony_ci goto out; 319762306a36Sopenharmony_ci } 319862306a36Sopenharmony_ci priv = scsi_cmd_priv(scmd); 319962306a36Sopenharmony_ci 320062306a36Sopenharmony_ci data_len_blks = scsi_bufflen(scmd) >> 9; 320162306a36Sopenharmony_ci sdev_priv_data = scmd->device->hostdata; 320262306a36Sopenharmony_ci if (sdev_priv_data) { 320362306a36Sopenharmony_ci stgt_priv_data = sdev_priv_data->tgt_priv_data; 320462306a36Sopenharmony_ci if (stgt_priv_data) { 320562306a36Sopenharmony_ci tg = stgt_priv_data->throttle_group; 320662306a36Sopenharmony_ci throttle_enabled_dev = 320762306a36Sopenharmony_ci stgt_priv_data->io_throttle_enabled; 320862306a36Sopenharmony_ci } 320962306a36Sopenharmony_ci } 321062306a36Sopenharmony_ci if (unlikely((data_len_blks >= mrioc->io_throttle_data_length) && 321162306a36Sopenharmony_ci throttle_enabled_dev)) { 321262306a36Sopenharmony_ci ioc_pend_data_len = atomic_sub_return(data_len_blks, 321362306a36Sopenharmony_ci &mrioc->pend_large_data_sz); 321462306a36Sopenharmony_ci if (tg) { 321562306a36Sopenharmony_ci tg_pend_data_len = atomic_sub_return(data_len_blks, 321662306a36Sopenharmony_ci &tg->pend_large_data_sz); 321762306a36Sopenharmony_ci if (tg->io_divert && ((ioc_pend_data_len <= 321862306a36Sopenharmony_ci mrioc->io_throttle_low) && 321962306a36Sopenharmony_ci (tg_pend_data_len <= tg->low))) { 322062306a36Sopenharmony_ci tg->io_divert = 0; 322162306a36Sopenharmony_ci mpi3mr_set_io_divert_for_all_vd_in_tg( 322262306a36Sopenharmony_ci mrioc, tg, 0); 322362306a36Sopenharmony_ci } 322462306a36Sopenharmony_ci } else { 322562306a36Sopenharmony_ci if (ioc_pend_data_len <= mrioc->io_throttle_low) 322662306a36Sopenharmony_ci stgt_priv_data->io_divert = 0; 322762306a36Sopenharmony_ci } 322862306a36Sopenharmony_ci } else if (unlikely((stgt_priv_data && stgt_priv_data->io_divert))) { 322962306a36Sopenharmony_ci ioc_pend_data_len = atomic_read(&mrioc->pend_large_data_sz); 323062306a36Sopenharmony_ci if (!tg) { 323162306a36Sopenharmony_ci if (ioc_pend_data_len <= mrioc->io_throttle_low) 323262306a36Sopenharmony_ci stgt_priv_data->io_divert = 0; 323362306a36Sopenharmony_ci 323462306a36Sopenharmony_ci } else if (ioc_pend_data_len <= mrioc->io_throttle_low) { 323562306a36Sopenharmony_ci tg_pend_data_len = atomic_read(&tg->pend_large_data_sz); 323662306a36Sopenharmony_ci if (tg->io_divert && (tg_pend_data_len <= tg->low)) { 323762306a36Sopenharmony_ci tg->io_divert = 0; 323862306a36Sopenharmony_ci mpi3mr_set_io_divert_for_all_vd_in_tg( 323962306a36Sopenharmony_ci mrioc, tg, 0); 324062306a36Sopenharmony_ci } 324162306a36Sopenharmony_ci } 324262306a36Sopenharmony_ci } 324362306a36Sopenharmony_ci 324462306a36Sopenharmony_ci if (success_desc) { 324562306a36Sopenharmony_ci scmd->result = DID_OK << 16; 324662306a36Sopenharmony_ci goto out_success; 324762306a36Sopenharmony_ci } 324862306a36Sopenharmony_ci 324962306a36Sopenharmony_ci scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_count); 325062306a36Sopenharmony_ci if (ioc_status == MPI3_IOCSTATUS_SCSI_DATA_UNDERRUN && 325162306a36Sopenharmony_ci xfer_count == 0 && (scsi_status == MPI3_SCSI_STATUS_BUSY || 325262306a36Sopenharmony_ci scsi_status == MPI3_SCSI_STATUS_RESERVATION_CONFLICT || 325362306a36Sopenharmony_ci scsi_status == MPI3_SCSI_STATUS_TASK_SET_FULL)) 325462306a36Sopenharmony_ci ioc_status = MPI3_IOCSTATUS_SUCCESS; 325562306a36Sopenharmony_ci 325662306a36Sopenharmony_ci if ((sense_state == MPI3_SCSI_STATE_SENSE_VALID) && sense_count && 325762306a36Sopenharmony_ci sense_buf) { 325862306a36Sopenharmony_ci u32 sz = min_t(u32, SCSI_SENSE_BUFFERSIZE, sense_count); 325962306a36Sopenharmony_ci 326062306a36Sopenharmony_ci memcpy(scmd->sense_buffer, sense_buf, sz); 326162306a36Sopenharmony_ci } 326262306a36Sopenharmony_ci 326362306a36Sopenharmony_ci switch (ioc_status) { 326462306a36Sopenharmony_ci case MPI3_IOCSTATUS_BUSY: 326562306a36Sopenharmony_ci case MPI3_IOCSTATUS_INSUFFICIENT_RESOURCES: 326662306a36Sopenharmony_ci scmd->result = SAM_STAT_BUSY; 326762306a36Sopenharmony_ci break; 326862306a36Sopenharmony_ci case MPI3_IOCSTATUS_SCSI_DEVICE_NOT_THERE: 326962306a36Sopenharmony_ci scmd->result = DID_NO_CONNECT << 16; 327062306a36Sopenharmony_ci break; 327162306a36Sopenharmony_ci case MPI3_IOCSTATUS_SCSI_IOC_TERMINATED: 327262306a36Sopenharmony_ci scmd->result = DID_SOFT_ERROR << 16; 327362306a36Sopenharmony_ci break; 327462306a36Sopenharmony_ci case MPI3_IOCSTATUS_SCSI_TASK_TERMINATED: 327562306a36Sopenharmony_ci case MPI3_IOCSTATUS_SCSI_EXT_TERMINATED: 327662306a36Sopenharmony_ci scmd->result = DID_RESET << 16; 327762306a36Sopenharmony_ci break; 327862306a36Sopenharmony_ci case MPI3_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: 327962306a36Sopenharmony_ci if ((xfer_count == 0) || (scmd->underflow > xfer_count)) 328062306a36Sopenharmony_ci scmd->result = DID_SOFT_ERROR << 16; 328162306a36Sopenharmony_ci else 328262306a36Sopenharmony_ci scmd->result = (DID_OK << 16) | scsi_status; 328362306a36Sopenharmony_ci break; 328462306a36Sopenharmony_ci case MPI3_IOCSTATUS_SCSI_DATA_UNDERRUN: 328562306a36Sopenharmony_ci scmd->result = (DID_OK << 16) | scsi_status; 328662306a36Sopenharmony_ci if (sense_state == MPI3_SCSI_STATE_SENSE_VALID) 328762306a36Sopenharmony_ci break; 328862306a36Sopenharmony_ci if (xfer_count < scmd->underflow) { 328962306a36Sopenharmony_ci if (scsi_status == SAM_STAT_BUSY) 329062306a36Sopenharmony_ci scmd->result = SAM_STAT_BUSY; 329162306a36Sopenharmony_ci else 329262306a36Sopenharmony_ci scmd->result = DID_SOFT_ERROR << 16; 329362306a36Sopenharmony_ci } else if ((scsi_state & (MPI3_SCSI_STATE_NO_SCSI_STATUS)) || 329462306a36Sopenharmony_ci (sense_state != MPI3_SCSI_STATE_SENSE_NOT_AVAILABLE)) 329562306a36Sopenharmony_ci scmd->result = DID_SOFT_ERROR << 16; 329662306a36Sopenharmony_ci else if (scsi_state & MPI3_SCSI_STATE_TERMINATED) 329762306a36Sopenharmony_ci scmd->result = DID_RESET << 16; 329862306a36Sopenharmony_ci break; 329962306a36Sopenharmony_ci case MPI3_IOCSTATUS_SCSI_DATA_OVERRUN: 330062306a36Sopenharmony_ci scsi_set_resid(scmd, 0); 330162306a36Sopenharmony_ci fallthrough; 330262306a36Sopenharmony_ci case MPI3_IOCSTATUS_SCSI_RECOVERED_ERROR: 330362306a36Sopenharmony_ci case MPI3_IOCSTATUS_SUCCESS: 330462306a36Sopenharmony_ci scmd->result = (DID_OK << 16) | scsi_status; 330562306a36Sopenharmony_ci if ((scsi_state & (MPI3_SCSI_STATE_NO_SCSI_STATUS)) || 330662306a36Sopenharmony_ci (sense_state == MPI3_SCSI_STATE_SENSE_FAILED) || 330762306a36Sopenharmony_ci (sense_state == MPI3_SCSI_STATE_SENSE_BUFF_Q_EMPTY)) 330862306a36Sopenharmony_ci scmd->result = DID_SOFT_ERROR << 16; 330962306a36Sopenharmony_ci else if (scsi_state & MPI3_SCSI_STATE_TERMINATED) 331062306a36Sopenharmony_ci scmd->result = DID_RESET << 16; 331162306a36Sopenharmony_ci break; 331262306a36Sopenharmony_ci case MPI3_IOCSTATUS_EEDP_GUARD_ERROR: 331362306a36Sopenharmony_ci case MPI3_IOCSTATUS_EEDP_REF_TAG_ERROR: 331462306a36Sopenharmony_ci case MPI3_IOCSTATUS_EEDP_APP_TAG_ERROR: 331562306a36Sopenharmony_ci mpi3mr_map_eedp_error(scmd, ioc_status); 331662306a36Sopenharmony_ci break; 331762306a36Sopenharmony_ci case MPI3_IOCSTATUS_SCSI_PROTOCOL_ERROR: 331862306a36Sopenharmony_ci case MPI3_IOCSTATUS_INVALID_FUNCTION: 331962306a36Sopenharmony_ci case MPI3_IOCSTATUS_INVALID_SGL: 332062306a36Sopenharmony_ci case MPI3_IOCSTATUS_INTERNAL_ERROR: 332162306a36Sopenharmony_ci case MPI3_IOCSTATUS_INVALID_FIELD: 332262306a36Sopenharmony_ci case MPI3_IOCSTATUS_INVALID_STATE: 332362306a36Sopenharmony_ci case MPI3_IOCSTATUS_SCSI_IO_DATA_ERROR: 332462306a36Sopenharmony_ci case MPI3_IOCSTATUS_SCSI_TASK_MGMT_FAILED: 332562306a36Sopenharmony_ci case MPI3_IOCSTATUS_INSUFFICIENT_POWER: 332662306a36Sopenharmony_ci default: 332762306a36Sopenharmony_ci scmd->result = DID_SOFT_ERROR << 16; 332862306a36Sopenharmony_ci break; 332962306a36Sopenharmony_ci } 333062306a36Sopenharmony_ci 333162306a36Sopenharmony_ci if (scmd->result != (DID_OK << 16) && (scmd->cmnd[0] != ATA_12) && 333262306a36Sopenharmony_ci (scmd->cmnd[0] != ATA_16) && 333362306a36Sopenharmony_ci mrioc->logging_level & MPI3_DEBUG_SCSI_ERROR) { 333462306a36Sopenharmony_ci ioc_info(mrioc, "%s :scmd->result 0x%x\n", __func__, 333562306a36Sopenharmony_ci scmd->result); 333662306a36Sopenharmony_ci scsi_print_command(scmd); 333762306a36Sopenharmony_ci ioc_info(mrioc, 333862306a36Sopenharmony_ci "%s :Command issued to handle 0x%02x returned with error 0x%04x loginfo 0x%08x, qid %d\n", 333962306a36Sopenharmony_ci __func__, dev_handle, ioc_status, ioc_loginfo, 334062306a36Sopenharmony_ci priv->req_q_idx + 1); 334162306a36Sopenharmony_ci ioc_info(mrioc, 334262306a36Sopenharmony_ci " host_tag %d scsi_state 0x%02x scsi_status 0x%02x, xfer_cnt %d resp_data 0x%x\n", 334362306a36Sopenharmony_ci host_tag, scsi_state, scsi_status, xfer_count, resp_data); 334462306a36Sopenharmony_ci if (sense_buf) { 334562306a36Sopenharmony_ci scsi_normalize_sense(sense_buf, sense_count, &sshdr); 334662306a36Sopenharmony_ci ioc_info(mrioc, 334762306a36Sopenharmony_ci "%s :sense_count 0x%x, sense_key 0x%x ASC 0x%x, ASCQ 0x%x\n", 334862306a36Sopenharmony_ci __func__, sense_count, sshdr.sense_key, 334962306a36Sopenharmony_ci sshdr.asc, sshdr.ascq); 335062306a36Sopenharmony_ci } 335162306a36Sopenharmony_ci } 335262306a36Sopenharmony_ciout_success: 335362306a36Sopenharmony_ci if (priv->meta_sg_valid) { 335462306a36Sopenharmony_ci dma_unmap_sg(&mrioc->pdev->dev, scsi_prot_sglist(scmd), 335562306a36Sopenharmony_ci scsi_prot_sg_count(scmd), scmd->sc_data_direction); 335662306a36Sopenharmony_ci } 335762306a36Sopenharmony_ci mpi3mr_clear_scmd_priv(mrioc, scmd); 335862306a36Sopenharmony_ci scsi_dma_unmap(scmd); 335962306a36Sopenharmony_ci scsi_done(scmd); 336062306a36Sopenharmony_ciout: 336162306a36Sopenharmony_ci if (sense_buf) 336262306a36Sopenharmony_ci mpi3mr_repost_sense_buf(mrioc, 336362306a36Sopenharmony_ci le64_to_cpu(scsi_reply->sense_data_buffer_address)); 336462306a36Sopenharmony_ci} 336562306a36Sopenharmony_ci 336662306a36Sopenharmony_ci/** 336762306a36Sopenharmony_ci * mpi3mr_get_chain_idx - get free chain buffer index 336862306a36Sopenharmony_ci * @mrioc: Adapter instance reference 336962306a36Sopenharmony_ci * 337062306a36Sopenharmony_ci * Try to get a free chain buffer index from the free pool. 337162306a36Sopenharmony_ci * 337262306a36Sopenharmony_ci * Return: -1 on failure or the free chain buffer index 337362306a36Sopenharmony_ci */ 337462306a36Sopenharmony_cistatic int mpi3mr_get_chain_idx(struct mpi3mr_ioc *mrioc) 337562306a36Sopenharmony_ci{ 337662306a36Sopenharmony_ci u8 retry_count = 5; 337762306a36Sopenharmony_ci int cmd_idx = -1; 337862306a36Sopenharmony_ci unsigned long flags; 337962306a36Sopenharmony_ci 338062306a36Sopenharmony_ci spin_lock_irqsave(&mrioc->chain_buf_lock, flags); 338162306a36Sopenharmony_ci do { 338262306a36Sopenharmony_ci cmd_idx = find_first_zero_bit(mrioc->chain_bitmap, 338362306a36Sopenharmony_ci mrioc->chain_buf_count); 338462306a36Sopenharmony_ci if (cmd_idx < mrioc->chain_buf_count) { 338562306a36Sopenharmony_ci set_bit(cmd_idx, mrioc->chain_bitmap); 338662306a36Sopenharmony_ci break; 338762306a36Sopenharmony_ci } 338862306a36Sopenharmony_ci cmd_idx = -1; 338962306a36Sopenharmony_ci } while (retry_count--); 339062306a36Sopenharmony_ci spin_unlock_irqrestore(&mrioc->chain_buf_lock, flags); 339162306a36Sopenharmony_ci return cmd_idx; 339262306a36Sopenharmony_ci} 339362306a36Sopenharmony_ci 339462306a36Sopenharmony_ci/** 339562306a36Sopenharmony_ci * mpi3mr_prepare_sg_scmd - build scatter gather list 339662306a36Sopenharmony_ci * @mrioc: Adapter instance reference 339762306a36Sopenharmony_ci * @scmd: SCSI command reference 339862306a36Sopenharmony_ci * @scsiio_req: MPI3 SCSI IO request 339962306a36Sopenharmony_ci * 340062306a36Sopenharmony_ci * This function maps SCSI command's data and protection SGEs to 340162306a36Sopenharmony_ci * MPI request SGEs. If required additional 4K chain buffer is 340262306a36Sopenharmony_ci * used to send the SGEs. 340362306a36Sopenharmony_ci * 340462306a36Sopenharmony_ci * Return: 0 on success, -ENOMEM on dma_map_sg failure 340562306a36Sopenharmony_ci */ 340662306a36Sopenharmony_cistatic int mpi3mr_prepare_sg_scmd(struct mpi3mr_ioc *mrioc, 340762306a36Sopenharmony_ci struct scsi_cmnd *scmd, struct mpi3_scsi_io_request *scsiio_req) 340862306a36Sopenharmony_ci{ 340962306a36Sopenharmony_ci dma_addr_t chain_dma; 341062306a36Sopenharmony_ci struct scatterlist *sg_scmd; 341162306a36Sopenharmony_ci void *sg_local, *chain; 341262306a36Sopenharmony_ci u32 chain_length; 341362306a36Sopenharmony_ci int sges_left, chain_idx; 341462306a36Sopenharmony_ci u32 sges_in_segment; 341562306a36Sopenharmony_ci u8 simple_sgl_flags; 341662306a36Sopenharmony_ci u8 simple_sgl_flags_last; 341762306a36Sopenharmony_ci u8 last_chain_sgl_flags; 341862306a36Sopenharmony_ci struct chain_element *chain_req; 341962306a36Sopenharmony_ci struct scmd_priv *priv = NULL; 342062306a36Sopenharmony_ci u32 meta_sg = le32_to_cpu(scsiio_req->flags) & 342162306a36Sopenharmony_ci MPI3_SCSIIO_FLAGS_DMAOPERATION_HOST_PI; 342262306a36Sopenharmony_ci 342362306a36Sopenharmony_ci priv = scsi_cmd_priv(scmd); 342462306a36Sopenharmony_ci 342562306a36Sopenharmony_ci simple_sgl_flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE | 342662306a36Sopenharmony_ci MPI3_SGE_FLAGS_DLAS_SYSTEM; 342762306a36Sopenharmony_ci simple_sgl_flags_last = simple_sgl_flags | 342862306a36Sopenharmony_ci MPI3_SGE_FLAGS_END_OF_LIST; 342962306a36Sopenharmony_ci last_chain_sgl_flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_LAST_CHAIN | 343062306a36Sopenharmony_ci MPI3_SGE_FLAGS_DLAS_SYSTEM; 343162306a36Sopenharmony_ci 343262306a36Sopenharmony_ci if (meta_sg) 343362306a36Sopenharmony_ci sg_local = &scsiio_req->sgl[MPI3_SCSIIO_METASGL_INDEX]; 343462306a36Sopenharmony_ci else 343562306a36Sopenharmony_ci sg_local = &scsiio_req->sgl; 343662306a36Sopenharmony_ci 343762306a36Sopenharmony_ci if (!scsiio_req->data_length && !meta_sg) { 343862306a36Sopenharmony_ci mpi3mr_build_zero_len_sge(sg_local); 343962306a36Sopenharmony_ci return 0; 344062306a36Sopenharmony_ci } 344162306a36Sopenharmony_ci 344262306a36Sopenharmony_ci if (meta_sg) { 344362306a36Sopenharmony_ci sg_scmd = scsi_prot_sglist(scmd); 344462306a36Sopenharmony_ci sges_left = dma_map_sg(&mrioc->pdev->dev, 344562306a36Sopenharmony_ci scsi_prot_sglist(scmd), 344662306a36Sopenharmony_ci scsi_prot_sg_count(scmd), 344762306a36Sopenharmony_ci scmd->sc_data_direction); 344862306a36Sopenharmony_ci priv->meta_sg_valid = 1; /* To unmap meta sg DMA */ 344962306a36Sopenharmony_ci } else { 345062306a36Sopenharmony_ci sg_scmd = scsi_sglist(scmd); 345162306a36Sopenharmony_ci sges_left = scsi_dma_map(scmd); 345262306a36Sopenharmony_ci } 345362306a36Sopenharmony_ci 345462306a36Sopenharmony_ci if (sges_left < 0) { 345562306a36Sopenharmony_ci sdev_printk(KERN_ERR, scmd->device, 345662306a36Sopenharmony_ci "scsi_dma_map failed: request for %d bytes!\n", 345762306a36Sopenharmony_ci scsi_bufflen(scmd)); 345862306a36Sopenharmony_ci return -ENOMEM; 345962306a36Sopenharmony_ci } 346062306a36Sopenharmony_ci if (sges_left > mrioc->max_sgl_entries) { 346162306a36Sopenharmony_ci sdev_printk(KERN_ERR, scmd->device, 346262306a36Sopenharmony_ci "scsi_dma_map returned unsupported sge count %d!\n", 346362306a36Sopenharmony_ci sges_left); 346462306a36Sopenharmony_ci return -ENOMEM; 346562306a36Sopenharmony_ci } 346662306a36Sopenharmony_ci 346762306a36Sopenharmony_ci sges_in_segment = (mrioc->facts.op_req_sz - 346862306a36Sopenharmony_ci offsetof(struct mpi3_scsi_io_request, sgl)) / sizeof(struct mpi3_sge_common); 346962306a36Sopenharmony_ci 347062306a36Sopenharmony_ci if (scsiio_req->sgl[0].eedp.flags == 347162306a36Sopenharmony_ci MPI3_SGE_FLAGS_ELEMENT_TYPE_EXTENDED && !meta_sg) { 347262306a36Sopenharmony_ci sg_local += sizeof(struct mpi3_sge_common); 347362306a36Sopenharmony_ci sges_in_segment--; 347462306a36Sopenharmony_ci /* Reserve 1st segment (scsiio_req->sgl[0]) for eedp */ 347562306a36Sopenharmony_ci } 347662306a36Sopenharmony_ci 347762306a36Sopenharmony_ci if (scsiio_req->msg_flags == 347862306a36Sopenharmony_ci MPI3_SCSIIO_MSGFLAGS_METASGL_VALID && !meta_sg) { 347962306a36Sopenharmony_ci sges_in_segment--; 348062306a36Sopenharmony_ci /* Reserve last segment (scsiio_req->sgl[3]) for meta sg */ 348162306a36Sopenharmony_ci } 348262306a36Sopenharmony_ci 348362306a36Sopenharmony_ci if (meta_sg) 348462306a36Sopenharmony_ci sges_in_segment = 1; 348562306a36Sopenharmony_ci 348662306a36Sopenharmony_ci if (sges_left <= sges_in_segment) 348762306a36Sopenharmony_ci goto fill_in_last_segment; 348862306a36Sopenharmony_ci 348962306a36Sopenharmony_ci /* fill in main message segment when there is a chain following */ 349062306a36Sopenharmony_ci while (sges_in_segment > 1) { 349162306a36Sopenharmony_ci mpi3mr_add_sg_single(sg_local, simple_sgl_flags, 349262306a36Sopenharmony_ci sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); 349362306a36Sopenharmony_ci sg_scmd = sg_next(sg_scmd); 349462306a36Sopenharmony_ci sg_local += sizeof(struct mpi3_sge_common); 349562306a36Sopenharmony_ci sges_left--; 349662306a36Sopenharmony_ci sges_in_segment--; 349762306a36Sopenharmony_ci } 349862306a36Sopenharmony_ci 349962306a36Sopenharmony_ci chain_idx = mpi3mr_get_chain_idx(mrioc); 350062306a36Sopenharmony_ci if (chain_idx < 0) 350162306a36Sopenharmony_ci return -1; 350262306a36Sopenharmony_ci chain_req = &mrioc->chain_sgl_list[chain_idx]; 350362306a36Sopenharmony_ci if (meta_sg) 350462306a36Sopenharmony_ci priv->meta_chain_idx = chain_idx; 350562306a36Sopenharmony_ci else 350662306a36Sopenharmony_ci priv->chain_idx = chain_idx; 350762306a36Sopenharmony_ci 350862306a36Sopenharmony_ci chain = chain_req->addr; 350962306a36Sopenharmony_ci chain_dma = chain_req->dma_addr; 351062306a36Sopenharmony_ci sges_in_segment = sges_left; 351162306a36Sopenharmony_ci chain_length = sges_in_segment * sizeof(struct mpi3_sge_common); 351262306a36Sopenharmony_ci 351362306a36Sopenharmony_ci mpi3mr_add_sg_single(sg_local, last_chain_sgl_flags, 351462306a36Sopenharmony_ci chain_length, chain_dma); 351562306a36Sopenharmony_ci 351662306a36Sopenharmony_ci sg_local = chain; 351762306a36Sopenharmony_ci 351862306a36Sopenharmony_cifill_in_last_segment: 351962306a36Sopenharmony_ci while (sges_left > 0) { 352062306a36Sopenharmony_ci if (sges_left == 1) 352162306a36Sopenharmony_ci mpi3mr_add_sg_single(sg_local, 352262306a36Sopenharmony_ci simple_sgl_flags_last, sg_dma_len(sg_scmd), 352362306a36Sopenharmony_ci sg_dma_address(sg_scmd)); 352462306a36Sopenharmony_ci else 352562306a36Sopenharmony_ci mpi3mr_add_sg_single(sg_local, simple_sgl_flags, 352662306a36Sopenharmony_ci sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); 352762306a36Sopenharmony_ci sg_scmd = sg_next(sg_scmd); 352862306a36Sopenharmony_ci sg_local += sizeof(struct mpi3_sge_common); 352962306a36Sopenharmony_ci sges_left--; 353062306a36Sopenharmony_ci } 353162306a36Sopenharmony_ci 353262306a36Sopenharmony_ci return 0; 353362306a36Sopenharmony_ci} 353462306a36Sopenharmony_ci 353562306a36Sopenharmony_ci/** 353662306a36Sopenharmony_ci * mpi3mr_build_sg_scmd - build scatter gather list for SCSI IO 353762306a36Sopenharmony_ci * @mrioc: Adapter instance reference 353862306a36Sopenharmony_ci * @scmd: SCSI command reference 353962306a36Sopenharmony_ci * @scsiio_req: MPI3 SCSI IO request 354062306a36Sopenharmony_ci * 354162306a36Sopenharmony_ci * This function calls mpi3mr_prepare_sg_scmd for constructing 354262306a36Sopenharmony_ci * both data SGEs and protection information SGEs in the MPI 354362306a36Sopenharmony_ci * format from the SCSI Command as appropriate . 354462306a36Sopenharmony_ci * 354562306a36Sopenharmony_ci * Return: return value of mpi3mr_prepare_sg_scmd. 354662306a36Sopenharmony_ci */ 354762306a36Sopenharmony_cistatic int mpi3mr_build_sg_scmd(struct mpi3mr_ioc *mrioc, 354862306a36Sopenharmony_ci struct scsi_cmnd *scmd, struct mpi3_scsi_io_request *scsiio_req) 354962306a36Sopenharmony_ci{ 355062306a36Sopenharmony_ci int ret; 355162306a36Sopenharmony_ci 355262306a36Sopenharmony_ci ret = mpi3mr_prepare_sg_scmd(mrioc, scmd, scsiio_req); 355362306a36Sopenharmony_ci if (ret) 355462306a36Sopenharmony_ci return ret; 355562306a36Sopenharmony_ci 355662306a36Sopenharmony_ci if (scsiio_req->msg_flags == MPI3_SCSIIO_MSGFLAGS_METASGL_VALID) { 355762306a36Sopenharmony_ci /* There is a valid meta sg */ 355862306a36Sopenharmony_ci scsiio_req->flags |= 355962306a36Sopenharmony_ci cpu_to_le32(MPI3_SCSIIO_FLAGS_DMAOPERATION_HOST_PI); 356062306a36Sopenharmony_ci ret = mpi3mr_prepare_sg_scmd(mrioc, scmd, scsiio_req); 356162306a36Sopenharmony_ci } 356262306a36Sopenharmony_ci 356362306a36Sopenharmony_ci return ret; 356462306a36Sopenharmony_ci} 356562306a36Sopenharmony_ci 356662306a36Sopenharmony_ci/** 356762306a36Sopenharmony_ci * mpi3mr_tm_response_name - get TM response as a string 356862306a36Sopenharmony_ci * @resp_code: TM response code 356962306a36Sopenharmony_ci * 357062306a36Sopenharmony_ci * Convert known task management response code as a readable 357162306a36Sopenharmony_ci * string. 357262306a36Sopenharmony_ci * 357362306a36Sopenharmony_ci * Return: response code string. 357462306a36Sopenharmony_ci */ 357562306a36Sopenharmony_cistatic const char *mpi3mr_tm_response_name(u8 resp_code) 357662306a36Sopenharmony_ci{ 357762306a36Sopenharmony_ci char *desc; 357862306a36Sopenharmony_ci 357962306a36Sopenharmony_ci switch (resp_code) { 358062306a36Sopenharmony_ci case MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE: 358162306a36Sopenharmony_ci desc = "task management request completed"; 358262306a36Sopenharmony_ci break; 358362306a36Sopenharmony_ci case MPI3_SCSITASKMGMT_RSPCODE_INVALID_FRAME: 358462306a36Sopenharmony_ci desc = "invalid frame"; 358562306a36Sopenharmony_ci break; 358662306a36Sopenharmony_ci case MPI3_SCSITASKMGMT_RSPCODE_TM_FUNCTION_NOT_SUPPORTED: 358762306a36Sopenharmony_ci desc = "task management request not supported"; 358862306a36Sopenharmony_ci break; 358962306a36Sopenharmony_ci case MPI3_SCSITASKMGMT_RSPCODE_TM_FAILED: 359062306a36Sopenharmony_ci desc = "task management request failed"; 359162306a36Sopenharmony_ci break; 359262306a36Sopenharmony_ci case MPI3_SCSITASKMGMT_RSPCODE_TM_SUCCEEDED: 359362306a36Sopenharmony_ci desc = "task management request succeeded"; 359462306a36Sopenharmony_ci break; 359562306a36Sopenharmony_ci case MPI3_SCSITASKMGMT_RSPCODE_TM_INVALID_LUN: 359662306a36Sopenharmony_ci desc = "invalid LUN"; 359762306a36Sopenharmony_ci break; 359862306a36Sopenharmony_ci case MPI3_SCSITASKMGMT_RSPCODE_TM_OVERLAPPED_TAG: 359962306a36Sopenharmony_ci desc = "overlapped tag attempted"; 360062306a36Sopenharmony_ci break; 360162306a36Sopenharmony_ci case MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC: 360262306a36Sopenharmony_ci desc = "task queued, however not sent to target"; 360362306a36Sopenharmony_ci break; 360462306a36Sopenharmony_ci case MPI3_SCSITASKMGMT_RSPCODE_TM_NVME_DENIED: 360562306a36Sopenharmony_ci desc = "task management request denied by NVMe device"; 360662306a36Sopenharmony_ci break; 360762306a36Sopenharmony_ci default: 360862306a36Sopenharmony_ci desc = "unknown"; 360962306a36Sopenharmony_ci break; 361062306a36Sopenharmony_ci } 361162306a36Sopenharmony_ci 361262306a36Sopenharmony_ci return desc; 361362306a36Sopenharmony_ci} 361462306a36Sopenharmony_ci 361562306a36Sopenharmony_ciinline void mpi3mr_poll_pend_io_completions(struct mpi3mr_ioc *mrioc) 361662306a36Sopenharmony_ci{ 361762306a36Sopenharmony_ci int i; 361862306a36Sopenharmony_ci int num_of_reply_queues = 361962306a36Sopenharmony_ci mrioc->num_op_reply_q + mrioc->op_reply_q_offset; 362062306a36Sopenharmony_ci 362162306a36Sopenharmony_ci for (i = mrioc->op_reply_q_offset; i < num_of_reply_queues; i++) 362262306a36Sopenharmony_ci mpi3mr_process_op_reply_q(mrioc, 362362306a36Sopenharmony_ci mrioc->intr_info[i].op_reply_q); 362462306a36Sopenharmony_ci} 362562306a36Sopenharmony_ci 362662306a36Sopenharmony_ci/** 362762306a36Sopenharmony_ci * mpi3mr_issue_tm - Issue Task Management request 362862306a36Sopenharmony_ci * @mrioc: Adapter instance reference 362962306a36Sopenharmony_ci * @tm_type: Task Management type 363062306a36Sopenharmony_ci * @handle: Device handle 363162306a36Sopenharmony_ci * @lun: lun ID 363262306a36Sopenharmony_ci * @htag: Host tag of the TM request 363362306a36Sopenharmony_ci * @timeout: TM timeout value 363462306a36Sopenharmony_ci * @drv_cmd: Internal command tracker 363562306a36Sopenharmony_ci * @resp_code: Response code place holder 363662306a36Sopenharmony_ci * @scmd: SCSI command 363762306a36Sopenharmony_ci * 363862306a36Sopenharmony_ci * Issues a Task Management Request to the controller for a 363962306a36Sopenharmony_ci * specified target, lun and command and wait for its completion 364062306a36Sopenharmony_ci * and check TM response. Recover the TM if it timed out by 364162306a36Sopenharmony_ci * issuing controller reset. 364262306a36Sopenharmony_ci * 364362306a36Sopenharmony_ci * Return: 0 on success, non-zero on errors 364462306a36Sopenharmony_ci */ 364562306a36Sopenharmony_ciint mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type, 364662306a36Sopenharmony_ci u16 handle, uint lun, u16 htag, ulong timeout, 364762306a36Sopenharmony_ci struct mpi3mr_drv_cmd *drv_cmd, 364862306a36Sopenharmony_ci u8 *resp_code, struct scsi_cmnd *scmd) 364962306a36Sopenharmony_ci{ 365062306a36Sopenharmony_ci struct mpi3_scsi_task_mgmt_request tm_req; 365162306a36Sopenharmony_ci struct mpi3_scsi_task_mgmt_reply *tm_reply = NULL; 365262306a36Sopenharmony_ci int retval = 0; 365362306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgtdev = NULL; 365462306a36Sopenharmony_ci struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data = NULL; 365562306a36Sopenharmony_ci struct scmd_priv *cmd_priv = NULL; 365662306a36Sopenharmony_ci struct scsi_device *sdev = NULL; 365762306a36Sopenharmony_ci struct mpi3mr_sdev_priv_data *sdev_priv_data = NULL; 365862306a36Sopenharmony_ci 365962306a36Sopenharmony_ci ioc_info(mrioc, "%s :Issue TM: TM type (0x%x) for devhandle 0x%04x\n", 366062306a36Sopenharmony_ci __func__, tm_type, handle); 366162306a36Sopenharmony_ci if (mrioc->unrecoverable) { 366262306a36Sopenharmony_ci retval = -1; 366362306a36Sopenharmony_ci ioc_err(mrioc, "%s :Issue TM: Unrecoverable controller\n", 366462306a36Sopenharmony_ci __func__); 366562306a36Sopenharmony_ci goto out; 366662306a36Sopenharmony_ci } 366762306a36Sopenharmony_ci 366862306a36Sopenharmony_ci memset(&tm_req, 0, sizeof(tm_req)); 366962306a36Sopenharmony_ci mutex_lock(&drv_cmd->mutex); 367062306a36Sopenharmony_ci if (drv_cmd->state & MPI3MR_CMD_PENDING) { 367162306a36Sopenharmony_ci retval = -1; 367262306a36Sopenharmony_ci ioc_err(mrioc, "%s :Issue TM: Command is in use\n", __func__); 367362306a36Sopenharmony_ci mutex_unlock(&drv_cmd->mutex); 367462306a36Sopenharmony_ci goto out; 367562306a36Sopenharmony_ci } 367662306a36Sopenharmony_ci if (mrioc->reset_in_progress) { 367762306a36Sopenharmony_ci retval = -1; 367862306a36Sopenharmony_ci ioc_err(mrioc, "%s :Issue TM: Reset in progress\n", __func__); 367962306a36Sopenharmony_ci mutex_unlock(&drv_cmd->mutex); 368062306a36Sopenharmony_ci goto out; 368162306a36Sopenharmony_ci } 368262306a36Sopenharmony_ci 368362306a36Sopenharmony_ci drv_cmd->state = MPI3MR_CMD_PENDING; 368462306a36Sopenharmony_ci drv_cmd->is_waiting = 1; 368562306a36Sopenharmony_ci drv_cmd->callback = NULL; 368662306a36Sopenharmony_ci tm_req.dev_handle = cpu_to_le16(handle); 368762306a36Sopenharmony_ci tm_req.task_type = tm_type; 368862306a36Sopenharmony_ci tm_req.host_tag = cpu_to_le16(htag); 368962306a36Sopenharmony_ci 369062306a36Sopenharmony_ci int_to_scsilun(lun, (struct scsi_lun *)tm_req.lun); 369162306a36Sopenharmony_ci tm_req.function = MPI3_FUNCTION_SCSI_TASK_MGMT; 369262306a36Sopenharmony_ci 369362306a36Sopenharmony_ci tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, handle); 369462306a36Sopenharmony_ci 369562306a36Sopenharmony_ci if (scmd) { 369662306a36Sopenharmony_ci sdev = scmd->device; 369762306a36Sopenharmony_ci sdev_priv_data = sdev->hostdata; 369862306a36Sopenharmony_ci scsi_tgt_priv_data = ((sdev_priv_data) ? 369962306a36Sopenharmony_ci sdev_priv_data->tgt_priv_data : NULL); 370062306a36Sopenharmony_ci } else { 370162306a36Sopenharmony_ci if (tgtdev && tgtdev->starget && tgtdev->starget->hostdata) 370262306a36Sopenharmony_ci scsi_tgt_priv_data = (struct mpi3mr_stgt_priv_data *) 370362306a36Sopenharmony_ci tgtdev->starget->hostdata; 370462306a36Sopenharmony_ci } 370562306a36Sopenharmony_ci 370662306a36Sopenharmony_ci if (scsi_tgt_priv_data) 370762306a36Sopenharmony_ci atomic_inc(&scsi_tgt_priv_data->block_io); 370862306a36Sopenharmony_ci 370962306a36Sopenharmony_ci if (tgtdev && (tgtdev->dev_type == MPI3_DEVICE_DEVFORM_PCIE)) { 371062306a36Sopenharmony_ci if (cmd_priv && tgtdev->dev_spec.pcie_inf.abort_to) 371162306a36Sopenharmony_ci timeout = tgtdev->dev_spec.pcie_inf.abort_to; 371262306a36Sopenharmony_ci else if (!cmd_priv && tgtdev->dev_spec.pcie_inf.reset_to) 371362306a36Sopenharmony_ci timeout = tgtdev->dev_spec.pcie_inf.reset_to; 371462306a36Sopenharmony_ci } 371562306a36Sopenharmony_ci 371662306a36Sopenharmony_ci init_completion(&drv_cmd->done); 371762306a36Sopenharmony_ci retval = mpi3mr_admin_request_post(mrioc, &tm_req, sizeof(tm_req), 1); 371862306a36Sopenharmony_ci if (retval) { 371962306a36Sopenharmony_ci ioc_err(mrioc, "%s :Issue TM: Admin Post failed\n", __func__); 372062306a36Sopenharmony_ci goto out_unlock; 372162306a36Sopenharmony_ci } 372262306a36Sopenharmony_ci wait_for_completion_timeout(&drv_cmd->done, (timeout * HZ)); 372362306a36Sopenharmony_ci 372462306a36Sopenharmony_ci if (!(drv_cmd->state & MPI3MR_CMD_COMPLETE)) { 372562306a36Sopenharmony_ci drv_cmd->is_waiting = 0; 372662306a36Sopenharmony_ci retval = -1; 372762306a36Sopenharmony_ci if (!(drv_cmd->state & MPI3MR_CMD_RESET)) { 372862306a36Sopenharmony_ci dprint_tm(mrioc, 372962306a36Sopenharmony_ci "task management request timed out after %ld seconds\n", 373062306a36Sopenharmony_ci timeout); 373162306a36Sopenharmony_ci if (mrioc->logging_level & MPI3_DEBUG_TM) 373262306a36Sopenharmony_ci dprint_dump_req(&tm_req, sizeof(tm_req)/4); 373362306a36Sopenharmony_ci mpi3mr_soft_reset_handler(mrioc, 373462306a36Sopenharmony_ci MPI3MR_RESET_FROM_TM_TIMEOUT, 1); 373562306a36Sopenharmony_ci } 373662306a36Sopenharmony_ci goto out_unlock; 373762306a36Sopenharmony_ci } 373862306a36Sopenharmony_ci 373962306a36Sopenharmony_ci if (!(drv_cmd->state & MPI3MR_CMD_REPLY_VALID)) { 374062306a36Sopenharmony_ci dprint_tm(mrioc, "invalid task management reply message\n"); 374162306a36Sopenharmony_ci retval = -1; 374262306a36Sopenharmony_ci goto out_unlock; 374362306a36Sopenharmony_ci } 374462306a36Sopenharmony_ci 374562306a36Sopenharmony_ci tm_reply = (struct mpi3_scsi_task_mgmt_reply *)drv_cmd->reply; 374662306a36Sopenharmony_ci 374762306a36Sopenharmony_ci switch (drv_cmd->ioc_status) { 374862306a36Sopenharmony_ci case MPI3_IOCSTATUS_SUCCESS: 374962306a36Sopenharmony_ci *resp_code = le32_to_cpu(tm_reply->response_data) & 375062306a36Sopenharmony_ci MPI3MR_RI_MASK_RESPCODE; 375162306a36Sopenharmony_ci break; 375262306a36Sopenharmony_ci case MPI3_IOCSTATUS_SCSI_IOC_TERMINATED: 375362306a36Sopenharmony_ci *resp_code = MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE; 375462306a36Sopenharmony_ci break; 375562306a36Sopenharmony_ci default: 375662306a36Sopenharmony_ci dprint_tm(mrioc, 375762306a36Sopenharmony_ci "task management request to handle(0x%04x) is failed with ioc_status(0x%04x) log_info(0x%08x)\n", 375862306a36Sopenharmony_ci handle, drv_cmd->ioc_status, drv_cmd->ioc_loginfo); 375962306a36Sopenharmony_ci retval = -1; 376062306a36Sopenharmony_ci goto out_unlock; 376162306a36Sopenharmony_ci } 376262306a36Sopenharmony_ci 376362306a36Sopenharmony_ci switch (*resp_code) { 376462306a36Sopenharmony_ci case MPI3_SCSITASKMGMT_RSPCODE_TM_SUCCEEDED: 376562306a36Sopenharmony_ci case MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE: 376662306a36Sopenharmony_ci break; 376762306a36Sopenharmony_ci case MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC: 376862306a36Sopenharmony_ci if (tm_type != MPI3_SCSITASKMGMT_TASKTYPE_QUERY_TASK) 376962306a36Sopenharmony_ci retval = -1; 377062306a36Sopenharmony_ci break; 377162306a36Sopenharmony_ci default: 377262306a36Sopenharmony_ci retval = -1; 377362306a36Sopenharmony_ci break; 377462306a36Sopenharmony_ci } 377562306a36Sopenharmony_ci 377662306a36Sopenharmony_ci dprint_tm(mrioc, 377762306a36Sopenharmony_ci "task management request type(%d) completed for handle(0x%04x) with ioc_status(0x%04x), log_info(0x%08x), termination_count(%d), response:%s(0x%x)\n", 377862306a36Sopenharmony_ci tm_type, handle, drv_cmd->ioc_status, drv_cmd->ioc_loginfo, 377962306a36Sopenharmony_ci le32_to_cpu(tm_reply->termination_count), 378062306a36Sopenharmony_ci mpi3mr_tm_response_name(*resp_code), *resp_code); 378162306a36Sopenharmony_ci 378262306a36Sopenharmony_ci if (!retval) { 378362306a36Sopenharmony_ci mpi3mr_ioc_disable_intr(mrioc); 378462306a36Sopenharmony_ci mpi3mr_poll_pend_io_completions(mrioc); 378562306a36Sopenharmony_ci mpi3mr_ioc_enable_intr(mrioc); 378662306a36Sopenharmony_ci mpi3mr_poll_pend_io_completions(mrioc); 378762306a36Sopenharmony_ci mpi3mr_process_admin_reply_q(mrioc); 378862306a36Sopenharmony_ci } 378962306a36Sopenharmony_ci switch (tm_type) { 379062306a36Sopenharmony_ci case MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET: 379162306a36Sopenharmony_ci if (!scsi_tgt_priv_data) 379262306a36Sopenharmony_ci break; 379362306a36Sopenharmony_ci scsi_tgt_priv_data->pend_count = 0; 379462306a36Sopenharmony_ci blk_mq_tagset_busy_iter(&mrioc->shost->tag_set, 379562306a36Sopenharmony_ci mpi3mr_count_tgt_pending, 379662306a36Sopenharmony_ci (void *)scsi_tgt_priv_data->starget); 379762306a36Sopenharmony_ci break; 379862306a36Sopenharmony_ci case MPI3_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET: 379962306a36Sopenharmony_ci if (!sdev_priv_data) 380062306a36Sopenharmony_ci break; 380162306a36Sopenharmony_ci sdev_priv_data->pend_count = 0; 380262306a36Sopenharmony_ci blk_mq_tagset_busy_iter(&mrioc->shost->tag_set, 380362306a36Sopenharmony_ci mpi3mr_count_dev_pending, (void *)sdev); 380462306a36Sopenharmony_ci break; 380562306a36Sopenharmony_ci default: 380662306a36Sopenharmony_ci break; 380762306a36Sopenharmony_ci } 380862306a36Sopenharmony_ci 380962306a36Sopenharmony_ciout_unlock: 381062306a36Sopenharmony_ci drv_cmd->state = MPI3MR_CMD_NOTUSED; 381162306a36Sopenharmony_ci mutex_unlock(&drv_cmd->mutex); 381262306a36Sopenharmony_ci if (scsi_tgt_priv_data) 381362306a36Sopenharmony_ci atomic_dec_if_positive(&scsi_tgt_priv_data->block_io); 381462306a36Sopenharmony_ci if (tgtdev) 381562306a36Sopenharmony_ci mpi3mr_tgtdev_put(tgtdev); 381662306a36Sopenharmony_ciout: 381762306a36Sopenharmony_ci return retval; 381862306a36Sopenharmony_ci} 381962306a36Sopenharmony_ci 382062306a36Sopenharmony_ci/** 382162306a36Sopenharmony_ci * mpi3mr_bios_param - BIOS param callback 382262306a36Sopenharmony_ci * @sdev: SCSI device reference 382362306a36Sopenharmony_ci * @bdev: Block device reference 382462306a36Sopenharmony_ci * @capacity: Capacity in logical sectors 382562306a36Sopenharmony_ci * @params: Parameter array 382662306a36Sopenharmony_ci * 382762306a36Sopenharmony_ci * Just the parameters with heads/secots/cylinders. 382862306a36Sopenharmony_ci * 382962306a36Sopenharmony_ci * Return: 0 always 383062306a36Sopenharmony_ci */ 383162306a36Sopenharmony_cistatic int mpi3mr_bios_param(struct scsi_device *sdev, 383262306a36Sopenharmony_ci struct block_device *bdev, sector_t capacity, int params[]) 383362306a36Sopenharmony_ci{ 383462306a36Sopenharmony_ci int heads; 383562306a36Sopenharmony_ci int sectors; 383662306a36Sopenharmony_ci sector_t cylinders; 383762306a36Sopenharmony_ci ulong dummy; 383862306a36Sopenharmony_ci 383962306a36Sopenharmony_ci heads = 64; 384062306a36Sopenharmony_ci sectors = 32; 384162306a36Sopenharmony_ci 384262306a36Sopenharmony_ci dummy = heads * sectors; 384362306a36Sopenharmony_ci cylinders = capacity; 384462306a36Sopenharmony_ci sector_div(cylinders, dummy); 384562306a36Sopenharmony_ci 384662306a36Sopenharmony_ci if ((ulong)capacity >= 0x200000) { 384762306a36Sopenharmony_ci heads = 255; 384862306a36Sopenharmony_ci sectors = 63; 384962306a36Sopenharmony_ci dummy = heads * sectors; 385062306a36Sopenharmony_ci cylinders = capacity; 385162306a36Sopenharmony_ci sector_div(cylinders, dummy); 385262306a36Sopenharmony_ci } 385362306a36Sopenharmony_ci 385462306a36Sopenharmony_ci params[0] = heads; 385562306a36Sopenharmony_ci params[1] = sectors; 385662306a36Sopenharmony_ci params[2] = cylinders; 385762306a36Sopenharmony_ci return 0; 385862306a36Sopenharmony_ci} 385962306a36Sopenharmony_ci 386062306a36Sopenharmony_ci/** 386162306a36Sopenharmony_ci * mpi3mr_map_queues - Map queues callback handler 386262306a36Sopenharmony_ci * @shost: SCSI host reference 386362306a36Sopenharmony_ci * 386462306a36Sopenharmony_ci * Maps default and poll queues. 386562306a36Sopenharmony_ci * 386662306a36Sopenharmony_ci * Return: return zero. 386762306a36Sopenharmony_ci */ 386862306a36Sopenharmony_cistatic void mpi3mr_map_queues(struct Scsi_Host *shost) 386962306a36Sopenharmony_ci{ 387062306a36Sopenharmony_ci struct mpi3mr_ioc *mrioc = shost_priv(shost); 387162306a36Sopenharmony_ci int i, qoff, offset; 387262306a36Sopenharmony_ci struct blk_mq_queue_map *map = NULL; 387362306a36Sopenharmony_ci 387462306a36Sopenharmony_ci offset = mrioc->op_reply_q_offset; 387562306a36Sopenharmony_ci 387662306a36Sopenharmony_ci for (i = 0, qoff = 0; i < HCTX_MAX_TYPES; i++) { 387762306a36Sopenharmony_ci map = &shost->tag_set.map[i]; 387862306a36Sopenharmony_ci 387962306a36Sopenharmony_ci map->nr_queues = 0; 388062306a36Sopenharmony_ci 388162306a36Sopenharmony_ci if (i == HCTX_TYPE_DEFAULT) 388262306a36Sopenharmony_ci map->nr_queues = mrioc->default_qcount; 388362306a36Sopenharmony_ci else if (i == HCTX_TYPE_POLL) 388462306a36Sopenharmony_ci map->nr_queues = mrioc->active_poll_qcount; 388562306a36Sopenharmony_ci 388662306a36Sopenharmony_ci if (!map->nr_queues) { 388762306a36Sopenharmony_ci BUG_ON(i == HCTX_TYPE_DEFAULT); 388862306a36Sopenharmony_ci continue; 388962306a36Sopenharmony_ci } 389062306a36Sopenharmony_ci 389162306a36Sopenharmony_ci /* 389262306a36Sopenharmony_ci * The poll queue(s) doesn't have an IRQ (and hence IRQ 389362306a36Sopenharmony_ci * affinity), so use the regular blk-mq cpu mapping 389462306a36Sopenharmony_ci */ 389562306a36Sopenharmony_ci map->queue_offset = qoff; 389662306a36Sopenharmony_ci if (i != HCTX_TYPE_POLL) 389762306a36Sopenharmony_ci blk_mq_pci_map_queues(map, mrioc->pdev, offset); 389862306a36Sopenharmony_ci else 389962306a36Sopenharmony_ci blk_mq_map_queues(map); 390062306a36Sopenharmony_ci 390162306a36Sopenharmony_ci qoff += map->nr_queues; 390262306a36Sopenharmony_ci offset += map->nr_queues; 390362306a36Sopenharmony_ci } 390462306a36Sopenharmony_ci} 390562306a36Sopenharmony_ci 390662306a36Sopenharmony_ci/** 390762306a36Sopenharmony_ci * mpi3mr_get_fw_pending_ios - Calculate pending I/O count 390862306a36Sopenharmony_ci * @mrioc: Adapter instance reference 390962306a36Sopenharmony_ci * 391062306a36Sopenharmony_ci * Calculate the pending I/Os for the controller and return. 391162306a36Sopenharmony_ci * 391262306a36Sopenharmony_ci * Return: Number of pending I/Os 391362306a36Sopenharmony_ci */ 391462306a36Sopenharmony_cistatic inline int mpi3mr_get_fw_pending_ios(struct mpi3mr_ioc *mrioc) 391562306a36Sopenharmony_ci{ 391662306a36Sopenharmony_ci u16 i; 391762306a36Sopenharmony_ci uint pend_ios = 0; 391862306a36Sopenharmony_ci 391962306a36Sopenharmony_ci for (i = 0; i < mrioc->num_op_reply_q; i++) 392062306a36Sopenharmony_ci pend_ios += atomic_read(&mrioc->op_reply_qinfo[i].pend_ios); 392162306a36Sopenharmony_ci return pend_ios; 392262306a36Sopenharmony_ci} 392362306a36Sopenharmony_ci 392462306a36Sopenharmony_ci/** 392562306a36Sopenharmony_ci * mpi3mr_print_pending_host_io - print pending I/Os 392662306a36Sopenharmony_ci * @mrioc: Adapter instance reference 392762306a36Sopenharmony_ci * 392862306a36Sopenharmony_ci * Print number of pending I/Os and each I/O details prior to 392962306a36Sopenharmony_ci * reset for debug purpose. 393062306a36Sopenharmony_ci * 393162306a36Sopenharmony_ci * Return: Nothing 393262306a36Sopenharmony_ci */ 393362306a36Sopenharmony_cistatic void mpi3mr_print_pending_host_io(struct mpi3mr_ioc *mrioc) 393462306a36Sopenharmony_ci{ 393562306a36Sopenharmony_ci struct Scsi_Host *shost = mrioc->shost; 393662306a36Sopenharmony_ci 393762306a36Sopenharmony_ci ioc_info(mrioc, "%s :Pending commands prior to reset: %d\n", 393862306a36Sopenharmony_ci __func__, mpi3mr_get_fw_pending_ios(mrioc)); 393962306a36Sopenharmony_ci blk_mq_tagset_busy_iter(&shost->tag_set, 394062306a36Sopenharmony_ci mpi3mr_print_scmd, (void *)mrioc); 394162306a36Sopenharmony_ci} 394262306a36Sopenharmony_ci 394362306a36Sopenharmony_ci/** 394462306a36Sopenharmony_ci * mpi3mr_wait_for_host_io - block for I/Os to complete 394562306a36Sopenharmony_ci * @mrioc: Adapter instance reference 394662306a36Sopenharmony_ci * @timeout: time out in seconds 394762306a36Sopenharmony_ci * Waits for pending I/Os for the given adapter to complete or 394862306a36Sopenharmony_ci * to hit the timeout. 394962306a36Sopenharmony_ci * 395062306a36Sopenharmony_ci * Return: Nothing 395162306a36Sopenharmony_ci */ 395262306a36Sopenharmony_civoid mpi3mr_wait_for_host_io(struct mpi3mr_ioc *mrioc, u32 timeout) 395362306a36Sopenharmony_ci{ 395462306a36Sopenharmony_ci enum mpi3mr_iocstate iocstate; 395562306a36Sopenharmony_ci int i = 0; 395662306a36Sopenharmony_ci 395762306a36Sopenharmony_ci iocstate = mpi3mr_get_iocstate(mrioc); 395862306a36Sopenharmony_ci if (iocstate != MRIOC_STATE_READY) 395962306a36Sopenharmony_ci return; 396062306a36Sopenharmony_ci 396162306a36Sopenharmony_ci if (!mpi3mr_get_fw_pending_ios(mrioc)) 396262306a36Sopenharmony_ci return; 396362306a36Sopenharmony_ci ioc_info(mrioc, 396462306a36Sopenharmony_ci "%s :Waiting for %d seconds prior to reset for %d I/O\n", 396562306a36Sopenharmony_ci __func__, timeout, mpi3mr_get_fw_pending_ios(mrioc)); 396662306a36Sopenharmony_ci 396762306a36Sopenharmony_ci for (i = 0; i < timeout; i++) { 396862306a36Sopenharmony_ci if (!mpi3mr_get_fw_pending_ios(mrioc)) 396962306a36Sopenharmony_ci break; 397062306a36Sopenharmony_ci iocstate = mpi3mr_get_iocstate(mrioc); 397162306a36Sopenharmony_ci if (iocstate != MRIOC_STATE_READY) 397262306a36Sopenharmony_ci break; 397362306a36Sopenharmony_ci msleep(1000); 397462306a36Sopenharmony_ci } 397562306a36Sopenharmony_ci 397662306a36Sopenharmony_ci ioc_info(mrioc, "%s :Pending I/Os after wait is: %d\n", __func__, 397762306a36Sopenharmony_ci mpi3mr_get_fw_pending_ios(mrioc)); 397862306a36Sopenharmony_ci} 397962306a36Sopenharmony_ci 398062306a36Sopenharmony_ci/** 398162306a36Sopenharmony_ci * mpi3mr_setup_divert_ws - Setup Divert IO flag for write same 398262306a36Sopenharmony_ci * @mrioc: Adapter instance reference 398362306a36Sopenharmony_ci * @scmd: SCSI command reference 398462306a36Sopenharmony_ci * @scsiio_req: MPI3 SCSI IO request 398562306a36Sopenharmony_ci * @scsiio_flags: Pointer to MPI3 SCSI IO Flags 398662306a36Sopenharmony_ci * @wslen: write same max length 398762306a36Sopenharmony_ci * 398862306a36Sopenharmony_ci * Gets values of unmap, ndob and number of blocks from write 398962306a36Sopenharmony_ci * same scsi io and based on these values it sets divert IO flag 399062306a36Sopenharmony_ci * and reason for diverting IO to firmware. 399162306a36Sopenharmony_ci * 399262306a36Sopenharmony_ci * Return: Nothing 399362306a36Sopenharmony_ci */ 399462306a36Sopenharmony_cistatic inline void mpi3mr_setup_divert_ws(struct mpi3mr_ioc *mrioc, 399562306a36Sopenharmony_ci struct scsi_cmnd *scmd, struct mpi3_scsi_io_request *scsiio_req, 399662306a36Sopenharmony_ci u32 *scsiio_flags, u16 wslen) 399762306a36Sopenharmony_ci{ 399862306a36Sopenharmony_ci u8 unmap = 0, ndob = 0; 399962306a36Sopenharmony_ci u8 opcode = scmd->cmnd[0]; 400062306a36Sopenharmony_ci u32 num_blocks = 0; 400162306a36Sopenharmony_ci u16 sa = (scmd->cmnd[8] << 8) | (scmd->cmnd[9]); 400262306a36Sopenharmony_ci 400362306a36Sopenharmony_ci if (opcode == WRITE_SAME_16) { 400462306a36Sopenharmony_ci unmap = scmd->cmnd[1] & 0x08; 400562306a36Sopenharmony_ci ndob = scmd->cmnd[1] & 0x01; 400662306a36Sopenharmony_ci num_blocks = get_unaligned_be32(scmd->cmnd + 10); 400762306a36Sopenharmony_ci } else if ((opcode == VARIABLE_LENGTH_CMD) && (sa == WRITE_SAME_32)) { 400862306a36Sopenharmony_ci unmap = scmd->cmnd[10] & 0x08; 400962306a36Sopenharmony_ci ndob = scmd->cmnd[10] & 0x01; 401062306a36Sopenharmony_ci num_blocks = get_unaligned_be32(scmd->cmnd + 28); 401162306a36Sopenharmony_ci } else 401262306a36Sopenharmony_ci return; 401362306a36Sopenharmony_ci 401462306a36Sopenharmony_ci if ((unmap) && (ndob) && (num_blocks > wslen)) { 401562306a36Sopenharmony_ci scsiio_req->msg_flags |= 401662306a36Sopenharmony_ci MPI3_SCSIIO_MSGFLAGS_DIVERT_TO_FIRMWARE; 401762306a36Sopenharmony_ci *scsiio_flags |= 401862306a36Sopenharmony_ci MPI3_SCSIIO_FLAGS_DIVERT_REASON_WRITE_SAME_TOO_LARGE; 401962306a36Sopenharmony_ci } 402062306a36Sopenharmony_ci} 402162306a36Sopenharmony_ci 402262306a36Sopenharmony_ci/** 402362306a36Sopenharmony_ci * mpi3mr_eh_host_reset - Host reset error handling callback 402462306a36Sopenharmony_ci * @scmd: SCSI command reference 402562306a36Sopenharmony_ci * 402662306a36Sopenharmony_ci * Issue controller reset if the scmd is for a Physical Device, 402762306a36Sopenharmony_ci * if the scmd is for RAID volume, then wait for 402862306a36Sopenharmony_ci * MPI3MR_RAID_ERRREC_RESET_TIMEOUT and checke whether any 402962306a36Sopenharmony_ci * pending I/Os prior to issuing reset to the controller. 403062306a36Sopenharmony_ci * 403162306a36Sopenharmony_ci * Return: SUCCESS of successful reset else FAILED 403262306a36Sopenharmony_ci */ 403362306a36Sopenharmony_cistatic int mpi3mr_eh_host_reset(struct scsi_cmnd *scmd) 403462306a36Sopenharmony_ci{ 403562306a36Sopenharmony_ci struct mpi3mr_ioc *mrioc = shost_priv(scmd->device->host); 403662306a36Sopenharmony_ci struct mpi3mr_stgt_priv_data *stgt_priv_data; 403762306a36Sopenharmony_ci struct mpi3mr_sdev_priv_data *sdev_priv_data; 403862306a36Sopenharmony_ci u8 dev_type = MPI3_DEVICE_DEVFORM_VD; 403962306a36Sopenharmony_ci int retval = FAILED, ret; 404062306a36Sopenharmony_ci 404162306a36Sopenharmony_ci sdev_priv_data = scmd->device->hostdata; 404262306a36Sopenharmony_ci if (sdev_priv_data && sdev_priv_data->tgt_priv_data) { 404362306a36Sopenharmony_ci stgt_priv_data = sdev_priv_data->tgt_priv_data; 404462306a36Sopenharmony_ci dev_type = stgt_priv_data->dev_type; 404562306a36Sopenharmony_ci } 404662306a36Sopenharmony_ci 404762306a36Sopenharmony_ci if (dev_type == MPI3_DEVICE_DEVFORM_VD) { 404862306a36Sopenharmony_ci mpi3mr_wait_for_host_io(mrioc, 404962306a36Sopenharmony_ci MPI3MR_RAID_ERRREC_RESET_TIMEOUT); 405062306a36Sopenharmony_ci if (!mpi3mr_get_fw_pending_ios(mrioc)) { 405162306a36Sopenharmony_ci retval = SUCCESS; 405262306a36Sopenharmony_ci goto out; 405362306a36Sopenharmony_ci } 405462306a36Sopenharmony_ci } 405562306a36Sopenharmony_ci 405662306a36Sopenharmony_ci mpi3mr_print_pending_host_io(mrioc); 405762306a36Sopenharmony_ci ret = mpi3mr_soft_reset_handler(mrioc, 405862306a36Sopenharmony_ci MPI3MR_RESET_FROM_EH_HOS, 1); 405962306a36Sopenharmony_ci if (ret) 406062306a36Sopenharmony_ci goto out; 406162306a36Sopenharmony_ci 406262306a36Sopenharmony_ci retval = SUCCESS; 406362306a36Sopenharmony_ciout: 406462306a36Sopenharmony_ci sdev_printk(KERN_INFO, scmd->device, 406562306a36Sopenharmony_ci "Host reset is %s for scmd(%p)\n", 406662306a36Sopenharmony_ci ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); 406762306a36Sopenharmony_ci 406862306a36Sopenharmony_ci return retval; 406962306a36Sopenharmony_ci} 407062306a36Sopenharmony_ci 407162306a36Sopenharmony_ci/** 407262306a36Sopenharmony_ci * mpi3mr_eh_target_reset - Target reset error handling callback 407362306a36Sopenharmony_ci * @scmd: SCSI command reference 407462306a36Sopenharmony_ci * 407562306a36Sopenharmony_ci * Issue Target reset Task Management and verify the scmd is 407662306a36Sopenharmony_ci * terminated successfully and return status accordingly. 407762306a36Sopenharmony_ci * 407862306a36Sopenharmony_ci * Return: SUCCESS of successful termination of the scmd else 407962306a36Sopenharmony_ci * FAILED 408062306a36Sopenharmony_ci */ 408162306a36Sopenharmony_cistatic int mpi3mr_eh_target_reset(struct scsi_cmnd *scmd) 408262306a36Sopenharmony_ci{ 408362306a36Sopenharmony_ci struct mpi3mr_ioc *mrioc = shost_priv(scmd->device->host); 408462306a36Sopenharmony_ci struct mpi3mr_stgt_priv_data *stgt_priv_data; 408562306a36Sopenharmony_ci struct mpi3mr_sdev_priv_data *sdev_priv_data; 408662306a36Sopenharmony_ci u16 dev_handle; 408762306a36Sopenharmony_ci u8 resp_code = 0; 408862306a36Sopenharmony_ci int retval = FAILED, ret = 0; 408962306a36Sopenharmony_ci 409062306a36Sopenharmony_ci sdev_printk(KERN_INFO, scmd->device, 409162306a36Sopenharmony_ci "Attempting Target Reset! scmd(%p)\n", scmd); 409262306a36Sopenharmony_ci scsi_print_command(scmd); 409362306a36Sopenharmony_ci 409462306a36Sopenharmony_ci sdev_priv_data = scmd->device->hostdata; 409562306a36Sopenharmony_ci if (!sdev_priv_data || !sdev_priv_data->tgt_priv_data) { 409662306a36Sopenharmony_ci sdev_printk(KERN_INFO, scmd->device, 409762306a36Sopenharmony_ci "SCSI device is not available\n"); 409862306a36Sopenharmony_ci retval = SUCCESS; 409962306a36Sopenharmony_ci goto out; 410062306a36Sopenharmony_ci } 410162306a36Sopenharmony_ci 410262306a36Sopenharmony_ci stgt_priv_data = sdev_priv_data->tgt_priv_data; 410362306a36Sopenharmony_ci dev_handle = stgt_priv_data->dev_handle; 410462306a36Sopenharmony_ci if (stgt_priv_data->dev_removed) { 410562306a36Sopenharmony_ci struct scmd_priv *cmd_priv = scsi_cmd_priv(scmd); 410662306a36Sopenharmony_ci sdev_printk(KERN_INFO, scmd->device, 410762306a36Sopenharmony_ci "%s:target(handle = 0x%04x) is removed, target reset is not issued\n", 410862306a36Sopenharmony_ci mrioc->name, dev_handle); 410962306a36Sopenharmony_ci if (!cmd_priv->in_lld_scope || cmd_priv->host_tag == MPI3MR_HOSTTAG_INVALID) 411062306a36Sopenharmony_ci retval = SUCCESS; 411162306a36Sopenharmony_ci else 411262306a36Sopenharmony_ci retval = FAILED; 411362306a36Sopenharmony_ci goto out; 411462306a36Sopenharmony_ci } 411562306a36Sopenharmony_ci sdev_printk(KERN_INFO, scmd->device, 411662306a36Sopenharmony_ci "Target Reset is issued to handle(0x%04x)\n", 411762306a36Sopenharmony_ci dev_handle); 411862306a36Sopenharmony_ci 411962306a36Sopenharmony_ci ret = mpi3mr_issue_tm(mrioc, 412062306a36Sopenharmony_ci MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET, dev_handle, 412162306a36Sopenharmony_ci sdev_priv_data->lun_id, MPI3MR_HOSTTAG_BLK_TMS, 412262306a36Sopenharmony_ci MPI3MR_RESETTM_TIMEOUT, &mrioc->host_tm_cmds, &resp_code, scmd); 412362306a36Sopenharmony_ci 412462306a36Sopenharmony_ci if (ret) 412562306a36Sopenharmony_ci goto out; 412662306a36Sopenharmony_ci 412762306a36Sopenharmony_ci if (stgt_priv_data->pend_count) { 412862306a36Sopenharmony_ci sdev_printk(KERN_INFO, scmd->device, 412962306a36Sopenharmony_ci "%s: target has %d pending commands, target reset is failed\n", 413062306a36Sopenharmony_ci mrioc->name, stgt_priv_data->pend_count); 413162306a36Sopenharmony_ci goto out; 413262306a36Sopenharmony_ci } 413362306a36Sopenharmony_ci 413462306a36Sopenharmony_ci retval = SUCCESS; 413562306a36Sopenharmony_ciout: 413662306a36Sopenharmony_ci sdev_printk(KERN_INFO, scmd->device, 413762306a36Sopenharmony_ci "%s: target reset is %s for scmd(%p)\n", mrioc->name, 413862306a36Sopenharmony_ci ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); 413962306a36Sopenharmony_ci 414062306a36Sopenharmony_ci return retval; 414162306a36Sopenharmony_ci} 414262306a36Sopenharmony_ci 414362306a36Sopenharmony_ci/** 414462306a36Sopenharmony_ci * mpi3mr_eh_dev_reset- Device reset error handling callback 414562306a36Sopenharmony_ci * @scmd: SCSI command reference 414662306a36Sopenharmony_ci * 414762306a36Sopenharmony_ci * Issue lun reset Task Management and verify the scmd is 414862306a36Sopenharmony_ci * terminated successfully and return status accordingly. 414962306a36Sopenharmony_ci * 415062306a36Sopenharmony_ci * Return: SUCCESS of successful termination of the scmd else 415162306a36Sopenharmony_ci * FAILED 415262306a36Sopenharmony_ci */ 415362306a36Sopenharmony_cistatic int mpi3mr_eh_dev_reset(struct scsi_cmnd *scmd) 415462306a36Sopenharmony_ci{ 415562306a36Sopenharmony_ci struct mpi3mr_ioc *mrioc = shost_priv(scmd->device->host); 415662306a36Sopenharmony_ci struct mpi3mr_stgt_priv_data *stgt_priv_data; 415762306a36Sopenharmony_ci struct mpi3mr_sdev_priv_data *sdev_priv_data; 415862306a36Sopenharmony_ci u16 dev_handle; 415962306a36Sopenharmony_ci u8 resp_code = 0; 416062306a36Sopenharmony_ci int retval = FAILED, ret = 0; 416162306a36Sopenharmony_ci 416262306a36Sopenharmony_ci sdev_printk(KERN_INFO, scmd->device, 416362306a36Sopenharmony_ci "Attempting Device(lun) Reset! scmd(%p)\n", scmd); 416462306a36Sopenharmony_ci scsi_print_command(scmd); 416562306a36Sopenharmony_ci 416662306a36Sopenharmony_ci sdev_priv_data = scmd->device->hostdata; 416762306a36Sopenharmony_ci if (!sdev_priv_data || !sdev_priv_data->tgt_priv_data) { 416862306a36Sopenharmony_ci sdev_printk(KERN_INFO, scmd->device, 416962306a36Sopenharmony_ci "SCSI device is not available\n"); 417062306a36Sopenharmony_ci retval = SUCCESS; 417162306a36Sopenharmony_ci goto out; 417262306a36Sopenharmony_ci } 417362306a36Sopenharmony_ci 417462306a36Sopenharmony_ci stgt_priv_data = sdev_priv_data->tgt_priv_data; 417562306a36Sopenharmony_ci dev_handle = stgt_priv_data->dev_handle; 417662306a36Sopenharmony_ci if (stgt_priv_data->dev_removed) { 417762306a36Sopenharmony_ci struct scmd_priv *cmd_priv = scsi_cmd_priv(scmd); 417862306a36Sopenharmony_ci sdev_printk(KERN_INFO, scmd->device, 417962306a36Sopenharmony_ci "%s: device(handle = 0x%04x) is removed, device(LUN) reset is not issued\n", 418062306a36Sopenharmony_ci mrioc->name, dev_handle); 418162306a36Sopenharmony_ci if (!cmd_priv->in_lld_scope || cmd_priv->host_tag == MPI3MR_HOSTTAG_INVALID) 418262306a36Sopenharmony_ci retval = SUCCESS; 418362306a36Sopenharmony_ci else 418462306a36Sopenharmony_ci retval = FAILED; 418562306a36Sopenharmony_ci goto out; 418662306a36Sopenharmony_ci } 418762306a36Sopenharmony_ci sdev_printk(KERN_INFO, scmd->device, 418862306a36Sopenharmony_ci "Device(lun) Reset is issued to handle(0x%04x)\n", dev_handle); 418962306a36Sopenharmony_ci 419062306a36Sopenharmony_ci ret = mpi3mr_issue_tm(mrioc, 419162306a36Sopenharmony_ci MPI3_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, dev_handle, 419262306a36Sopenharmony_ci sdev_priv_data->lun_id, MPI3MR_HOSTTAG_BLK_TMS, 419362306a36Sopenharmony_ci MPI3MR_RESETTM_TIMEOUT, &mrioc->host_tm_cmds, &resp_code, scmd); 419462306a36Sopenharmony_ci 419562306a36Sopenharmony_ci if (ret) 419662306a36Sopenharmony_ci goto out; 419762306a36Sopenharmony_ci 419862306a36Sopenharmony_ci if (sdev_priv_data->pend_count) { 419962306a36Sopenharmony_ci sdev_printk(KERN_INFO, scmd->device, 420062306a36Sopenharmony_ci "%s: device has %d pending commands, device(LUN) reset is failed\n", 420162306a36Sopenharmony_ci mrioc->name, sdev_priv_data->pend_count); 420262306a36Sopenharmony_ci goto out; 420362306a36Sopenharmony_ci } 420462306a36Sopenharmony_ci retval = SUCCESS; 420562306a36Sopenharmony_ciout: 420662306a36Sopenharmony_ci sdev_printk(KERN_INFO, scmd->device, 420762306a36Sopenharmony_ci "%s: device(LUN) reset is %s for scmd(%p)\n", mrioc->name, 420862306a36Sopenharmony_ci ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); 420962306a36Sopenharmony_ci 421062306a36Sopenharmony_ci return retval; 421162306a36Sopenharmony_ci} 421262306a36Sopenharmony_ci 421362306a36Sopenharmony_ci/** 421462306a36Sopenharmony_ci * mpi3mr_scan_start - Scan start callback handler 421562306a36Sopenharmony_ci * @shost: SCSI host reference 421662306a36Sopenharmony_ci * 421762306a36Sopenharmony_ci * Issue port enable request asynchronously. 421862306a36Sopenharmony_ci * 421962306a36Sopenharmony_ci * Return: Nothing 422062306a36Sopenharmony_ci */ 422162306a36Sopenharmony_cistatic void mpi3mr_scan_start(struct Scsi_Host *shost) 422262306a36Sopenharmony_ci{ 422362306a36Sopenharmony_ci struct mpi3mr_ioc *mrioc = shost_priv(shost); 422462306a36Sopenharmony_ci 422562306a36Sopenharmony_ci mrioc->scan_started = 1; 422662306a36Sopenharmony_ci ioc_info(mrioc, "%s :Issuing Port Enable\n", __func__); 422762306a36Sopenharmony_ci if (mpi3mr_issue_port_enable(mrioc, 1)) { 422862306a36Sopenharmony_ci ioc_err(mrioc, "%s :Issuing port enable failed\n", __func__); 422962306a36Sopenharmony_ci mrioc->scan_started = 0; 423062306a36Sopenharmony_ci mrioc->scan_failed = MPI3_IOCSTATUS_INTERNAL_ERROR; 423162306a36Sopenharmony_ci } 423262306a36Sopenharmony_ci} 423362306a36Sopenharmony_ci 423462306a36Sopenharmony_ci/** 423562306a36Sopenharmony_ci * mpi3mr_scan_finished - Scan finished callback handler 423662306a36Sopenharmony_ci * @shost: SCSI host reference 423762306a36Sopenharmony_ci * @time: Jiffies from the scan start 423862306a36Sopenharmony_ci * 423962306a36Sopenharmony_ci * Checks whether the port enable is completed or timedout or 424062306a36Sopenharmony_ci * failed and set the scan status accordingly after taking any 424162306a36Sopenharmony_ci * recovery if required. 424262306a36Sopenharmony_ci * 424362306a36Sopenharmony_ci * Return: 1 on scan finished or timed out, 0 for in progress 424462306a36Sopenharmony_ci */ 424562306a36Sopenharmony_cistatic int mpi3mr_scan_finished(struct Scsi_Host *shost, 424662306a36Sopenharmony_ci unsigned long time) 424762306a36Sopenharmony_ci{ 424862306a36Sopenharmony_ci struct mpi3mr_ioc *mrioc = shost_priv(shost); 424962306a36Sopenharmony_ci u32 pe_timeout = MPI3MR_PORTENABLE_TIMEOUT; 425062306a36Sopenharmony_ci u32 ioc_status = readl(&mrioc->sysif_regs->ioc_status); 425162306a36Sopenharmony_ci 425262306a36Sopenharmony_ci if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) || 425362306a36Sopenharmony_ci (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) { 425462306a36Sopenharmony_ci ioc_err(mrioc, "port enable failed due to fault or reset\n"); 425562306a36Sopenharmony_ci mpi3mr_print_fault_info(mrioc); 425662306a36Sopenharmony_ci mrioc->scan_failed = MPI3_IOCSTATUS_INTERNAL_ERROR; 425762306a36Sopenharmony_ci mrioc->scan_started = 0; 425862306a36Sopenharmony_ci mrioc->init_cmds.is_waiting = 0; 425962306a36Sopenharmony_ci mrioc->init_cmds.callback = NULL; 426062306a36Sopenharmony_ci mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 426162306a36Sopenharmony_ci } 426262306a36Sopenharmony_ci 426362306a36Sopenharmony_ci if (time >= (pe_timeout * HZ)) { 426462306a36Sopenharmony_ci ioc_err(mrioc, "port enable failed due to time out\n"); 426562306a36Sopenharmony_ci mpi3mr_check_rh_fault_ioc(mrioc, 426662306a36Sopenharmony_ci MPI3MR_RESET_FROM_PE_TIMEOUT); 426762306a36Sopenharmony_ci mrioc->scan_failed = MPI3_IOCSTATUS_INTERNAL_ERROR; 426862306a36Sopenharmony_ci mrioc->scan_started = 0; 426962306a36Sopenharmony_ci mrioc->init_cmds.is_waiting = 0; 427062306a36Sopenharmony_ci mrioc->init_cmds.callback = NULL; 427162306a36Sopenharmony_ci mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; 427262306a36Sopenharmony_ci } 427362306a36Sopenharmony_ci 427462306a36Sopenharmony_ci if (mrioc->scan_started) 427562306a36Sopenharmony_ci return 0; 427662306a36Sopenharmony_ci 427762306a36Sopenharmony_ci if (mrioc->scan_failed) { 427862306a36Sopenharmony_ci ioc_err(mrioc, 427962306a36Sopenharmony_ci "port enable failed with status=0x%04x\n", 428062306a36Sopenharmony_ci mrioc->scan_failed); 428162306a36Sopenharmony_ci } else 428262306a36Sopenharmony_ci ioc_info(mrioc, "port enable is successfully completed\n"); 428362306a36Sopenharmony_ci 428462306a36Sopenharmony_ci mpi3mr_start_watchdog(mrioc); 428562306a36Sopenharmony_ci mrioc->is_driver_loading = 0; 428662306a36Sopenharmony_ci mrioc->stop_bsgs = 0; 428762306a36Sopenharmony_ci return 1; 428862306a36Sopenharmony_ci} 428962306a36Sopenharmony_ci 429062306a36Sopenharmony_ci/** 429162306a36Sopenharmony_ci * mpi3mr_slave_destroy - Slave destroy callback handler 429262306a36Sopenharmony_ci * @sdev: SCSI device reference 429362306a36Sopenharmony_ci * 429462306a36Sopenharmony_ci * Cleanup and free per device(lun) private data. 429562306a36Sopenharmony_ci * 429662306a36Sopenharmony_ci * Return: Nothing. 429762306a36Sopenharmony_ci */ 429862306a36Sopenharmony_cistatic void mpi3mr_slave_destroy(struct scsi_device *sdev) 429962306a36Sopenharmony_ci{ 430062306a36Sopenharmony_ci struct Scsi_Host *shost; 430162306a36Sopenharmony_ci struct mpi3mr_ioc *mrioc; 430262306a36Sopenharmony_ci struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data; 430362306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgt_dev = NULL; 430462306a36Sopenharmony_ci unsigned long flags; 430562306a36Sopenharmony_ci struct scsi_target *starget; 430662306a36Sopenharmony_ci struct sas_rphy *rphy = NULL; 430762306a36Sopenharmony_ci 430862306a36Sopenharmony_ci if (!sdev->hostdata) 430962306a36Sopenharmony_ci return; 431062306a36Sopenharmony_ci 431162306a36Sopenharmony_ci starget = scsi_target(sdev); 431262306a36Sopenharmony_ci shost = dev_to_shost(&starget->dev); 431362306a36Sopenharmony_ci mrioc = shost_priv(shost); 431462306a36Sopenharmony_ci scsi_tgt_priv_data = starget->hostdata; 431562306a36Sopenharmony_ci 431662306a36Sopenharmony_ci scsi_tgt_priv_data->num_luns--; 431762306a36Sopenharmony_ci 431862306a36Sopenharmony_ci spin_lock_irqsave(&mrioc->tgtdev_lock, flags); 431962306a36Sopenharmony_ci if (starget->channel == mrioc->scsi_device_channel) 432062306a36Sopenharmony_ci tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id); 432162306a36Sopenharmony_ci else if (mrioc->sas_transport_enabled && !starget->channel) { 432262306a36Sopenharmony_ci rphy = dev_to_rphy(starget->dev.parent); 432362306a36Sopenharmony_ci tgt_dev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc, 432462306a36Sopenharmony_ci rphy->identify.sas_address, rphy); 432562306a36Sopenharmony_ci } 432662306a36Sopenharmony_ci 432762306a36Sopenharmony_ci if (tgt_dev && (!scsi_tgt_priv_data->num_luns)) 432862306a36Sopenharmony_ci tgt_dev->starget = NULL; 432962306a36Sopenharmony_ci if (tgt_dev) 433062306a36Sopenharmony_ci mpi3mr_tgtdev_put(tgt_dev); 433162306a36Sopenharmony_ci spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags); 433262306a36Sopenharmony_ci 433362306a36Sopenharmony_ci kfree(sdev->hostdata); 433462306a36Sopenharmony_ci sdev->hostdata = NULL; 433562306a36Sopenharmony_ci} 433662306a36Sopenharmony_ci 433762306a36Sopenharmony_ci/** 433862306a36Sopenharmony_ci * mpi3mr_target_destroy - Target destroy callback handler 433962306a36Sopenharmony_ci * @starget: SCSI target reference 434062306a36Sopenharmony_ci * 434162306a36Sopenharmony_ci * Cleanup and free per target private data. 434262306a36Sopenharmony_ci * 434362306a36Sopenharmony_ci * Return: Nothing. 434462306a36Sopenharmony_ci */ 434562306a36Sopenharmony_cistatic void mpi3mr_target_destroy(struct scsi_target *starget) 434662306a36Sopenharmony_ci{ 434762306a36Sopenharmony_ci struct Scsi_Host *shost; 434862306a36Sopenharmony_ci struct mpi3mr_ioc *mrioc; 434962306a36Sopenharmony_ci struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data; 435062306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgt_dev; 435162306a36Sopenharmony_ci unsigned long flags; 435262306a36Sopenharmony_ci 435362306a36Sopenharmony_ci if (!starget->hostdata) 435462306a36Sopenharmony_ci return; 435562306a36Sopenharmony_ci 435662306a36Sopenharmony_ci shost = dev_to_shost(&starget->dev); 435762306a36Sopenharmony_ci mrioc = shost_priv(shost); 435862306a36Sopenharmony_ci scsi_tgt_priv_data = starget->hostdata; 435962306a36Sopenharmony_ci 436062306a36Sopenharmony_ci spin_lock_irqsave(&mrioc->tgtdev_lock, flags); 436162306a36Sopenharmony_ci tgt_dev = __mpi3mr_get_tgtdev_from_tgtpriv(mrioc, scsi_tgt_priv_data); 436262306a36Sopenharmony_ci if (tgt_dev && (tgt_dev->starget == starget) && 436362306a36Sopenharmony_ci (tgt_dev->perst_id == starget->id)) 436462306a36Sopenharmony_ci tgt_dev->starget = NULL; 436562306a36Sopenharmony_ci if (tgt_dev) { 436662306a36Sopenharmony_ci scsi_tgt_priv_data->tgt_dev = NULL; 436762306a36Sopenharmony_ci scsi_tgt_priv_data->perst_id = 0; 436862306a36Sopenharmony_ci mpi3mr_tgtdev_put(tgt_dev); 436962306a36Sopenharmony_ci mpi3mr_tgtdev_put(tgt_dev); 437062306a36Sopenharmony_ci } 437162306a36Sopenharmony_ci spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags); 437262306a36Sopenharmony_ci 437362306a36Sopenharmony_ci kfree(starget->hostdata); 437462306a36Sopenharmony_ci starget->hostdata = NULL; 437562306a36Sopenharmony_ci} 437662306a36Sopenharmony_ci 437762306a36Sopenharmony_ci/** 437862306a36Sopenharmony_ci * mpi3mr_slave_configure - Slave configure callback handler 437962306a36Sopenharmony_ci * @sdev: SCSI device reference 438062306a36Sopenharmony_ci * 438162306a36Sopenharmony_ci * Configure queue depth, max hardware sectors and virt boundary 438262306a36Sopenharmony_ci * as required 438362306a36Sopenharmony_ci * 438462306a36Sopenharmony_ci * Return: 0 always. 438562306a36Sopenharmony_ci */ 438662306a36Sopenharmony_cistatic int mpi3mr_slave_configure(struct scsi_device *sdev) 438762306a36Sopenharmony_ci{ 438862306a36Sopenharmony_ci struct scsi_target *starget; 438962306a36Sopenharmony_ci struct Scsi_Host *shost; 439062306a36Sopenharmony_ci struct mpi3mr_ioc *mrioc; 439162306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgt_dev = NULL; 439262306a36Sopenharmony_ci unsigned long flags; 439362306a36Sopenharmony_ci int retval = 0; 439462306a36Sopenharmony_ci struct sas_rphy *rphy = NULL; 439562306a36Sopenharmony_ci 439662306a36Sopenharmony_ci starget = scsi_target(sdev); 439762306a36Sopenharmony_ci shost = dev_to_shost(&starget->dev); 439862306a36Sopenharmony_ci mrioc = shost_priv(shost); 439962306a36Sopenharmony_ci 440062306a36Sopenharmony_ci spin_lock_irqsave(&mrioc->tgtdev_lock, flags); 440162306a36Sopenharmony_ci if (starget->channel == mrioc->scsi_device_channel) 440262306a36Sopenharmony_ci tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id); 440362306a36Sopenharmony_ci else if (mrioc->sas_transport_enabled && !starget->channel) { 440462306a36Sopenharmony_ci rphy = dev_to_rphy(starget->dev.parent); 440562306a36Sopenharmony_ci tgt_dev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc, 440662306a36Sopenharmony_ci rphy->identify.sas_address, rphy); 440762306a36Sopenharmony_ci } 440862306a36Sopenharmony_ci spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags); 440962306a36Sopenharmony_ci if (!tgt_dev) 441062306a36Sopenharmony_ci return -ENXIO; 441162306a36Sopenharmony_ci 441262306a36Sopenharmony_ci mpi3mr_change_queue_depth(sdev, tgt_dev->q_depth); 441362306a36Sopenharmony_ci 441462306a36Sopenharmony_ci sdev->eh_timeout = MPI3MR_EH_SCMD_TIMEOUT; 441562306a36Sopenharmony_ci blk_queue_rq_timeout(sdev->request_queue, MPI3MR_SCMD_TIMEOUT); 441662306a36Sopenharmony_ci 441762306a36Sopenharmony_ci switch (tgt_dev->dev_type) { 441862306a36Sopenharmony_ci case MPI3_DEVICE_DEVFORM_PCIE: 441962306a36Sopenharmony_ci /*The block layer hw sector size = 512*/ 442062306a36Sopenharmony_ci if ((tgt_dev->dev_spec.pcie_inf.dev_info & 442162306a36Sopenharmony_ci MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) == 442262306a36Sopenharmony_ci MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) { 442362306a36Sopenharmony_ci blk_queue_max_hw_sectors(sdev->request_queue, 442462306a36Sopenharmony_ci tgt_dev->dev_spec.pcie_inf.mdts / 512); 442562306a36Sopenharmony_ci if (tgt_dev->dev_spec.pcie_inf.pgsz == 0) 442662306a36Sopenharmony_ci blk_queue_virt_boundary(sdev->request_queue, 442762306a36Sopenharmony_ci ((1 << MPI3MR_DEFAULT_PGSZEXP) - 1)); 442862306a36Sopenharmony_ci else 442962306a36Sopenharmony_ci blk_queue_virt_boundary(sdev->request_queue, 443062306a36Sopenharmony_ci ((1 << tgt_dev->dev_spec.pcie_inf.pgsz) - 1)); 443162306a36Sopenharmony_ci } 443262306a36Sopenharmony_ci break; 443362306a36Sopenharmony_ci default: 443462306a36Sopenharmony_ci break; 443562306a36Sopenharmony_ci } 443662306a36Sopenharmony_ci 443762306a36Sopenharmony_ci mpi3mr_tgtdev_put(tgt_dev); 443862306a36Sopenharmony_ci 443962306a36Sopenharmony_ci return retval; 444062306a36Sopenharmony_ci} 444162306a36Sopenharmony_ci 444262306a36Sopenharmony_ci/** 444362306a36Sopenharmony_ci * mpi3mr_slave_alloc -Slave alloc callback handler 444462306a36Sopenharmony_ci * @sdev: SCSI device reference 444562306a36Sopenharmony_ci * 444662306a36Sopenharmony_ci * Allocate per device(lun) private data and initialize it. 444762306a36Sopenharmony_ci * 444862306a36Sopenharmony_ci * Return: 0 on success -ENOMEM on memory allocation failure. 444962306a36Sopenharmony_ci */ 445062306a36Sopenharmony_cistatic int mpi3mr_slave_alloc(struct scsi_device *sdev) 445162306a36Sopenharmony_ci{ 445262306a36Sopenharmony_ci struct Scsi_Host *shost; 445362306a36Sopenharmony_ci struct mpi3mr_ioc *mrioc; 445462306a36Sopenharmony_ci struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data; 445562306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgt_dev = NULL; 445662306a36Sopenharmony_ci struct mpi3mr_sdev_priv_data *scsi_dev_priv_data; 445762306a36Sopenharmony_ci unsigned long flags; 445862306a36Sopenharmony_ci struct scsi_target *starget; 445962306a36Sopenharmony_ci int retval = 0; 446062306a36Sopenharmony_ci struct sas_rphy *rphy = NULL; 446162306a36Sopenharmony_ci 446262306a36Sopenharmony_ci starget = scsi_target(sdev); 446362306a36Sopenharmony_ci shost = dev_to_shost(&starget->dev); 446462306a36Sopenharmony_ci mrioc = shost_priv(shost); 446562306a36Sopenharmony_ci scsi_tgt_priv_data = starget->hostdata; 446662306a36Sopenharmony_ci 446762306a36Sopenharmony_ci spin_lock_irqsave(&mrioc->tgtdev_lock, flags); 446862306a36Sopenharmony_ci 446962306a36Sopenharmony_ci if (starget->channel == mrioc->scsi_device_channel) 447062306a36Sopenharmony_ci tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id); 447162306a36Sopenharmony_ci else if (mrioc->sas_transport_enabled && !starget->channel) { 447262306a36Sopenharmony_ci rphy = dev_to_rphy(starget->dev.parent); 447362306a36Sopenharmony_ci tgt_dev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc, 447462306a36Sopenharmony_ci rphy->identify.sas_address, rphy); 447562306a36Sopenharmony_ci } 447662306a36Sopenharmony_ci 447762306a36Sopenharmony_ci if (tgt_dev) { 447862306a36Sopenharmony_ci if (tgt_dev->starget == NULL) 447962306a36Sopenharmony_ci tgt_dev->starget = starget; 448062306a36Sopenharmony_ci mpi3mr_tgtdev_put(tgt_dev); 448162306a36Sopenharmony_ci retval = 0; 448262306a36Sopenharmony_ci } else { 448362306a36Sopenharmony_ci spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags); 448462306a36Sopenharmony_ci return -ENXIO; 448562306a36Sopenharmony_ci } 448662306a36Sopenharmony_ci 448762306a36Sopenharmony_ci spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags); 448862306a36Sopenharmony_ci 448962306a36Sopenharmony_ci scsi_dev_priv_data = kzalloc(sizeof(*scsi_dev_priv_data), GFP_KERNEL); 449062306a36Sopenharmony_ci if (!scsi_dev_priv_data) 449162306a36Sopenharmony_ci return -ENOMEM; 449262306a36Sopenharmony_ci 449362306a36Sopenharmony_ci scsi_dev_priv_data->lun_id = sdev->lun; 449462306a36Sopenharmony_ci scsi_dev_priv_data->tgt_priv_data = scsi_tgt_priv_data; 449562306a36Sopenharmony_ci sdev->hostdata = scsi_dev_priv_data; 449662306a36Sopenharmony_ci 449762306a36Sopenharmony_ci scsi_tgt_priv_data->num_luns++; 449862306a36Sopenharmony_ci 449962306a36Sopenharmony_ci return retval; 450062306a36Sopenharmony_ci} 450162306a36Sopenharmony_ci 450262306a36Sopenharmony_ci/** 450362306a36Sopenharmony_ci * mpi3mr_target_alloc - Target alloc callback handler 450462306a36Sopenharmony_ci * @starget: SCSI target reference 450562306a36Sopenharmony_ci * 450662306a36Sopenharmony_ci * Allocate per target private data and initialize it. 450762306a36Sopenharmony_ci * 450862306a36Sopenharmony_ci * Return: 0 on success -ENOMEM on memory allocation failure. 450962306a36Sopenharmony_ci */ 451062306a36Sopenharmony_cistatic int mpi3mr_target_alloc(struct scsi_target *starget) 451162306a36Sopenharmony_ci{ 451262306a36Sopenharmony_ci struct Scsi_Host *shost = dev_to_shost(&starget->dev); 451362306a36Sopenharmony_ci struct mpi3mr_ioc *mrioc = shost_priv(shost); 451462306a36Sopenharmony_ci struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data; 451562306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgt_dev; 451662306a36Sopenharmony_ci unsigned long flags; 451762306a36Sopenharmony_ci int retval = 0; 451862306a36Sopenharmony_ci struct sas_rphy *rphy = NULL; 451962306a36Sopenharmony_ci 452062306a36Sopenharmony_ci scsi_tgt_priv_data = kzalloc(sizeof(*scsi_tgt_priv_data), GFP_KERNEL); 452162306a36Sopenharmony_ci if (!scsi_tgt_priv_data) 452262306a36Sopenharmony_ci return -ENOMEM; 452362306a36Sopenharmony_ci 452462306a36Sopenharmony_ci starget->hostdata = scsi_tgt_priv_data; 452562306a36Sopenharmony_ci 452662306a36Sopenharmony_ci spin_lock_irqsave(&mrioc->tgtdev_lock, flags); 452762306a36Sopenharmony_ci if (starget->channel == mrioc->scsi_device_channel) { 452862306a36Sopenharmony_ci tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id); 452962306a36Sopenharmony_ci if (tgt_dev && !tgt_dev->is_hidden) { 453062306a36Sopenharmony_ci scsi_tgt_priv_data->starget = starget; 453162306a36Sopenharmony_ci scsi_tgt_priv_data->dev_handle = tgt_dev->dev_handle; 453262306a36Sopenharmony_ci scsi_tgt_priv_data->perst_id = tgt_dev->perst_id; 453362306a36Sopenharmony_ci scsi_tgt_priv_data->dev_type = tgt_dev->dev_type; 453462306a36Sopenharmony_ci scsi_tgt_priv_data->tgt_dev = tgt_dev; 453562306a36Sopenharmony_ci tgt_dev->starget = starget; 453662306a36Sopenharmony_ci atomic_set(&scsi_tgt_priv_data->block_io, 0); 453762306a36Sopenharmony_ci retval = 0; 453862306a36Sopenharmony_ci if ((tgt_dev->dev_type == MPI3_DEVICE_DEVFORM_PCIE) && 453962306a36Sopenharmony_ci ((tgt_dev->dev_spec.pcie_inf.dev_info & 454062306a36Sopenharmony_ci MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) == 454162306a36Sopenharmony_ci MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) && 454262306a36Sopenharmony_ci ((tgt_dev->dev_spec.pcie_inf.dev_info & 454362306a36Sopenharmony_ci MPI3_DEVICE0_PCIE_DEVICE_INFO_PITYPE_MASK) != 454462306a36Sopenharmony_ci MPI3_DEVICE0_PCIE_DEVICE_INFO_PITYPE_0)) 454562306a36Sopenharmony_ci scsi_tgt_priv_data->dev_nvme_dif = 1; 454662306a36Sopenharmony_ci scsi_tgt_priv_data->io_throttle_enabled = tgt_dev->io_throttle_enabled; 454762306a36Sopenharmony_ci scsi_tgt_priv_data->wslen = tgt_dev->wslen; 454862306a36Sopenharmony_ci if (tgt_dev->dev_type == MPI3_DEVICE_DEVFORM_VD) 454962306a36Sopenharmony_ci scsi_tgt_priv_data->throttle_group = tgt_dev->dev_spec.vd_inf.tg; 455062306a36Sopenharmony_ci } else 455162306a36Sopenharmony_ci retval = -ENXIO; 455262306a36Sopenharmony_ci } else if (mrioc->sas_transport_enabled && !starget->channel) { 455362306a36Sopenharmony_ci rphy = dev_to_rphy(starget->dev.parent); 455462306a36Sopenharmony_ci tgt_dev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc, 455562306a36Sopenharmony_ci rphy->identify.sas_address, rphy); 455662306a36Sopenharmony_ci if (tgt_dev && !tgt_dev->is_hidden && !tgt_dev->non_stl && 455762306a36Sopenharmony_ci (tgt_dev->dev_type == MPI3_DEVICE_DEVFORM_SAS_SATA)) { 455862306a36Sopenharmony_ci scsi_tgt_priv_data->starget = starget; 455962306a36Sopenharmony_ci scsi_tgt_priv_data->dev_handle = tgt_dev->dev_handle; 456062306a36Sopenharmony_ci scsi_tgt_priv_data->perst_id = tgt_dev->perst_id; 456162306a36Sopenharmony_ci scsi_tgt_priv_data->dev_type = tgt_dev->dev_type; 456262306a36Sopenharmony_ci scsi_tgt_priv_data->tgt_dev = tgt_dev; 456362306a36Sopenharmony_ci scsi_tgt_priv_data->io_throttle_enabled = tgt_dev->io_throttle_enabled; 456462306a36Sopenharmony_ci scsi_tgt_priv_data->wslen = tgt_dev->wslen; 456562306a36Sopenharmony_ci tgt_dev->starget = starget; 456662306a36Sopenharmony_ci atomic_set(&scsi_tgt_priv_data->block_io, 0); 456762306a36Sopenharmony_ci retval = 0; 456862306a36Sopenharmony_ci } else 456962306a36Sopenharmony_ci retval = -ENXIO; 457062306a36Sopenharmony_ci } 457162306a36Sopenharmony_ci spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags); 457262306a36Sopenharmony_ci 457362306a36Sopenharmony_ci return retval; 457462306a36Sopenharmony_ci} 457562306a36Sopenharmony_ci 457662306a36Sopenharmony_ci/** 457762306a36Sopenharmony_ci * mpi3mr_check_return_unmap - Whether an unmap is allowed 457862306a36Sopenharmony_ci * @mrioc: Adapter instance reference 457962306a36Sopenharmony_ci * @scmd: SCSI Command reference 458062306a36Sopenharmony_ci * 458162306a36Sopenharmony_ci * The controller hardware cannot handle certain unmap commands 458262306a36Sopenharmony_ci * for NVMe drives, this routine checks those and return true 458362306a36Sopenharmony_ci * and completes the SCSI command with proper status and sense 458462306a36Sopenharmony_ci * data. 458562306a36Sopenharmony_ci * 458662306a36Sopenharmony_ci * Return: TRUE for not allowed unmap, FALSE otherwise. 458762306a36Sopenharmony_ci */ 458862306a36Sopenharmony_cistatic bool mpi3mr_check_return_unmap(struct mpi3mr_ioc *mrioc, 458962306a36Sopenharmony_ci struct scsi_cmnd *scmd) 459062306a36Sopenharmony_ci{ 459162306a36Sopenharmony_ci unsigned char *buf; 459262306a36Sopenharmony_ci u16 param_len, desc_len, trunc_param_len; 459362306a36Sopenharmony_ci 459462306a36Sopenharmony_ci trunc_param_len = param_len = get_unaligned_be16(scmd->cmnd + 7); 459562306a36Sopenharmony_ci 459662306a36Sopenharmony_ci if (mrioc->pdev->revision) { 459762306a36Sopenharmony_ci if ((param_len > 24) && ((param_len - 8) & 0xF)) { 459862306a36Sopenharmony_ci trunc_param_len -= (param_len - 8) & 0xF; 459962306a36Sopenharmony_ci dprint_scsi_command(mrioc, scmd, MPI3_DEBUG_SCSI_ERROR); 460062306a36Sopenharmony_ci dprint_scsi_err(mrioc, 460162306a36Sopenharmony_ci "truncating param_len from (%d) to (%d)\n", 460262306a36Sopenharmony_ci param_len, trunc_param_len); 460362306a36Sopenharmony_ci put_unaligned_be16(trunc_param_len, scmd->cmnd + 7); 460462306a36Sopenharmony_ci dprint_scsi_command(mrioc, scmd, MPI3_DEBUG_SCSI_ERROR); 460562306a36Sopenharmony_ci } 460662306a36Sopenharmony_ci return false; 460762306a36Sopenharmony_ci } 460862306a36Sopenharmony_ci 460962306a36Sopenharmony_ci if (!param_len) { 461062306a36Sopenharmony_ci ioc_warn(mrioc, 461162306a36Sopenharmony_ci "%s: cdb received with zero parameter length\n", 461262306a36Sopenharmony_ci __func__); 461362306a36Sopenharmony_ci scsi_print_command(scmd); 461462306a36Sopenharmony_ci scmd->result = DID_OK << 16; 461562306a36Sopenharmony_ci scsi_done(scmd); 461662306a36Sopenharmony_ci return true; 461762306a36Sopenharmony_ci } 461862306a36Sopenharmony_ci 461962306a36Sopenharmony_ci if (param_len < 24) { 462062306a36Sopenharmony_ci ioc_warn(mrioc, 462162306a36Sopenharmony_ci "%s: cdb received with invalid param_len: %d\n", 462262306a36Sopenharmony_ci __func__, param_len); 462362306a36Sopenharmony_ci scsi_print_command(scmd); 462462306a36Sopenharmony_ci scmd->result = SAM_STAT_CHECK_CONDITION; 462562306a36Sopenharmony_ci scsi_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST, 462662306a36Sopenharmony_ci 0x1A, 0); 462762306a36Sopenharmony_ci scsi_done(scmd); 462862306a36Sopenharmony_ci return true; 462962306a36Sopenharmony_ci } 463062306a36Sopenharmony_ci if (param_len != scsi_bufflen(scmd)) { 463162306a36Sopenharmony_ci ioc_warn(mrioc, 463262306a36Sopenharmony_ci "%s: cdb received with param_len: %d bufflen: %d\n", 463362306a36Sopenharmony_ci __func__, param_len, scsi_bufflen(scmd)); 463462306a36Sopenharmony_ci scsi_print_command(scmd); 463562306a36Sopenharmony_ci scmd->result = SAM_STAT_CHECK_CONDITION; 463662306a36Sopenharmony_ci scsi_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST, 463762306a36Sopenharmony_ci 0x1A, 0); 463862306a36Sopenharmony_ci scsi_done(scmd); 463962306a36Sopenharmony_ci return true; 464062306a36Sopenharmony_ci } 464162306a36Sopenharmony_ci buf = kzalloc(scsi_bufflen(scmd), GFP_ATOMIC); 464262306a36Sopenharmony_ci if (!buf) { 464362306a36Sopenharmony_ci scsi_print_command(scmd); 464462306a36Sopenharmony_ci scmd->result = SAM_STAT_CHECK_CONDITION; 464562306a36Sopenharmony_ci scsi_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST, 464662306a36Sopenharmony_ci 0x55, 0x03); 464762306a36Sopenharmony_ci scsi_done(scmd); 464862306a36Sopenharmony_ci return true; 464962306a36Sopenharmony_ci } 465062306a36Sopenharmony_ci scsi_sg_copy_to_buffer(scmd, buf, scsi_bufflen(scmd)); 465162306a36Sopenharmony_ci desc_len = get_unaligned_be16(&buf[2]); 465262306a36Sopenharmony_ci 465362306a36Sopenharmony_ci if (desc_len < 16) { 465462306a36Sopenharmony_ci ioc_warn(mrioc, 465562306a36Sopenharmony_ci "%s: Invalid descriptor length in param list: %d\n", 465662306a36Sopenharmony_ci __func__, desc_len); 465762306a36Sopenharmony_ci scsi_print_command(scmd); 465862306a36Sopenharmony_ci scmd->result = SAM_STAT_CHECK_CONDITION; 465962306a36Sopenharmony_ci scsi_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST, 466062306a36Sopenharmony_ci 0x26, 0); 466162306a36Sopenharmony_ci scsi_done(scmd); 466262306a36Sopenharmony_ci kfree(buf); 466362306a36Sopenharmony_ci return true; 466462306a36Sopenharmony_ci } 466562306a36Sopenharmony_ci 466662306a36Sopenharmony_ci if (param_len > (desc_len + 8)) { 466762306a36Sopenharmony_ci trunc_param_len = desc_len + 8; 466862306a36Sopenharmony_ci scsi_print_command(scmd); 466962306a36Sopenharmony_ci dprint_scsi_err(mrioc, 467062306a36Sopenharmony_ci "truncating param_len(%d) to desc_len+8(%d)\n", 467162306a36Sopenharmony_ci param_len, trunc_param_len); 467262306a36Sopenharmony_ci put_unaligned_be16(trunc_param_len, scmd->cmnd + 7); 467362306a36Sopenharmony_ci scsi_print_command(scmd); 467462306a36Sopenharmony_ci } 467562306a36Sopenharmony_ci 467662306a36Sopenharmony_ci kfree(buf); 467762306a36Sopenharmony_ci return false; 467862306a36Sopenharmony_ci} 467962306a36Sopenharmony_ci 468062306a36Sopenharmony_ci/** 468162306a36Sopenharmony_ci * mpi3mr_allow_scmd_to_fw - Command is allowed during shutdown 468262306a36Sopenharmony_ci * @scmd: SCSI Command reference 468362306a36Sopenharmony_ci * 468462306a36Sopenharmony_ci * Checks whether a cdb is allowed during shutdown or not. 468562306a36Sopenharmony_ci * 468662306a36Sopenharmony_ci * Return: TRUE for allowed commands, FALSE otherwise. 468762306a36Sopenharmony_ci */ 468862306a36Sopenharmony_ci 468962306a36Sopenharmony_ciinline bool mpi3mr_allow_scmd_to_fw(struct scsi_cmnd *scmd) 469062306a36Sopenharmony_ci{ 469162306a36Sopenharmony_ci switch (scmd->cmnd[0]) { 469262306a36Sopenharmony_ci case SYNCHRONIZE_CACHE: 469362306a36Sopenharmony_ci case START_STOP: 469462306a36Sopenharmony_ci return true; 469562306a36Sopenharmony_ci default: 469662306a36Sopenharmony_ci return false; 469762306a36Sopenharmony_ci } 469862306a36Sopenharmony_ci} 469962306a36Sopenharmony_ci 470062306a36Sopenharmony_ci/** 470162306a36Sopenharmony_ci * mpi3mr_qcmd - I/O request despatcher 470262306a36Sopenharmony_ci * @shost: SCSI Host reference 470362306a36Sopenharmony_ci * @scmd: SCSI Command reference 470462306a36Sopenharmony_ci * 470562306a36Sopenharmony_ci * Issues the SCSI Command as an MPI3 request. 470662306a36Sopenharmony_ci * 470762306a36Sopenharmony_ci * Return: 0 on successful queueing of the request or if the 470862306a36Sopenharmony_ci * request is completed with failure. 470962306a36Sopenharmony_ci * SCSI_MLQUEUE_DEVICE_BUSY when the device is busy. 471062306a36Sopenharmony_ci * SCSI_MLQUEUE_HOST_BUSY when the host queue is full. 471162306a36Sopenharmony_ci */ 471262306a36Sopenharmony_cistatic int mpi3mr_qcmd(struct Scsi_Host *shost, 471362306a36Sopenharmony_ci struct scsi_cmnd *scmd) 471462306a36Sopenharmony_ci{ 471562306a36Sopenharmony_ci struct mpi3mr_ioc *mrioc = shost_priv(shost); 471662306a36Sopenharmony_ci struct mpi3mr_stgt_priv_data *stgt_priv_data; 471762306a36Sopenharmony_ci struct mpi3mr_sdev_priv_data *sdev_priv_data; 471862306a36Sopenharmony_ci struct scmd_priv *scmd_priv_data = NULL; 471962306a36Sopenharmony_ci struct mpi3_scsi_io_request *scsiio_req = NULL; 472062306a36Sopenharmony_ci struct op_req_qinfo *op_req_q = NULL; 472162306a36Sopenharmony_ci int retval = 0; 472262306a36Sopenharmony_ci u16 dev_handle; 472362306a36Sopenharmony_ci u16 host_tag; 472462306a36Sopenharmony_ci u32 scsiio_flags = 0, data_len_blks = 0; 472562306a36Sopenharmony_ci struct request *rq = scsi_cmd_to_rq(scmd); 472662306a36Sopenharmony_ci int iprio_class; 472762306a36Sopenharmony_ci u8 is_pcie_dev = 0; 472862306a36Sopenharmony_ci u32 tracked_io_sz = 0; 472962306a36Sopenharmony_ci u32 ioc_pend_data_len = 0, tg_pend_data_len = 0; 473062306a36Sopenharmony_ci struct mpi3mr_throttle_group_info *tg = NULL; 473162306a36Sopenharmony_ci 473262306a36Sopenharmony_ci if (mrioc->unrecoverable) { 473362306a36Sopenharmony_ci scmd->result = DID_ERROR << 16; 473462306a36Sopenharmony_ci scsi_done(scmd); 473562306a36Sopenharmony_ci goto out; 473662306a36Sopenharmony_ci } 473762306a36Sopenharmony_ci 473862306a36Sopenharmony_ci sdev_priv_data = scmd->device->hostdata; 473962306a36Sopenharmony_ci if (!sdev_priv_data || !sdev_priv_data->tgt_priv_data) { 474062306a36Sopenharmony_ci scmd->result = DID_NO_CONNECT << 16; 474162306a36Sopenharmony_ci scsi_done(scmd); 474262306a36Sopenharmony_ci goto out; 474362306a36Sopenharmony_ci } 474462306a36Sopenharmony_ci 474562306a36Sopenharmony_ci if (mrioc->stop_drv_processing && 474662306a36Sopenharmony_ci !(mpi3mr_allow_scmd_to_fw(scmd))) { 474762306a36Sopenharmony_ci scmd->result = DID_NO_CONNECT << 16; 474862306a36Sopenharmony_ci scsi_done(scmd); 474962306a36Sopenharmony_ci goto out; 475062306a36Sopenharmony_ci } 475162306a36Sopenharmony_ci 475262306a36Sopenharmony_ci stgt_priv_data = sdev_priv_data->tgt_priv_data; 475362306a36Sopenharmony_ci dev_handle = stgt_priv_data->dev_handle; 475462306a36Sopenharmony_ci 475562306a36Sopenharmony_ci /* Avoid error handling escalation when device is removed or blocked */ 475662306a36Sopenharmony_ci 475762306a36Sopenharmony_ci if (scmd->device->host->shost_state == SHOST_RECOVERY && 475862306a36Sopenharmony_ci scmd->cmnd[0] == TEST_UNIT_READY && 475962306a36Sopenharmony_ci (stgt_priv_data->dev_removed || (dev_handle == MPI3MR_INVALID_DEV_HANDLE))) { 476062306a36Sopenharmony_ci scsi_build_sense(scmd, 0, UNIT_ATTENTION, 0x29, 0x07); 476162306a36Sopenharmony_ci scsi_done(scmd); 476262306a36Sopenharmony_ci goto out; 476362306a36Sopenharmony_ci } 476462306a36Sopenharmony_ci 476562306a36Sopenharmony_ci if (mrioc->reset_in_progress) { 476662306a36Sopenharmony_ci retval = SCSI_MLQUEUE_HOST_BUSY; 476762306a36Sopenharmony_ci goto out; 476862306a36Sopenharmony_ci } 476962306a36Sopenharmony_ci 477062306a36Sopenharmony_ci if (atomic_read(&stgt_priv_data->block_io)) { 477162306a36Sopenharmony_ci if (mrioc->stop_drv_processing) { 477262306a36Sopenharmony_ci scmd->result = DID_NO_CONNECT << 16; 477362306a36Sopenharmony_ci scsi_done(scmd); 477462306a36Sopenharmony_ci goto out; 477562306a36Sopenharmony_ci } 477662306a36Sopenharmony_ci retval = SCSI_MLQUEUE_DEVICE_BUSY; 477762306a36Sopenharmony_ci goto out; 477862306a36Sopenharmony_ci } 477962306a36Sopenharmony_ci 478062306a36Sopenharmony_ci if (dev_handle == MPI3MR_INVALID_DEV_HANDLE) { 478162306a36Sopenharmony_ci scmd->result = DID_NO_CONNECT << 16; 478262306a36Sopenharmony_ci scsi_done(scmd); 478362306a36Sopenharmony_ci goto out; 478462306a36Sopenharmony_ci } 478562306a36Sopenharmony_ci if (stgt_priv_data->dev_removed) { 478662306a36Sopenharmony_ci scmd->result = DID_NO_CONNECT << 16; 478762306a36Sopenharmony_ci scsi_done(scmd); 478862306a36Sopenharmony_ci goto out; 478962306a36Sopenharmony_ci } 479062306a36Sopenharmony_ci 479162306a36Sopenharmony_ci if (stgt_priv_data->dev_type == MPI3_DEVICE_DEVFORM_PCIE) 479262306a36Sopenharmony_ci is_pcie_dev = 1; 479362306a36Sopenharmony_ci if ((scmd->cmnd[0] == UNMAP) && is_pcie_dev && 479462306a36Sopenharmony_ci (mrioc->pdev->device == MPI3_MFGPAGE_DEVID_SAS4116) && 479562306a36Sopenharmony_ci mpi3mr_check_return_unmap(mrioc, scmd)) 479662306a36Sopenharmony_ci goto out; 479762306a36Sopenharmony_ci 479862306a36Sopenharmony_ci host_tag = mpi3mr_host_tag_for_scmd(mrioc, scmd); 479962306a36Sopenharmony_ci if (host_tag == MPI3MR_HOSTTAG_INVALID) { 480062306a36Sopenharmony_ci scmd->result = DID_ERROR << 16; 480162306a36Sopenharmony_ci scsi_done(scmd); 480262306a36Sopenharmony_ci goto out; 480362306a36Sopenharmony_ci } 480462306a36Sopenharmony_ci 480562306a36Sopenharmony_ci if (scmd->sc_data_direction == DMA_FROM_DEVICE) 480662306a36Sopenharmony_ci scsiio_flags = MPI3_SCSIIO_FLAGS_DATADIRECTION_READ; 480762306a36Sopenharmony_ci else if (scmd->sc_data_direction == DMA_TO_DEVICE) 480862306a36Sopenharmony_ci scsiio_flags = MPI3_SCSIIO_FLAGS_DATADIRECTION_WRITE; 480962306a36Sopenharmony_ci else 481062306a36Sopenharmony_ci scsiio_flags = MPI3_SCSIIO_FLAGS_DATADIRECTION_NO_DATA_TRANSFER; 481162306a36Sopenharmony_ci 481262306a36Sopenharmony_ci scsiio_flags |= MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_SIMPLEQ; 481362306a36Sopenharmony_ci 481462306a36Sopenharmony_ci if (sdev_priv_data->ncq_prio_enable) { 481562306a36Sopenharmony_ci iprio_class = IOPRIO_PRIO_CLASS(req_get_ioprio(rq)); 481662306a36Sopenharmony_ci if (iprio_class == IOPRIO_CLASS_RT) 481762306a36Sopenharmony_ci scsiio_flags |= 1 << MPI3_SCSIIO_FLAGS_CMDPRI_SHIFT; 481862306a36Sopenharmony_ci } 481962306a36Sopenharmony_ci 482062306a36Sopenharmony_ci if (scmd->cmd_len > 16) 482162306a36Sopenharmony_ci scsiio_flags |= MPI3_SCSIIO_FLAGS_CDB_GREATER_THAN_16; 482262306a36Sopenharmony_ci 482362306a36Sopenharmony_ci scmd_priv_data = scsi_cmd_priv(scmd); 482462306a36Sopenharmony_ci memset(scmd_priv_data->mpi3mr_scsiio_req, 0, MPI3MR_ADMIN_REQ_FRAME_SZ); 482562306a36Sopenharmony_ci scsiio_req = (struct mpi3_scsi_io_request *)scmd_priv_data->mpi3mr_scsiio_req; 482662306a36Sopenharmony_ci scsiio_req->function = MPI3_FUNCTION_SCSI_IO; 482762306a36Sopenharmony_ci scsiio_req->host_tag = cpu_to_le16(host_tag); 482862306a36Sopenharmony_ci 482962306a36Sopenharmony_ci mpi3mr_setup_eedp(mrioc, scmd, scsiio_req); 483062306a36Sopenharmony_ci 483162306a36Sopenharmony_ci if (stgt_priv_data->wslen) 483262306a36Sopenharmony_ci mpi3mr_setup_divert_ws(mrioc, scmd, scsiio_req, &scsiio_flags, 483362306a36Sopenharmony_ci stgt_priv_data->wslen); 483462306a36Sopenharmony_ci 483562306a36Sopenharmony_ci memcpy(scsiio_req->cdb.cdb32, scmd->cmnd, scmd->cmd_len); 483662306a36Sopenharmony_ci scsiio_req->data_length = cpu_to_le32(scsi_bufflen(scmd)); 483762306a36Sopenharmony_ci scsiio_req->dev_handle = cpu_to_le16(dev_handle); 483862306a36Sopenharmony_ci scsiio_req->flags = cpu_to_le32(scsiio_flags); 483962306a36Sopenharmony_ci int_to_scsilun(sdev_priv_data->lun_id, 484062306a36Sopenharmony_ci (struct scsi_lun *)scsiio_req->lun); 484162306a36Sopenharmony_ci 484262306a36Sopenharmony_ci if (mpi3mr_build_sg_scmd(mrioc, scmd, scsiio_req)) { 484362306a36Sopenharmony_ci mpi3mr_clear_scmd_priv(mrioc, scmd); 484462306a36Sopenharmony_ci retval = SCSI_MLQUEUE_HOST_BUSY; 484562306a36Sopenharmony_ci goto out; 484662306a36Sopenharmony_ci } 484762306a36Sopenharmony_ci op_req_q = &mrioc->req_qinfo[scmd_priv_data->req_q_idx]; 484862306a36Sopenharmony_ci data_len_blks = scsi_bufflen(scmd) >> 9; 484962306a36Sopenharmony_ci if ((data_len_blks >= mrioc->io_throttle_data_length) && 485062306a36Sopenharmony_ci stgt_priv_data->io_throttle_enabled) { 485162306a36Sopenharmony_ci tracked_io_sz = data_len_blks; 485262306a36Sopenharmony_ci tg = stgt_priv_data->throttle_group; 485362306a36Sopenharmony_ci if (tg) { 485462306a36Sopenharmony_ci ioc_pend_data_len = atomic_add_return(data_len_blks, 485562306a36Sopenharmony_ci &mrioc->pend_large_data_sz); 485662306a36Sopenharmony_ci tg_pend_data_len = atomic_add_return(data_len_blks, 485762306a36Sopenharmony_ci &tg->pend_large_data_sz); 485862306a36Sopenharmony_ci if (!tg->io_divert && ((ioc_pend_data_len >= 485962306a36Sopenharmony_ci mrioc->io_throttle_high) || 486062306a36Sopenharmony_ci (tg_pend_data_len >= tg->high))) { 486162306a36Sopenharmony_ci tg->io_divert = 1; 486262306a36Sopenharmony_ci tg->need_qd_reduction = 1; 486362306a36Sopenharmony_ci mpi3mr_set_io_divert_for_all_vd_in_tg(mrioc, 486462306a36Sopenharmony_ci tg, 1); 486562306a36Sopenharmony_ci mpi3mr_queue_qd_reduction_event(mrioc, tg); 486662306a36Sopenharmony_ci } 486762306a36Sopenharmony_ci } else { 486862306a36Sopenharmony_ci ioc_pend_data_len = atomic_add_return(data_len_blks, 486962306a36Sopenharmony_ci &mrioc->pend_large_data_sz); 487062306a36Sopenharmony_ci if (ioc_pend_data_len >= mrioc->io_throttle_high) 487162306a36Sopenharmony_ci stgt_priv_data->io_divert = 1; 487262306a36Sopenharmony_ci } 487362306a36Sopenharmony_ci } 487462306a36Sopenharmony_ci 487562306a36Sopenharmony_ci if (stgt_priv_data->io_divert) { 487662306a36Sopenharmony_ci scsiio_req->msg_flags |= 487762306a36Sopenharmony_ci MPI3_SCSIIO_MSGFLAGS_DIVERT_TO_FIRMWARE; 487862306a36Sopenharmony_ci scsiio_flags |= MPI3_SCSIIO_FLAGS_DIVERT_REASON_IO_THROTTLING; 487962306a36Sopenharmony_ci } 488062306a36Sopenharmony_ci scsiio_req->flags = cpu_to_le32(scsiio_flags); 488162306a36Sopenharmony_ci 488262306a36Sopenharmony_ci if (mpi3mr_op_request_post(mrioc, op_req_q, 488362306a36Sopenharmony_ci scmd_priv_data->mpi3mr_scsiio_req)) { 488462306a36Sopenharmony_ci mpi3mr_clear_scmd_priv(mrioc, scmd); 488562306a36Sopenharmony_ci retval = SCSI_MLQUEUE_HOST_BUSY; 488662306a36Sopenharmony_ci if (tracked_io_sz) { 488762306a36Sopenharmony_ci atomic_sub(tracked_io_sz, &mrioc->pend_large_data_sz); 488862306a36Sopenharmony_ci if (tg) 488962306a36Sopenharmony_ci atomic_sub(tracked_io_sz, 489062306a36Sopenharmony_ci &tg->pend_large_data_sz); 489162306a36Sopenharmony_ci } 489262306a36Sopenharmony_ci goto out; 489362306a36Sopenharmony_ci } 489462306a36Sopenharmony_ci 489562306a36Sopenharmony_ciout: 489662306a36Sopenharmony_ci return retval; 489762306a36Sopenharmony_ci} 489862306a36Sopenharmony_ci 489962306a36Sopenharmony_cistatic const struct scsi_host_template mpi3mr_driver_template = { 490062306a36Sopenharmony_ci .module = THIS_MODULE, 490162306a36Sopenharmony_ci .name = "MPI3 Storage Controller", 490262306a36Sopenharmony_ci .proc_name = MPI3MR_DRIVER_NAME, 490362306a36Sopenharmony_ci .queuecommand = mpi3mr_qcmd, 490462306a36Sopenharmony_ci .target_alloc = mpi3mr_target_alloc, 490562306a36Sopenharmony_ci .slave_alloc = mpi3mr_slave_alloc, 490662306a36Sopenharmony_ci .slave_configure = mpi3mr_slave_configure, 490762306a36Sopenharmony_ci .target_destroy = mpi3mr_target_destroy, 490862306a36Sopenharmony_ci .slave_destroy = mpi3mr_slave_destroy, 490962306a36Sopenharmony_ci .scan_finished = mpi3mr_scan_finished, 491062306a36Sopenharmony_ci .scan_start = mpi3mr_scan_start, 491162306a36Sopenharmony_ci .change_queue_depth = mpi3mr_change_queue_depth, 491262306a36Sopenharmony_ci .eh_device_reset_handler = mpi3mr_eh_dev_reset, 491362306a36Sopenharmony_ci .eh_target_reset_handler = mpi3mr_eh_target_reset, 491462306a36Sopenharmony_ci .eh_host_reset_handler = mpi3mr_eh_host_reset, 491562306a36Sopenharmony_ci .bios_param = mpi3mr_bios_param, 491662306a36Sopenharmony_ci .map_queues = mpi3mr_map_queues, 491762306a36Sopenharmony_ci .mq_poll = mpi3mr_blk_mq_poll, 491862306a36Sopenharmony_ci .no_write_same = 1, 491962306a36Sopenharmony_ci .can_queue = 1, 492062306a36Sopenharmony_ci .this_id = -1, 492162306a36Sopenharmony_ci .sg_tablesize = MPI3MR_DEFAULT_SGL_ENTRIES, 492262306a36Sopenharmony_ci /* max xfer supported is 1M (2K in 512 byte sized sectors) 492362306a36Sopenharmony_ci */ 492462306a36Sopenharmony_ci .max_sectors = (MPI3MR_DEFAULT_MAX_IO_SIZE / 512), 492562306a36Sopenharmony_ci .cmd_per_lun = MPI3MR_MAX_CMDS_LUN, 492662306a36Sopenharmony_ci .max_segment_size = 0xffffffff, 492762306a36Sopenharmony_ci .track_queue_depth = 1, 492862306a36Sopenharmony_ci .cmd_size = sizeof(struct scmd_priv), 492962306a36Sopenharmony_ci .shost_groups = mpi3mr_host_groups, 493062306a36Sopenharmony_ci .sdev_groups = mpi3mr_dev_groups, 493162306a36Sopenharmony_ci}; 493262306a36Sopenharmony_ci 493362306a36Sopenharmony_ci/** 493462306a36Sopenharmony_ci * mpi3mr_init_drv_cmd - Initialize internal command tracker 493562306a36Sopenharmony_ci * @cmdptr: Internal command tracker 493662306a36Sopenharmony_ci * @host_tag: Host tag used for the specific command 493762306a36Sopenharmony_ci * 493862306a36Sopenharmony_ci * Initialize the internal command tracker structure with 493962306a36Sopenharmony_ci * specified host tag. 494062306a36Sopenharmony_ci * 494162306a36Sopenharmony_ci * Return: Nothing. 494262306a36Sopenharmony_ci */ 494362306a36Sopenharmony_cistatic inline void mpi3mr_init_drv_cmd(struct mpi3mr_drv_cmd *cmdptr, 494462306a36Sopenharmony_ci u16 host_tag) 494562306a36Sopenharmony_ci{ 494662306a36Sopenharmony_ci mutex_init(&cmdptr->mutex); 494762306a36Sopenharmony_ci cmdptr->reply = NULL; 494862306a36Sopenharmony_ci cmdptr->state = MPI3MR_CMD_NOTUSED; 494962306a36Sopenharmony_ci cmdptr->dev_handle = MPI3MR_INVALID_DEV_HANDLE; 495062306a36Sopenharmony_ci cmdptr->host_tag = host_tag; 495162306a36Sopenharmony_ci} 495262306a36Sopenharmony_ci 495362306a36Sopenharmony_ci/** 495462306a36Sopenharmony_ci * osintfc_mrioc_security_status -Check controller secure status 495562306a36Sopenharmony_ci * @pdev: PCI device instance 495662306a36Sopenharmony_ci * 495762306a36Sopenharmony_ci * Read the Device Serial Number capability from PCI config 495862306a36Sopenharmony_ci * space and decide whether the controller is secure or not. 495962306a36Sopenharmony_ci * 496062306a36Sopenharmony_ci * Return: 0 on success, non-zero on failure. 496162306a36Sopenharmony_ci */ 496262306a36Sopenharmony_cistatic int 496362306a36Sopenharmony_ciosintfc_mrioc_security_status(struct pci_dev *pdev) 496462306a36Sopenharmony_ci{ 496562306a36Sopenharmony_ci u32 cap_data; 496662306a36Sopenharmony_ci int base; 496762306a36Sopenharmony_ci u32 ctlr_status; 496862306a36Sopenharmony_ci u32 debug_status; 496962306a36Sopenharmony_ci int retval = 0; 497062306a36Sopenharmony_ci 497162306a36Sopenharmony_ci base = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_DSN); 497262306a36Sopenharmony_ci if (!base) { 497362306a36Sopenharmony_ci dev_err(&pdev->dev, 497462306a36Sopenharmony_ci "%s: PCI_EXT_CAP_ID_DSN is not supported\n", __func__); 497562306a36Sopenharmony_ci return -1; 497662306a36Sopenharmony_ci } 497762306a36Sopenharmony_ci 497862306a36Sopenharmony_ci pci_read_config_dword(pdev, base + 4, &cap_data); 497962306a36Sopenharmony_ci 498062306a36Sopenharmony_ci debug_status = cap_data & MPI3MR_CTLR_SECURE_DBG_STATUS_MASK; 498162306a36Sopenharmony_ci ctlr_status = cap_data & MPI3MR_CTLR_SECURITY_STATUS_MASK; 498262306a36Sopenharmony_ci 498362306a36Sopenharmony_ci switch (ctlr_status) { 498462306a36Sopenharmony_ci case MPI3MR_INVALID_DEVICE: 498562306a36Sopenharmony_ci dev_err(&pdev->dev, 498662306a36Sopenharmony_ci "%s: Non secure ctlr (Invalid) is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n", 498762306a36Sopenharmony_ci __func__, pdev->device, pdev->subsystem_vendor, 498862306a36Sopenharmony_ci pdev->subsystem_device); 498962306a36Sopenharmony_ci retval = -1; 499062306a36Sopenharmony_ci break; 499162306a36Sopenharmony_ci case MPI3MR_CONFIG_SECURE_DEVICE: 499262306a36Sopenharmony_ci if (!debug_status) 499362306a36Sopenharmony_ci dev_info(&pdev->dev, 499462306a36Sopenharmony_ci "%s: Config secure ctlr is detected\n", 499562306a36Sopenharmony_ci __func__); 499662306a36Sopenharmony_ci break; 499762306a36Sopenharmony_ci case MPI3MR_HARD_SECURE_DEVICE: 499862306a36Sopenharmony_ci break; 499962306a36Sopenharmony_ci case MPI3MR_TAMPERED_DEVICE: 500062306a36Sopenharmony_ci dev_err(&pdev->dev, 500162306a36Sopenharmony_ci "%s: Non secure ctlr (Tampered) is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n", 500262306a36Sopenharmony_ci __func__, pdev->device, pdev->subsystem_vendor, 500362306a36Sopenharmony_ci pdev->subsystem_device); 500462306a36Sopenharmony_ci retval = -1; 500562306a36Sopenharmony_ci break; 500662306a36Sopenharmony_ci default: 500762306a36Sopenharmony_ci retval = -1; 500862306a36Sopenharmony_ci break; 500962306a36Sopenharmony_ci } 501062306a36Sopenharmony_ci 501162306a36Sopenharmony_ci if (!retval && debug_status) { 501262306a36Sopenharmony_ci dev_err(&pdev->dev, 501362306a36Sopenharmony_ci "%s: Non secure ctlr (Secure Dbg) is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n", 501462306a36Sopenharmony_ci __func__, pdev->device, pdev->subsystem_vendor, 501562306a36Sopenharmony_ci pdev->subsystem_device); 501662306a36Sopenharmony_ci retval = -1; 501762306a36Sopenharmony_ci } 501862306a36Sopenharmony_ci 501962306a36Sopenharmony_ci return retval; 502062306a36Sopenharmony_ci} 502162306a36Sopenharmony_ci 502262306a36Sopenharmony_ci/** 502362306a36Sopenharmony_ci * mpi3mr_probe - PCI probe callback 502462306a36Sopenharmony_ci * @pdev: PCI device instance 502562306a36Sopenharmony_ci * @id: PCI device ID details 502662306a36Sopenharmony_ci * 502762306a36Sopenharmony_ci * controller initialization routine. Checks the security status 502862306a36Sopenharmony_ci * of the controller and if it is invalid or tampered return the 502962306a36Sopenharmony_ci * probe without initializing the controller. Otherwise, 503062306a36Sopenharmony_ci * allocate per adapter instance through shost_priv and 503162306a36Sopenharmony_ci * initialize controller specific data structures, initializae 503262306a36Sopenharmony_ci * the controller hardware, add shost to the SCSI subsystem. 503362306a36Sopenharmony_ci * 503462306a36Sopenharmony_ci * Return: 0 on success, non-zero on failure. 503562306a36Sopenharmony_ci */ 503662306a36Sopenharmony_ci 503762306a36Sopenharmony_cistatic int 503862306a36Sopenharmony_cimpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id) 503962306a36Sopenharmony_ci{ 504062306a36Sopenharmony_ci struct mpi3mr_ioc *mrioc = NULL; 504162306a36Sopenharmony_ci struct Scsi_Host *shost = NULL; 504262306a36Sopenharmony_ci int retval = 0, i; 504362306a36Sopenharmony_ci 504462306a36Sopenharmony_ci if (osintfc_mrioc_security_status(pdev)) { 504562306a36Sopenharmony_ci warn_non_secure_ctlr = 1; 504662306a36Sopenharmony_ci return 1; /* For Invalid and Tampered device */ 504762306a36Sopenharmony_ci } 504862306a36Sopenharmony_ci 504962306a36Sopenharmony_ci shost = scsi_host_alloc(&mpi3mr_driver_template, 505062306a36Sopenharmony_ci sizeof(struct mpi3mr_ioc)); 505162306a36Sopenharmony_ci if (!shost) { 505262306a36Sopenharmony_ci retval = -ENODEV; 505362306a36Sopenharmony_ci goto shost_failed; 505462306a36Sopenharmony_ci } 505562306a36Sopenharmony_ci 505662306a36Sopenharmony_ci mrioc = shost_priv(shost); 505762306a36Sopenharmony_ci mrioc->id = mrioc_ids++; 505862306a36Sopenharmony_ci sprintf(mrioc->driver_name, "%s", MPI3MR_DRIVER_NAME); 505962306a36Sopenharmony_ci sprintf(mrioc->name, "%s%d", mrioc->driver_name, mrioc->id); 506062306a36Sopenharmony_ci INIT_LIST_HEAD(&mrioc->list); 506162306a36Sopenharmony_ci spin_lock(&mrioc_list_lock); 506262306a36Sopenharmony_ci list_add_tail(&mrioc->list, &mrioc_list); 506362306a36Sopenharmony_ci spin_unlock(&mrioc_list_lock); 506462306a36Sopenharmony_ci 506562306a36Sopenharmony_ci spin_lock_init(&mrioc->admin_req_lock); 506662306a36Sopenharmony_ci spin_lock_init(&mrioc->reply_free_queue_lock); 506762306a36Sopenharmony_ci spin_lock_init(&mrioc->sbq_lock); 506862306a36Sopenharmony_ci spin_lock_init(&mrioc->fwevt_lock); 506962306a36Sopenharmony_ci spin_lock_init(&mrioc->tgtdev_lock); 507062306a36Sopenharmony_ci spin_lock_init(&mrioc->watchdog_lock); 507162306a36Sopenharmony_ci spin_lock_init(&mrioc->chain_buf_lock); 507262306a36Sopenharmony_ci spin_lock_init(&mrioc->sas_node_lock); 507362306a36Sopenharmony_ci 507462306a36Sopenharmony_ci INIT_LIST_HEAD(&mrioc->fwevt_list); 507562306a36Sopenharmony_ci INIT_LIST_HEAD(&mrioc->tgtdev_list); 507662306a36Sopenharmony_ci INIT_LIST_HEAD(&mrioc->delayed_rmhs_list); 507762306a36Sopenharmony_ci INIT_LIST_HEAD(&mrioc->delayed_evtack_cmds_list); 507862306a36Sopenharmony_ci INIT_LIST_HEAD(&mrioc->sas_expander_list); 507962306a36Sopenharmony_ci INIT_LIST_HEAD(&mrioc->hba_port_table_list); 508062306a36Sopenharmony_ci INIT_LIST_HEAD(&mrioc->enclosure_list); 508162306a36Sopenharmony_ci 508262306a36Sopenharmony_ci mutex_init(&mrioc->reset_mutex); 508362306a36Sopenharmony_ci mpi3mr_init_drv_cmd(&mrioc->init_cmds, MPI3MR_HOSTTAG_INITCMDS); 508462306a36Sopenharmony_ci mpi3mr_init_drv_cmd(&mrioc->host_tm_cmds, MPI3MR_HOSTTAG_BLK_TMS); 508562306a36Sopenharmony_ci mpi3mr_init_drv_cmd(&mrioc->bsg_cmds, MPI3MR_HOSTTAG_BSG_CMDS); 508662306a36Sopenharmony_ci mpi3mr_init_drv_cmd(&mrioc->cfg_cmds, MPI3MR_HOSTTAG_CFG_CMDS); 508762306a36Sopenharmony_ci mpi3mr_init_drv_cmd(&mrioc->transport_cmds, 508862306a36Sopenharmony_ci MPI3MR_HOSTTAG_TRANSPORT_CMDS); 508962306a36Sopenharmony_ci 509062306a36Sopenharmony_ci for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) 509162306a36Sopenharmony_ci mpi3mr_init_drv_cmd(&mrioc->dev_rmhs_cmds[i], 509262306a36Sopenharmony_ci MPI3MR_HOSTTAG_DEVRMCMD_MIN + i); 509362306a36Sopenharmony_ci 509462306a36Sopenharmony_ci for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) 509562306a36Sopenharmony_ci mpi3mr_init_drv_cmd(&mrioc->evtack_cmds[i], 509662306a36Sopenharmony_ci MPI3MR_HOSTTAG_EVTACKCMD_MIN + i); 509762306a36Sopenharmony_ci 509862306a36Sopenharmony_ci if ((pdev->device == MPI3_MFGPAGE_DEVID_SAS4116) && 509962306a36Sopenharmony_ci !pdev->revision) 510062306a36Sopenharmony_ci mrioc->enable_segqueue = false; 510162306a36Sopenharmony_ci else 510262306a36Sopenharmony_ci mrioc->enable_segqueue = true; 510362306a36Sopenharmony_ci 510462306a36Sopenharmony_ci init_waitqueue_head(&mrioc->reset_waitq); 510562306a36Sopenharmony_ci mrioc->logging_level = logging_level; 510662306a36Sopenharmony_ci mrioc->shost = shost; 510762306a36Sopenharmony_ci mrioc->pdev = pdev; 510862306a36Sopenharmony_ci mrioc->stop_bsgs = 1; 510962306a36Sopenharmony_ci 511062306a36Sopenharmony_ci mrioc->max_sgl_entries = max_sgl_entries; 511162306a36Sopenharmony_ci if (max_sgl_entries > MPI3MR_MAX_SGL_ENTRIES) 511262306a36Sopenharmony_ci mrioc->max_sgl_entries = MPI3MR_MAX_SGL_ENTRIES; 511362306a36Sopenharmony_ci else if (max_sgl_entries < MPI3MR_DEFAULT_SGL_ENTRIES) 511462306a36Sopenharmony_ci mrioc->max_sgl_entries = MPI3MR_DEFAULT_SGL_ENTRIES; 511562306a36Sopenharmony_ci else { 511662306a36Sopenharmony_ci mrioc->max_sgl_entries /= MPI3MR_DEFAULT_SGL_ENTRIES; 511762306a36Sopenharmony_ci mrioc->max_sgl_entries *= MPI3MR_DEFAULT_SGL_ENTRIES; 511862306a36Sopenharmony_ci } 511962306a36Sopenharmony_ci 512062306a36Sopenharmony_ci /* init shost parameters */ 512162306a36Sopenharmony_ci shost->max_cmd_len = MPI3MR_MAX_CDB_LENGTH; 512262306a36Sopenharmony_ci shost->max_lun = -1; 512362306a36Sopenharmony_ci shost->unique_id = mrioc->id; 512462306a36Sopenharmony_ci 512562306a36Sopenharmony_ci shost->max_channel = 0; 512662306a36Sopenharmony_ci shost->max_id = 0xFFFFFFFF; 512762306a36Sopenharmony_ci 512862306a36Sopenharmony_ci shost->host_tagset = 1; 512962306a36Sopenharmony_ci 513062306a36Sopenharmony_ci if (prot_mask >= 0) 513162306a36Sopenharmony_ci scsi_host_set_prot(shost, prot_mask); 513262306a36Sopenharmony_ci else { 513362306a36Sopenharmony_ci prot_mask = SHOST_DIF_TYPE1_PROTECTION 513462306a36Sopenharmony_ci | SHOST_DIF_TYPE2_PROTECTION 513562306a36Sopenharmony_ci | SHOST_DIF_TYPE3_PROTECTION; 513662306a36Sopenharmony_ci scsi_host_set_prot(shost, prot_mask); 513762306a36Sopenharmony_ci } 513862306a36Sopenharmony_ci 513962306a36Sopenharmony_ci ioc_info(mrioc, 514062306a36Sopenharmony_ci "%s :host protection capabilities enabled %s%s%s%s%s%s%s\n", 514162306a36Sopenharmony_ci __func__, 514262306a36Sopenharmony_ci (prot_mask & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "", 514362306a36Sopenharmony_ci (prot_mask & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "", 514462306a36Sopenharmony_ci (prot_mask & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "", 514562306a36Sopenharmony_ci (prot_mask & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "", 514662306a36Sopenharmony_ci (prot_mask & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "", 514762306a36Sopenharmony_ci (prot_mask & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "", 514862306a36Sopenharmony_ci (prot_mask & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : ""); 514962306a36Sopenharmony_ci 515062306a36Sopenharmony_ci if (prot_guard_mask) 515162306a36Sopenharmony_ci scsi_host_set_guard(shost, (prot_guard_mask & 3)); 515262306a36Sopenharmony_ci else 515362306a36Sopenharmony_ci scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC); 515462306a36Sopenharmony_ci 515562306a36Sopenharmony_ci snprintf(mrioc->fwevt_worker_name, sizeof(mrioc->fwevt_worker_name), 515662306a36Sopenharmony_ci "%s%d_fwevt_wrkr", mrioc->driver_name, mrioc->id); 515762306a36Sopenharmony_ci mrioc->fwevt_worker_thread = alloc_ordered_workqueue( 515862306a36Sopenharmony_ci mrioc->fwevt_worker_name, 0); 515962306a36Sopenharmony_ci if (!mrioc->fwevt_worker_thread) { 516062306a36Sopenharmony_ci ioc_err(mrioc, "failure at %s:%d/%s()!\n", 516162306a36Sopenharmony_ci __FILE__, __LINE__, __func__); 516262306a36Sopenharmony_ci retval = -ENODEV; 516362306a36Sopenharmony_ci goto fwevtthread_failed; 516462306a36Sopenharmony_ci } 516562306a36Sopenharmony_ci 516662306a36Sopenharmony_ci mrioc->is_driver_loading = 1; 516762306a36Sopenharmony_ci mrioc->cpu_count = num_online_cpus(); 516862306a36Sopenharmony_ci if (mpi3mr_setup_resources(mrioc)) { 516962306a36Sopenharmony_ci ioc_err(mrioc, "setup resources failed\n"); 517062306a36Sopenharmony_ci retval = -ENODEV; 517162306a36Sopenharmony_ci goto resource_alloc_failed; 517262306a36Sopenharmony_ci } 517362306a36Sopenharmony_ci if (mpi3mr_init_ioc(mrioc)) { 517462306a36Sopenharmony_ci ioc_err(mrioc, "initializing IOC failed\n"); 517562306a36Sopenharmony_ci retval = -ENODEV; 517662306a36Sopenharmony_ci goto init_ioc_failed; 517762306a36Sopenharmony_ci } 517862306a36Sopenharmony_ci 517962306a36Sopenharmony_ci shost->nr_hw_queues = mrioc->num_op_reply_q; 518062306a36Sopenharmony_ci if (mrioc->active_poll_qcount) 518162306a36Sopenharmony_ci shost->nr_maps = 3; 518262306a36Sopenharmony_ci 518362306a36Sopenharmony_ci shost->can_queue = mrioc->max_host_ios; 518462306a36Sopenharmony_ci shost->sg_tablesize = mrioc->max_sgl_entries; 518562306a36Sopenharmony_ci shost->max_id = mrioc->facts.max_perids + 1; 518662306a36Sopenharmony_ci 518762306a36Sopenharmony_ci retval = scsi_add_host(shost, &pdev->dev); 518862306a36Sopenharmony_ci if (retval) { 518962306a36Sopenharmony_ci ioc_err(mrioc, "failure at %s:%d/%s()!\n", 519062306a36Sopenharmony_ci __FILE__, __LINE__, __func__); 519162306a36Sopenharmony_ci goto addhost_failed; 519262306a36Sopenharmony_ci } 519362306a36Sopenharmony_ci 519462306a36Sopenharmony_ci scsi_scan_host(shost); 519562306a36Sopenharmony_ci mpi3mr_bsg_init(mrioc); 519662306a36Sopenharmony_ci return retval; 519762306a36Sopenharmony_ci 519862306a36Sopenharmony_ciaddhost_failed: 519962306a36Sopenharmony_ci mpi3mr_stop_watchdog(mrioc); 520062306a36Sopenharmony_ci mpi3mr_cleanup_ioc(mrioc); 520162306a36Sopenharmony_ciinit_ioc_failed: 520262306a36Sopenharmony_ci mpi3mr_free_mem(mrioc); 520362306a36Sopenharmony_ci mpi3mr_cleanup_resources(mrioc); 520462306a36Sopenharmony_ciresource_alloc_failed: 520562306a36Sopenharmony_ci destroy_workqueue(mrioc->fwevt_worker_thread); 520662306a36Sopenharmony_cifwevtthread_failed: 520762306a36Sopenharmony_ci spin_lock(&mrioc_list_lock); 520862306a36Sopenharmony_ci list_del(&mrioc->list); 520962306a36Sopenharmony_ci spin_unlock(&mrioc_list_lock); 521062306a36Sopenharmony_ci scsi_host_put(shost); 521162306a36Sopenharmony_cishost_failed: 521262306a36Sopenharmony_ci return retval; 521362306a36Sopenharmony_ci} 521462306a36Sopenharmony_ci 521562306a36Sopenharmony_ci/** 521662306a36Sopenharmony_ci * mpi3mr_remove - PCI remove callback 521762306a36Sopenharmony_ci * @pdev: PCI device instance 521862306a36Sopenharmony_ci * 521962306a36Sopenharmony_ci * Cleanup the IOC by issuing MUR and shutdown notification. 522062306a36Sopenharmony_ci * Free up all memory and resources associated with the 522162306a36Sopenharmony_ci * controllerand target devices, unregister the shost. 522262306a36Sopenharmony_ci * 522362306a36Sopenharmony_ci * Return: Nothing. 522462306a36Sopenharmony_ci */ 522562306a36Sopenharmony_cistatic void mpi3mr_remove(struct pci_dev *pdev) 522662306a36Sopenharmony_ci{ 522762306a36Sopenharmony_ci struct Scsi_Host *shost = pci_get_drvdata(pdev); 522862306a36Sopenharmony_ci struct mpi3mr_ioc *mrioc; 522962306a36Sopenharmony_ci struct workqueue_struct *wq; 523062306a36Sopenharmony_ci unsigned long flags; 523162306a36Sopenharmony_ci struct mpi3mr_tgt_dev *tgtdev, *tgtdev_next; 523262306a36Sopenharmony_ci struct mpi3mr_hba_port *port, *hba_port_next; 523362306a36Sopenharmony_ci struct mpi3mr_sas_node *sas_expander, *sas_expander_next; 523462306a36Sopenharmony_ci 523562306a36Sopenharmony_ci if (!shost) 523662306a36Sopenharmony_ci return; 523762306a36Sopenharmony_ci 523862306a36Sopenharmony_ci mrioc = shost_priv(shost); 523962306a36Sopenharmony_ci while (mrioc->reset_in_progress || mrioc->is_driver_loading) 524062306a36Sopenharmony_ci ssleep(1); 524162306a36Sopenharmony_ci 524262306a36Sopenharmony_ci if (!pci_device_is_present(mrioc->pdev)) { 524362306a36Sopenharmony_ci mrioc->unrecoverable = 1; 524462306a36Sopenharmony_ci mpi3mr_flush_cmds_for_unrecovered_controller(mrioc); 524562306a36Sopenharmony_ci } 524662306a36Sopenharmony_ci 524762306a36Sopenharmony_ci mpi3mr_bsg_exit(mrioc); 524862306a36Sopenharmony_ci mrioc->stop_drv_processing = 1; 524962306a36Sopenharmony_ci mpi3mr_cleanup_fwevt_list(mrioc); 525062306a36Sopenharmony_ci spin_lock_irqsave(&mrioc->fwevt_lock, flags); 525162306a36Sopenharmony_ci wq = mrioc->fwevt_worker_thread; 525262306a36Sopenharmony_ci mrioc->fwevt_worker_thread = NULL; 525362306a36Sopenharmony_ci spin_unlock_irqrestore(&mrioc->fwevt_lock, flags); 525462306a36Sopenharmony_ci if (wq) 525562306a36Sopenharmony_ci destroy_workqueue(wq); 525662306a36Sopenharmony_ci 525762306a36Sopenharmony_ci if (mrioc->sas_transport_enabled) 525862306a36Sopenharmony_ci sas_remove_host(shost); 525962306a36Sopenharmony_ci else 526062306a36Sopenharmony_ci scsi_remove_host(shost); 526162306a36Sopenharmony_ci 526262306a36Sopenharmony_ci list_for_each_entry_safe(tgtdev, tgtdev_next, &mrioc->tgtdev_list, 526362306a36Sopenharmony_ci list) { 526462306a36Sopenharmony_ci mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev); 526562306a36Sopenharmony_ci mpi3mr_tgtdev_del_from_list(mrioc, tgtdev, true); 526662306a36Sopenharmony_ci mpi3mr_tgtdev_put(tgtdev); 526762306a36Sopenharmony_ci } 526862306a36Sopenharmony_ci mpi3mr_stop_watchdog(mrioc); 526962306a36Sopenharmony_ci mpi3mr_cleanup_ioc(mrioc); 527062306a36Sopenharmony_ci mpi3mr_free_mem(mrioc); 527162306a36Sopenharmony_ci mpi3mr_cleanup_resources(mrioc); 527262306a36Sopenharmony_ci 527362306a36Sopenharmony_ci spin_lock_irqsave(&mrioc->sas_node_lock, flags); 527462306a36Sopenharmony_ci list_for_each_entry_safe_reverse(sas_expander, sas_expander_next, 527562306a36Sopenharmony_ci &mrioc->sas_expander_list, list) { 527662306a36Sopenharmony_ci spin_unlock_irqrestore(&mrioc->sas_node_lock, flags); 527762306a36Sopenharmony_ci mpi3mr_expander_node_remove(mrioc, sas_expander); 527862306a36Sopenharmony_ci spin_lock_irqsave(&mrioc->sas_node_lock, flags); 527962306a36Sopenharmony_ci } 528062306a36Sopenharmony_ci list_for_each_entry_safe(port, hba_port_next, &mrioc->hba_port_table_list, list) { 528162306a36Sopenharmony_ci ioc_info(mrioc, 528262306a36Sopenharmony_ci "removing hba_port entry: %p port: %d from hba_port list\n", 528362306a36Sopenharmony_ci port, port->port_id); 528462306a36Sopenharmony_ci list_del(&port->list); 528562306a36Sopenharmony_ci kfree(port); 528662306a36Sopenharmony_ci } 528762306a36Sopenharmony_ci spin_unlock_irqrestore(&mrioc->sas_node_lock, flags); 528862306a36Sopenharmony_ci 528962306a36Sopenharmony_ci if (mrioc->sas_hba.num_phys) { 529062306a36Sopenharmony_ci kfree(mrioc->sas_hba.phy); 529162306a36Sopenharmony_ci mrioc->sas_hba.phy = NULL; 529262306a36Sopenharmony_ci mrioc->sas_hba.num_phys = 0; 529362306a36Sopenharmony_ci } 529462306a36Sopenharmony_ci 529562306a36Sopenharmony_ci spin_lock(&mrioc_list_lock); 529662306a36Sopenharmony_ci list_del(&mrioc->list); 529762306a36Sopenharmony_ci spin_unlock(&mrioc_list_lock); 529862306a36Sopenharmony_ci 529962306a36Sopenharmony_ci scsi_host_put(shost); 530062306a36Sopenharmony_ci} 530162306a36Sopenharmony_ci 530262306a36Sopenharmony_ci/** 530362306a36Sopenharmony_ci * mpi3mr_shutdown - PCI shutdown callback 530462306a36Sopenharmony_ci * @pdev: PCI device instance 530562306a36Sopenharmony_ci * 530662306a36Sopenharmony_ci * Free up all memory and resources associated with the 530762306a36Sopenharmony_ci * controller 530862306a36Sopenharmony_ci * 530962306a36Sopenharmony_ci * Return: Nothing. 531062306a36Sopenharmony_ci */ 531162306a36Sopenharmony_cistatic void mpi3mr_shutdown(struct pci_dev *pdev) 531262306a36Sopenharmony_ci{ 531362306a36Sopenharmony_ci struct Scsi_Host *shost = pci_get_drvdata(pdev); 531462306a36Sopenharmony_ci struct mpi3mr_ioc *mrioc; 531562306a36Sopenharmony_ci struct workqueue_struct *wq; 531662306a36Sopenharmony_ci unsigned long flags; 531762306a36Sopenharmony_ci 531862306a36Sopenharmony_ci if (!shost) 531962306a36Sopenharmony_ci return; 532062306a36Sopenharmony_ci 532162306a36Sopenharmony_ci mrioc = shost_priv(shost); 532262306a36Sopenharmony_ci while (mrioc->reset_in_progress || mrioc->is_driver_loading) 532362306a36Sopenharmony_ci ssleep(1); 532462306a36Sopenharmony_ci 532562306a36Sopenharmony_ci mrioc->stop_drv_processing = 1; 532662306a36Sopenharmony_ci mpi3mr_cleanup_fwevt_list(mrioc); 532762306a36Sopenharmony_ci spin_lock_irqsave(&mrioc->fwevt_lock, flags); 532862306a36Sopenharmony_ci wq = mrioc->fwevt_worker_thread; 532962306a36Sopenharmony_ci mrioc->fwevt_worker_thread = NULL; 533062306a36Sopenharmony_ci spin_unlock_irqrestore(&mrioc->fwevt_lock, flags); 533162306a36Sopenharmony_ci if (wq) 533262306a36Sopenharmony_ci destroy_workqueue(wq); 533362306a36Sopenharmony_ci 533462306a36Sopenharmony_ci mpi3mr_stop_watchdog(mrioc); 533562306a36Sopenharmony_ci mpi3mr_cleanup_ioc(mrioc); 533662306a36Sopenharmony_ci mpi3mr_cleanup_resources(mrioc); 533762306a36Sopenharmony_ci} 533862306a36Sopenharmony_ci 533962306a36Sopenharmony_ci/** 534062306a36Sopenharmony_ci * mpi3mr_suspend - PCI power management suspend callback 534162306a36Sopenharmony_ci * @dev: Device struct 534262306a36Sopenharmony_ci * 534362306a36Sopenharmony_ci * Change the power state to the given value and cleanup the IOC 534462306a36Sopenharmony_ci * by issuing MUR and shutdown notification 534562306a36Sopenharmony_ci * 534662306a36Sopenharmony_ci * Return: 0 always. 534762306a36Sopenharmony_ci */ 534862306a36Sopenharmony_cistatic int __maybe_unused 534962306a36Sopenharmony_cimpi3mr_suspend(struct device *dev) 535062306a36Sopenharmony_ci{ 535162306a36Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev); 535262306a36Sopenharmony_ci struct Scsi_Host *shost = pci_get_drvdata(pdev); 535362306a36Sopenharmony_ci struct mpi3mr_ioc *mrioc; 535462306a36Sopenharmony_ci 535562306a36Sopenharmony_ci if (!shost) 535662306a36Sopenharmony_ci return 0; 535762306a36Sopenharmony_ci 535862306a36Sopenharmony_ci mrioc = shost_priv(shost); 535962306a36Sopenharmony_ci while (mrioc->reset_in_progress || mrioc->is_driver_loading) 536062306a36Sopenharmony_ci ssleep(1); 536162306a36Sopenharmony_ci mrioc->stop_drv_processing = 1; 536262306a36Sopenharmony_ci mpi3mr_cleanup_fwevt_list(mrioc); 536362306a36Sopenharmony_ci scsi_block_requests(shost); 536462306a36Sopenharmony_ci mpi3mr_stop_watchdog(mrioc); 536562306a36Sopenharmony_ci mpi3mr_cleanup_ioc(mrioc); 536662306a36Sopenharmony_ci 536762306a36Sopenharmony_ci ioc_info(mrioc, "pdev=0x%p, slot=%s, entering operating state\n", 536862306a36Sopenharmony_ci pdev, pci_name(pdev)); 536962306a36Sopenharmony_ci mpi3mr_cleanup_resources(mrioc); 537062306a36Sopenharmony_ci 537162306a36Sopenharmony_ci return 0; 537262306a36Sopenharmony_ci} 537362306a36Sopenharmony_ci 537462306a36Sopenharmony_ci/** 537562306a36Sopenharmony_ci * mpi3mr_resume - PCI power management resume callback 537662306a36Sopenharmony_ci * @dev: Device struct 537762306a36Sopenharmony_ci * 537862306a36Sopenharmony_ci * Restore the power state to D0 and reinitialize the controller 537962306a36Sopenharmony_ci * and resume I/O operations to the target devices 538062306a36Sopenharmony_ci * 538162306a36Sopenharmony_ci * Return: 0 on success, non-zero on failure 538262306a36Sopenharmony_ci */ 538362306a36Sopenharmony_cistatic int __maybe_unused 538462306a36Sopenharmony_cimpi3mr_resume(struct device *dev) 538562306a36Sopenharmony_ci{ 538662306a36Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev); 538762306a36Sopenharmony_ci struct Scsi_Host *shost = pci_get_drvdata(pdev); 538862306a36Sopenharmony_ci struct mpi3mr_ioc *mrioc; 538962306a36Sopenharmony_ci pci_power_t device_state = pdev->current_state; 539062306a36Sopenharmony_ci int r; 539162306a36Sopenharmony_ci 539262306a36Sopenharmony_ci if (!shost) 539362306a36Sopenharmony_ci return 0; 539462306a36Sopenharmony_ci 539562306a36Sopenharmony_ci mrioc = shost_priv(shost); 539662306a36Sopenharmony_ci 539762306a36Sopenharmony_ci ioc_info(mrioc, "pdev=0x%p, slot=%s, previous operating state [D%d]\n", 539862306a36Sopenharmony_ci pdev, pci_name(pdev), device_state); 539962306a36Sopenharmony_ci mrioc->pdev = pdev; 540062306a36Sopenharmony_ci mrioc->cpu_count = num_online_cpus(); 540162306a36Sopenharmony_ci r = mpi3mr_setup_resources(mrioc); 540262306a36Sopenharmony_ci if (r) { 540362306a36Sopenharmony_ci ioc_info(mrioc, "%s: Setup resources failed[%d]\n", 540462306a36Sopenharmony_ci __func__, r); 540562306a36Sopenharmony_ci return r; 540662306a36Sopenharmony_ci } 540762306a36Sopenharmony_ci 540862306a36Sopenharmony_ci mrioc->stop_drv_processing = 0; 540962306a36Sopenharmony_ci mpi3mr_invalidate_devhandles(mrioc); 541062306a36Sopenharmony_ci mpi3mr_free_enclosure_list(mrioc); 541162306a36Sopenharmony_ci mpi3mr_memset_buffers(mrioc); 541262306a36Sopenharmony_ci r = mpi3mr_reinit_ioc(mrioc, 1); 541362306a36Sopenharmony_ci if (r) { 541462306a36Sopenharmony_ci ioc_err(mrioc, "resuming controller failed[%d]\n", r); 541562306a36Sopenharmony_ci return r; 541662306a36Sopenharmony_ci } 541762306a36Sopenharmony_ci ssleep(MPI3MR_RESET_TOPOLOGY_SETTLE_TIME); 541862306a36Sopenharmony_ci scsi_unblock_requests(shost); 541962306a36Sopenharmony_ci mrioc->device_refresh_on = 0; 542062306a36Sopenharmony_ci mpi3mr_start_watchdog(mrioc); 542162306a36Sopenharmony_ci 542262306a36Sopenharmony_ci return 0; 542362306a36Sopenharmony_ci} 542462306a36Sopenharmony_ci 542562306a36Sopenharmony_cistatic const struct pci_device_id mpi3mr_pci_id_table[] = { 542662306a36Sopenharmony_ci { 542762306a36Sopenharmony_ci PCI_DEVICE_SUB(MPI3_MFGPAGE_VENDORID_BROADCOM, 542862306a36Sopenharmony_ci MPI3_MFGPAGE_DEVID_SAS4116, PCI_ANY_ID, PCI_ANY_ID) 542962306a36Sopenharmony_ci }, 543062306a36Sopenharmony_ci { 543162306a36Sopenharmony_ci PCI_DEVICE_SUB(MPI3_MFGPAGE_VENDORID_BROADCOM, 543262306a36Sopenharmony_ci MPI3_MFGPAGE_DEVID_SAS5116_MPI, PCI_ANY_ID, PCI_ANY_ID) 543362306a36Sopenharmony_ci }, 543462306a36Sopenharmony_ci { 543562306a36Sopenharmony_ci PCI_DEVICE_SUB(MPI3_MFGPAGE_VENDORID_BROADCOM, 543662306a36Sopenharmony_ci MPI3_MFGPAGE_DEVID_SAS5116_MPI_MGMT, PCI_ANY_ID, PCI_ANY_ID) 543762306a36Sopenharmony_ci }, 543862306a36Sopenharmony_ci { 0 } 543962306a36Sopenharmony_ci}; 544062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mpi3mr_pci_id_table); 544162306a36Sopenharmony_ci 544262306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(mpi3mr_pm_ops, mpi3mr_suspend, mpi3mr_resume); 544362306a36Sopenharmony_ci 544462306a36Sopenharmony_cistatic struct pci_driver mpi3mr_pci_driver = { 544562306a36Sopenharmony_ci .name = MPI3MR_DRIVER_NAME, 544662306a36Sopenharmony_ci .id_table = mpi3mr_pci_id_table, 544762306a36Sopenharmony_ci .probe = mpi3mr_probe, 544862306a36Sopenharmony_ci .remove = mpi3mr_remove, 544962306a36Sopenharmony_ci .shutdown = mpi3mr_shutdown, 545062306a36Sopenharmony_ci .driver.pm = &mpi3mr_pm_ops, 545162306a36Sopenharmony_ci}; 545262306a36Sopenharmony_ci 545362306a36Sopenharmony_cistatic ssize_t event_counter_show(struct device_driver *dd, char *buf) 545462306a36Sopenharmony_ci{ 545562306a36Sopenharmony_ci return sprintf(buf, "%llu\n", atomic64_read(&event_counter)); 545662306a36Sopenharmony_ci} 545762306a36Sopenharmony_cistatic DRIVER_ATTR_RO(event_counter); 545862306a36Sopenharmony_ci 545962306a36Sopenharmony_cistatic int __init mpi3mr_init(void) 546062306a36Sopenharmony_ci{ 546162306a36Sopenharmony_ci int ret_val; 546262306a36Sopenharmony_ci 546362306a36Sopenharmony_ci pr_info("Loading %s version %s\n", MPI3MR_DRIVER_NAME, 546462306a36Sopenharmony_ci MPI3MR_DRIVER_VERSION); 546562306a36Sopenharmony_ci 546662306a36Sopenharmony_ci mpi3mr_transport_template = 546762306a36Sopenharmony_ci sas_attach_transport(&mpi3mr_transport_functions); 546862306a36Sopenharmony_ci if (!mpi3mr_transport_template) { 546962306a36Sopenharmony_ci pr_err("%s failed to load due to sas transport attach failure\n", 547062306a36Sopenharmony_ci MPI3MR_DRIVER_NAME); 547162306a36Sopenharmony_ci return -ENODEV; 547262306a36Sopenharmony_ci } 547362306a36Sopenharmony_ci 547462306a36Sopenharmony_ci ret_val = pci_register_driver(&mpi3mr_pci_driver); 547562306a36Sopenharmony_ci if (ret_val) { 547662306a36Sopenharmony_ci pr_err("%s failed to load due to pci register driver failure\n", 547762306a36Sopenharmony_ci MPI3MR_DRIVER_NAME); 547862306a36Sopenharmony_ci goto err_pci_reg_fail; 547962306a36Sopenharmony_ci } 548062306a36Sopenharmony_ci 548162306a36Sopenharmony_ci ret_val = driver_create_file(&mpi3mr_pci_driver.driver, 548262306a36Sopenharmony_ci &driver_attr_event_counter); 548362306a36Sopenharmony_ci if (ret_val) 548462306a36Sopenharmony_ci goto err_event_counter; 548562306a36Sopenharmony_ci 548662306a36Sopenharmony_ci return ret_val; 548762306a36Sopenharmony_ci 548862306a36Sopenharmony_cierr_event_counter: 548962306a36Sopenharmony_ci pci_unregister_driver(&mpi3mr_pci_driver); 549062306a36Sopenharmony_ci 549162306a36Sopenharmony_cierr_pci_reg_fail: 549262306a36Sopenharmony_ci sas_release_transport(mpi3mr_transport_template); 549362306a36Sopenharmony_ci return ret_val; 549462306a36Sopenharmony_ci} 549562306a36Sopenharmony_ci 549662306a36Sopenharmony_cistatic void __exit mpi3mr_exit(void) 549762306a36Sopenharmony_ci{ 549862306a36Sopenharmony_ci if (warn_non_secure_ctlr) 549962306a36Sopenharmony_ci pr_warn( 550062306a36Sopenharmony_ci "Unloading %s version %s while managing a non secure controller\n", 550162306a36Sopenharmony_ci MPI3MR_DRIVER_NAME, MPI3MR_DRIVER_VERSION); 550262306a36Sopenharmony_ci else 550362306a36Sopenharmony_ci pr_info("Unloading %s version %s\n", MPI3MR_DRIVER_NAME, 550462306a36Sopenharmony_ci MPI3MR_DRIVER_VERSION); 550562306a36Sopenharmony_ci 550662306a36Sopenharmony_ci driver_remove_file(&mpi3mr_pci_driver.driver, 550762306a36Sopenharmony_ci &driver_attr_event_counter); 550862306a36Sopenharmony_ci pci_unregister_driver(&mpi3mr_pci_driver); 550962306a36Sopenharmony_ci sas_release_transport(mpi3mr_transport_template); 551062306a36Sopenharmony_ci} 551162306a36Sopenharmony_ci 551262306a36Sopenharmony_cimodule_init(mpi3mr_init); 551362306a36Sopenharmony_cimodule_exit(mpi3mr_exit); 5514