162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * linux/drivers/message/fusion/mptspi.c 362306a36Sopenharmony_ci * For use with LSI PCI chip/adapter(s) 462306a36Sopenharmony_ci * running LSI Fusion MPT (Message Passing Technology) firmware. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (c) 1999-2008 LSI Corporation 762306a36Sopenharmony_ci * (mailto:DL-MPTFusionLinux@lsi.com) 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 1162306a36Sopenharmony_ci/* 1262306a36Sopenharmony_ci This program is free software; you can redistribute it and/or modify 1362306a36Sopenharmony_ci it under the terms of the GNU General Public License as published by 1462306a36Sopenharmony_ci the Free Software Foundation; version 2 of the License. 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci This program is distributed in the hope that it will be useful, 1762306a36Sopenharmony_ci but WITHOUT ANY WARRANTY; without even the implied warranty of 1862306a36Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1962306a36Sopenharmony_ci GNU General Public License for more details. 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci NO WARRANTY 2262306a36Sopenharmony_ci THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR 2362306a36Sopenharmony_ci CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT 2462306a36Sopenharmony_ci LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, 2562306a36Sopenharmony_ci MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is 2662306a36Sopenharmony_ci solely responsible for determining the appropriateness of using and 2762306a36Sopenharmony_ci distributing the Program and assumes all risks associated with its 2862306a36Sopenharmony_ci exercise of rights under this Agreement, including but not limited to 2962306a36Sopenharmony_ci the risks and costs of program errors, damage to or loss of data, 3062306a36Sopenharmony_ci programs or equipment, and unavailability or interruption of operations. 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci DISCLAIMER OF LIABILITY 3362306a36Sopenharmony_ci NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY 3462306a36Sopenharmony_ci DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3562306a36Sopenharmony_ci DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND 3662306a36Sopenharmony_ci ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 3762306a36Sopenharmony_ci TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 3862306a36Sopenharmony_ci USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED 3962306a36Sopenharmony_ci HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci You should have received a copy of the GNU General Public License 4262306a36Sopenharmony_ci along with this program; if not, write to the Free Software 4362306a36Sopenharmony_ci Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 4462306a36Sopenharmony_ci*/ 4562306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#include <linux/module.h> 4862306a36Sopenharmony_ci#include <linux/kernel.h> 4962306a36Sopenharmony_ci#include <linux/slab.h> 5062306a36Sopenharmony_ci#include <linux/init.h> 5162306a36Sopenharmony_ci#include <linux/errno.h> 5262306a36Sopenharmony_ci#include <linux/kdev_t.h> 5362306a36Sopenharmony_ci#include <linux/blkdev.h> 5462306a36Sopenharmony_ci#include <linux/delay.h> /* for mdelay */ 5562306a36Sopenharmony_ci#include <linux/interrupt.h> 5662306a36Sopenharmony_ci#include <linux/reboot.h> /* notifier code */ 5762306a36Sopenharmony_ci#include <linux/workqueue.h> 5862306a36Sopenharmony_ci#include <linux/raid_class.h> 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#include <scsi/scsi.h> 6162306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h> 6262306a36Sopenharmony_ci#include <scsi/scsi_device.h> 6362306a36Sopenharmony_ci#include <scsi/scsi_host.h> 6462306a36Sopenharmony_ci#include <scsi/scsi_tcq.h> 6562306a36Sopenharmony_ci#include <scsi/scsi_transport.h> 6662306a36Sopenharmony_ci#include <scsi/scsi_transport_spi.h> 6762306a36Sopenharmony_ci#include <scsi/scsi_dbg.h> 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci#include "mptbase.h" 7062306a36Sopenharmony_ci#include "mptscsih.h" 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 7362306a36Sopenharmony_ci#define my_NAME "Fusion MPT SPI Host driver" 7462306a36Sopenharmony_ci#define my_VERSION MPT_LINUX_VERSION_COMMON 7562306a36Sopenharmony_ci#define MYNAM "mptspi" 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ciMODULE_AUTHOR(MODULEAUTHOR); 7862306a36Sopenharmony_ciMODULE_DESCRIPTION(my_NAME); 7962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 8062306a36Sopenharmony_ciMODULE_VERSION(my_VERSION); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* Command line args */ 8362306a36Sopenharmony_cistatic int mpt_saf_te = MPTSCSIH_SAF_TE; 8462306a36Sopenharmony_cimodule_param(mpt_saf_te, int, 0); 8562306a36Sopenharmony_ciMODULE_PARM_DESC(mpt_saf_te, " Force enabling SEP Processor: enable=1 (default=MPTSCSIH_SAF_TE=0)"); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic void mptspi_write_offset(struct scsi_target *, int); 8862306a36Sopenharmony_cistatic void mptspi_write_width(struct scsi_target *, int); 8962306a36Sopenharmony_cistatic int mptspi_write_spi_device_pg1(struct scsi_target *, 9062306a36Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_1 *); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic struct scsi_transport_template *mptspi_transport_template = NULL; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic u8 mptspiDoneCtx = MPT_MAX_PROTOCOL_DRIVERS; 9562306a36Sopenharmony_cistatic u8 mptspiTaskCtx = MPT_MAX_PROTOCOL_DRIVERS; 9662306a36Sopenharmony_cistatic u8 mptspiInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */ 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci/** 9962306a36Sopenharmony_ci * mptspi_setTargetNegoParms - Update the target negotiation parameters 10062306a36Sopenharmony_ci * @hd: Pointer to a SCSI Host Structure 10162306a36Sopenharmony_ci * @target: per target private data 10262306a36Sopenharmony_ci * @sdev: SCSI device 10362306a36Sopenharmony_ci * 10462306a36Sopenharmony_ci * Update the target negotiation parameters based on the Inquiry 10562306a36Sopenharmony_ci * data, adapter capabilities, and NVRAM settings. 10662306a36Sopenharmony_ci **/ 10762306a36Sopenharmony_cistatic void 10862306a36Sopenharmony_cimptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target, 10962306a36Sopenharmony_ci struct scsi_device *sdev) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci MPT_ADAPTER *ioc = hd->ioc; 11262306a36Sopenharmony_ci SpiCfgData *pspi_data = &ioc->spi_data; 11362306a36Sopenharmony_ci int id = (int) target->id; 11462306a36Sopenharmony_ci int nvram; 11562306a36Sopenharmony_ci u8 width = MPT_NARROW; 11662306a36Sopenharmony_ci u8 factor = MPT_ASYNC; 11762306a36Sopenharmony_ci u8 offset = 0; 11862306a36Sopenharmony_ci u8 nfactor; 11962306a36Sopenharmony_ci u8 noQas = 1; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci target->negoFlags = pspi_data->noQas; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (sdev->scsi_level < SCSI_2) { 12462306a36Sopenharmony_ci width = 0; 12562306a36Sopenharmony_ci factor = MPT_ULTRA2; 12662306a36Sopenharmony_ci offset = pspi_data->maxSyncOffset; 12762306a36Sopenharmony_ci target->tflags &= ~MPT_TARGET_FLAGS_Q_YES; 12862306a36Sopenharmony_ci } else { 12962306a36Sopenharmony_ci if (scsi_device_wide(sdev)) 13062306a36Sopenharmony_ci width = 1; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (scsi_device_sync(sdev)) { 13362306a36Sopenharmony_ci factor = pspi_data->minSyncFactor; 13462306a36Sopenharmony_ci if (!scsi_device_dt(sdev)) 13562306a36Sopenharmony_ci factor = MPT_ULTRA2; 13662306a36Sopenharmony_ci else { 13762306a36Sopenharmony_ci if (!scsi_device_ius(sdev) && 13862306a36Sopenharmony_ci !scsi_device_qas(sdev)) 13962306a36Sopenharmony_ci factor = MPT_ULTRA160; 14062306a36Sopenharmony_ci else { 14162306a36Sopenharmony_ci factor = MPT_ULTRA320; 14262306a36Sopenharmony_ci if (scsi_device_qas(sdev)) { 14362306a36Sopenharmony_ci ddvprintk(ioc, 14462306a36Sopenharmony_ci printk(MYIOC_s_DEBUG_FMT "Enabling QAS due to " 14562306a36Sopenharmony_ci "byte56=%02x on id=%d!\n", ioc->name, 14662306a36Sopenharmony_ci scsi_device_qas(sdev), id)); 14762306a36Sopenharmony_ci noQas = 0; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci if (sdev->type == TYPE_TAPE && 15062306a36Sopenharmony_ci scsi_device_ius(sdev)) 15162306a36Sopenharmony_ci target->negoFlags |= MPT_TAPE_NEGO_IDP; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci offset = pspi_data->maxSyncOffset; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci /* If RAID, never disable QAS 15762306a36Sopenharmony_ci * else if non RAID, do not disable 15862306a36Sopenharmony_ci * QAS if bit 1 is set 15962306a36Sopenharmony_ci * bit 1 QAS support, non-raid only 16062306a36Sopenharmony_ci * bit 0 IU support 16162306a36Sopenharmony_ci */ 16262306a36Sopenharmony_ci if (target->raidVolume == 1) 16362306a36Sopenharmony_ci noQas = 0; 16462306a36Sopenharmony_ci } else { 16562306a36Sopenharmony_ci factor = MPT_ASYNC; 16662306a36Sopenharmony_ci offset = 0; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (!sdev->tagged_supported) 17162306a36Sopenharmony_ci target->tflags &= ~MPT_TARGET_FLAGS_Q_YES; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci /* Update tflags based on NVRAM settings. (SCSI only) 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_ci if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) { 17662306a36Sopenharmony_ci nvram = pspi_data->nvram[id]; 17762306a36Sopenharmony_ci nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci if (width) 18062306a36Sopenharmony_ci width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (offset > 0) { 18362306a36Sopenharmony_ci /* Ensure factor is set to the 18462306a36Sopenharmony_ci * maximum of: adapter, nvram, inquiry 18562306a36Sopenharmony_ci */ 18662306a36Sopenharmony_ci if (nfactor) { 18762306a36Sopenharmony_ci if (nfactor < pspi_data->minSyncFactor ) 18862306a36Sopenharmony_ci nfactor = pspi_data->minSyncFactor; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci factor = max(factor, nfactor); 19162306a36Sopenharmony_ci if (factor == MPT_ASYNC) 19262306a36Sopenharmony_ci offset = 0; 19362306a36Sopenharmony_ci } else { 19462306a36Sopenharmony_ci offset = 0; 19562306a36Sopenharmony_ci factor = MPT_ASYNC; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci } else { 19862306a36Sopenharmony_ci factor = MPT_ASYNC; 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci /* Make sure data is consistent 20362306a36Sopenharmony_ci */ 20462306a36Sopenharmony_ci if ((!width) && (factor < MPT_ULTRA2)) 20562306a36Sopenharmony_ci factor = MPT_ULTRA2; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci /* Save the data to the target structure. 20862306a36Sopenharmony_ci */ 20962306a36Sopenharmony_ci target->minSyncFactor = factor; 21062306a36Sopenharmony_ci target->maxOffset = offset; 21162306a36Sopenharmony_ci target->maxWidth = width; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci spi_min_period(scsi_target(sdev)) = factor; 21462306a36Sopenharmony_ci spi_max_offset(scsi_target(sdev)) = offset; 21562306a36Sopenharmony_ci spi_max_width(scsi_target(sdev)) = width; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci /* Disable unused features. 22062306a36Sopenharmony_ci */ 22162306a36Sopenharmony_ci if (!width) 22262306a36Sopenharmony_ci target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci if (!offset) 22562306a36Sopenharmony_ci target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci if ( factor > MPT_ULTRA320 ) 22862306a36Sopenharmony_ci noQas = 0; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci if (noQas && (pspi_data->noQas == 0)) { 23162306a36Sopenharmony_ci pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS; 23262306a36Sopenharmony_ci target->negoFlags |= MPT_TARGET_NO_NEGO_QAS; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci /* Disable QAS in a mixed configuration case 23562306a36Sopenharmony_ci */ 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT 23862306a36Sopenharmony_ci "Disabling QAS due to noQas=%02x on id=%d!\n", ioc->name, noQas, id)); 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci/** 24362306a36Sopenharmony_ci * mptspi_writeIOCPage4 - write IOC Page 4 24462306a36Sopenharmony_ci * @hd: Pointer to a SCSI Host Structure 24562306a36Sopenharmony_ci * @channel: channel number 24662306a36Sopenharmony_ci * @id: write IOC Page4 for this ID & Bus 24762306a36Sopenharmony_ci * 24862306a36Sopenharmony_ci * Return: -EAGAIN if unable to obtain a Message Frame 24962306a36Sopenharmony_ci * or 0 if success. 25062306a36Sopenharmony_ci * 25162306a36Sopenharmony_ci * Remark: We do not wait for a return, write pages sequentially. 25262306a36Sopenharmony_ci **/ 25362306a36Sopenharmony_cistatic int 25462306a36Sopenharmony_cimptspi_writeIOCPage4(MPT_SCSI_HOST *hd, u8 channel , u8 id) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci MPT_ADAPTER *ioc = hd->ioc; 25762306a36Sopenharmony_ci Config_t *pReq; 25862306a36Sopenharmony_ci IOCPage4_t *IOCPage4Ptr; 25962306a36Sopenharmony_ci MPT_FRAME_HDR *mf; 26062306a36Sopenharmony_ci dma_addr_t dataDma; 26162306a36Sopenharmony_ci u32 flagsLength; 26262306a36Sopenharmony_ci int ii; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci /* Get a MF for this command. 26562306a36Sopenharmony_ci */ 26662306a36Sopenharmony_ci if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) { 26762306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_WARN_FMT 26862306a36Sopenharmony_ci "writeIOCPage4 : no msg frames!\n",ioc->name)); 26962306a36Sopenharmony_ci return -EAGAIN; 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* Set the request and the data pointers. 27362306a36Sopenharmony_ci * Place data at end of MF. 27462306a36Sopenharmony_ci */ 27562306a36Sopenharmony_ci pReq = (Config_t *)mf; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci /* Complete the request frame (same for all requests). 27862306a36Sopenharmony_ci */ 27962306a36Sopenharmony_ci pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; 28062306a36Sopenharmony_ci pReq->Reserved = 0; 28162306a36Sopenharmony_ci pReq->ChainOffset = 0; 28262306a36Sopenharmony_ci pReq->Function = MPI_FUNCTION_CONFIG; 28362306a36Sopenharmony_ci pReq->ExtPageLength = 0; 28462306a36Sopenharmony_ci pReq->ExtPageType = 0; 28562306a36Sopenharmony_ci pReq->MsgFlags = 0; 28662306a36Sopenharmony_ci for (ii=0; ii < 8; ii++) { 28762306a36Sopenharmony_ci pReq->Reserved2[ii] = 0; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci IOCPage4Ptr = ioc->spi_data.pIocPg4; 29162306a36Sopenharmony_ci dataDma = ioc->spi_data.IocPg4_dma; 29262306a36Sopenharmony_ci ii = IOCPage4Ptr->ActiveSEP++; 29362306a36Sopenharmony_ci IOCPage4Ptr->SEP[ii].SEPTargetID = id; 29462306a36Sopenharmony_ci IOCPage4Ptr->SEP[ii].SEPBus = channel; 29562306a36Sopenharmony_ci pReq->Header = IOCPage4Ptr->Header; 29662306a36Sopenharmony_ci pReq->PageAddress = cpu_to_le32(id | (channel << 8 )); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci /* Add a SGE to the config request. 29962306a36Sopenharmony_ci */ 30062306a36Sopenharmony_ci flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE | 30162306a36Sopenharmony_ci (IOCPage4Ptr->Header.PageLength + ii) * 4; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT 30662306a36Sopenharmony_ci "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n", 30762306a36Sopenharmony_ci ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel)); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci mpt_put_msg_frame(ioc->DoneCtx, ioc, mf); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci return 0; 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci/** 31562306a36Sopenharmony_ci * mptspi_initTarget - Target, LUN alloc/free functionality. 31662306a36Sopenharmony_ci * @hd: Pointer to MPT_SCSI_HOST structure 31762306a36Sopenharmony_ci * @vtarget: per target private data 31862306a36Sopenharmony_ci * @sdev: SCSI device 31962306a36Sopenharmony_ci * 32062306a36Sopenharmony_ci * NOTE: It's only SAFE to call this routine if data points to 32162306a36Sopenharmony_ci * sane & valid STANDARD INQUIRY data! 32262306a36Sopenharmony_ci * 32362306a36Sopenharmony_ci * Allocate and initialize memory for this target. 32462306a36Sopenharmony_ci * Save inquiry data. 32562306a36Sopenharmony_ci * 32662306a36Sopenharmony_ci **/ 32762306a36Sopenharmony_cistatic void 32862306a36Sopenharmony_cimptspi_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget, 32962306a36Sopenharmony_ci struct scsi_device *sdev) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* Is LUN supported? If so, upper 2 bits will be 0 33362306a36Sopenharmony_ci * in first byte of inquiry data. 33462306a36Sopenharmony_ci */ 33562306a36Sopenharmony_ci if (sdev->inq_periph_qual != 0) 33662306a36Sopenharmony_ci return; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci if (vtarget == NULL) 33962306a36Sopenharmony_ci return; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci vtarget->type = sdev->type; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if ((sdev->type == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) { 34462306a36Sopenharmony_ci /* Treat all Processors as SAF-TE if 34562306a36Sopenharmony_ci * command line option is set */ 34662306a36Sopenharmony_ci vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED; 34762306a36Sopenharmony_ci mptspi_writeIOCPage4(hd, vtarget->channel, vtarget->id); 34862306a36Sopenharmony_ci }else if ((sdev->type == TYPE_PROCESSOR) && 34962306a36Sopenharmony_ci !(vtarget->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) { 35062306a36Sopenharmony_ci if (sdev->inquiry_len > 49 ) { 35162306a36Sopenharmony_ci if (sdev->inquiry[44] == 'S' && 35262306a36Sopenharmony_ci sdev->inquiry[45] == 'A' && 35362306a36Sopenharmony_ci sdev->inquiry[46] == 'F' && 35462306a36Sopenharmony_ci sdev->inquiry[47] == '-' && 35562306a36Sopenharmony_ci sdev->inquiry[48] == 'T' && 35662306a36Sopenharmony_ci sdev->inquiry[49] == 'E' ) { 35762306a36Sopenharmony_ci vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED; 35862306a36Sopenharmony_ci mptspi_writeIOCPage4(hd, vtarget->channel, vtarget->id); 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci mptspi_setTargetNegoParms(hd, vtarget, sdev); 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci/** 36662306a36Sopenharmony_ci * mptspi_is_raid - Determines whether target is belonging to volume 36762306a36Sopenharmony_ci * @hd: Pointer to a SCSI HOST structure 36862306a36Sopenharmony_ci * @id: target device id 36962306a36Sopenharmony_ci * 37062306a36Sopenharmony_ci * Return: 37162306a36Sopenharmony_ci * non-zero = true 37262306a36Sopenharmony_ci * zero = false 37362306a36Sopenharmony_ci * 37462306a36Sopenharmony_ci */ 37562306a36Sopenharmony_cistatic int 37662306a36Sopenharmony_cimptspi_is_raid(struct _MPT_SCSI_HOST *hd, u32 id) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci int i, rc = 0; 37962306a36Sopenharmony_ci MPT_ADAPTER *ioc = hd->ioc; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci if (!ioc->raid_data.pIocPg2) 38262306a36Sopenharmony_ci goto out; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (!ioc->raid_data.pIocPg2->NumActiveVolumes) 38562306a36Sopenharmony_ci goto out; 38662306a36Sopenharmony_ci for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { 38762306a36Sopenharmony_ci if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) { 38862306a36Sopenharmony_ci rc = 1; 38962306a36Sopenharmony_ci goto out; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci out: 39462306a36Sopenharmony_ci return rc; 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_cistatic int mptspi_target_alloc(struct scsi_target *starget) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci struct Scsi_Host *shost = dev_to_shost(&starget->dev); 40062306a36Sopenharmony_ci struct _MPT_SCSI_HOST *hd = shost_priv(shost); 40162306a36Sopenharmony_ci VirtTarget *vtarget; 40262306a36Sopenharmony_ci MPT_ADAPTER *ioc; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (hd == NULL) 40562306a36Sopenharmony_ci return -ENODEV; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci ioc = hd->ioc; 40862306a36Sopenharmony_ci vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL); 40962306a36Sopenharmony_ci if (!vtarget) 41062306a36Sopenharmony_ci return -ENOMEM; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci vtarget->ioc_id = ioc->id; 41362306a36Sopenharmony_ci vtarget->tflags = MPT_TARGET_FLAGS_Q_YES; 41462306a36Sopenharmony_ci vtarget->id = (u8)starget->id; 41562306a36Sopenharmony_ci vtarget->channel = (u8)starget->channel; 41662306a36Sopenharmony_ci vtarget->starget = starget; 41762306a36Sopenharmony_ci starget->hostdata = vtarget; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (starget->channel == 1) { 42062306a36Sopenharmony_ci if (mptscsih_is_phys_disk(ioc, 0, starget->id) == 0) 42162306a36Sopenharmony_ci return 0; 42262306a36Sopenharmony_ci vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; 42362306a36Sopenharmony_ci /* The real channel for this device is zero */ 42462306a36Sopenharmony_ci vtarget->channel = 0; 42562306a36Sopenharmony_ci /* The actual physdisknum (for RAID passthrough) */ 42662306a36Sopenharmony_ci vtarget->id = mptscsih_raid_id_to_num(ioc, 0, 42762306a36Sopenharmony_ci starget->id); 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci if (starget->channel == 0 && 43162306a36Sopenharmony_ci mptspi_is_raid(hd, starget->id)) { 43262306a36Sopenharmony_ci vtarget->raidVolume = 1; 43362306a36Sopenharmony_ci ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT 43462306a36Sopenharmony_ci "RAID Volume @ channel=%d id=%d\n", ioc->name, starget->channel, 43562306a36Sopenharmony_ci starget->id)); 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci if (ioc->spi_data.nvram && 43962306a36Sopenharmony_ci ioc->spi_data.nvram[starget->id] != MPT_HOST_NVRAM_INVALID) { 44062306a36Sopenharmony_ci u32 nvram = ioc->spi_data.nvram[starget->id]; 44162306a36Sopenharmony_ci spi_min_period(starget) = (nvram & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT; 44262306a36Sopenharmony_ci spi_max_width(starget) = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1; 44362306a36Sopenharmony_ci } else { 44462306a36Sopenharmony_ci spi_min_period(starget) = ioc->spi_data.minSyncFactor; 44562306a36Sopenharmony_ci spi_max_width(starget) = ioc->spi_data.maxBusWidth; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci spi_max_offset(starget) = ioc->spi_data.maxSyncOffset; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci spi_offset(starget) = 0; 45062306a36Sopenharmony_ci spi_period(starget) = 0xFF; 45162306a36Sopenharmony_ci mptspi_write_width(starget, 0); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci return 0; 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic void 45762306a36Sopenharmony_cimptspi_target_destroy(struct scsi_target *starget) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci kfree(starget->hostdata); 46062306a36Sopenharmony_ci starget->hostdata = NULL; 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci/** 46462306a36Sopenharmony_ci * mptspi_print_write_nego - negotiation parameters debug info that is being sent 46562306a36Sopenharmony_ci * @hd: Pointer to a SCSI HOST structure 46662306a36Sopenharmony_ci * @starget: SCSI target 46762306a36Sopenharmony_ci * @ii: negotiation parameters 46862306a36Sopenharmony_ci * 46962306a36Sopenharmony_ci */ 47062306a36Sopenharmony_cistatic void 47162306a36Sopenharmony_cimptspi_print_write_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u32 ii) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d Requested = 0x%08x" 47462306a36Sopenharmony_ci " ( %s factor = 0x%02x @ offset = 0x%02x %s%s%s%s%s%s%s%s)\n", 47562306a36Sopenharmony_ci hd->ioc->name, starget->id, ii, 47662306a36Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_WIDE ? "Wide ": "", 47762306a36Sopenharmony_ci ((ii >> 8) & 0xFF), ((ii >> 16) & 0xFF), 47862306a36Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_IU ? "IU ": "", 47962306a36Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_DT ? "DT ": "", 48062306a36Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_QAS ? "QAS ": "", 48162306a36Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_HOLD_MCS ? "HOLDMCS ": "", 48262306a36Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_WR_FLOW ? "WRFLOW ": "", 48362306a36Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_RD_STRM ? "RDSTRM ": "", 48462306a36Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_RTI ? "RTI ": "", 48562306a36Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": "")); 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci/** 48962306a36Sopenharmony_ci * mptspi_print_read_nego - negotiation parameters debug info that is being read 49062306a36Sopenharmony_ci * @hd: Pointer to a SCSI HOST structure 49162306a36Sopenharmony_ci * @starget: SCSI target 49262306a36Sopenharmony_ci * @ii: negotiation parameters 49362306a36Sopenharmony_ci * 49462306a36Sopenharmony_ci */ 49562306a36Sopenharmony_cistatic void 49662306a36Sopenharmony_cimptspi_print_read_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u32 ii) 49762306a36Sopenharmony_ci{ 49862306a36Sopenharmony_ci ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d Read = 0x%08x" 49962306a36Sopenharmony_ci " ( %s factor = 0x%02x @ offset = 0x%02x %s%s%s%s%s%s%s%s)\n", 50062306a36Sopenharmony_ci hd->ioc->name, starget->id, ii, 50162306a36Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_WIDE ? "Wide ": "", 50262306a36Sopenharmony_ci ((ii >> 8) & 0xFF), ((ii >> 16) & 0xFF), 50362306a36Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_IU ? "IU ": "", 50462306a36Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_DT ? "DT ": "", 50562306a36Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_QAS ? "QAS ": "", 50662306a36Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_HOLD_MCS ? "HOLDMCS ": "", 50762306a36Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_WR_FLOW ? "WRFLOW ": "", 50862306a36Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_RD_STRM ? "RDSTRM ": "", 50962306a36Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_RTI ? "RTI ": "", 51062306a36Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": "")); 51162306a36Sopenharmony_ci} 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_cistatic int mptspi_read_spi_device_pg0(struct scsi_target *starget, 51462306a36Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_0 *pass_pg0) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci struct Scsi_Host *shost = dev_to_shost(&starget->dev); 51762306a36Sopenharmony_ci struct _MPT_SCSI_HOST *hd = shost_priv(shost); 51862306a36Sopenharmony_ci struct _MPT_ADAPTER *ioc = hd->ioc; 51962306a36Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_0 *spi_dev_pg0; 52062306a36Sopenharmony_ci dma_addr_t spi_dev_pg0_dma; 52162306a36Sopenharmony_ci int size; 52262306a36Sopenharmony_ci struct _x_config_parms cfg; 52362306a36Sopenharmony_ci struct _CONFIG_PAGE_HEADER hdr; 52462306a36Sopenharmony_ci int err = -EBUSY; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci /* No SPI parameters for RAID devices */ 52762306a36Sopenharmony_ci if (starget->channel == 0 && 52862306a36Sopenharmony_ci mptspi_is_raid(hd, starget->id)) 52962306a36Sopenharmony_ci return -1; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci size = ioc->spi_data.sdp0length * 4; 53262306a36Sopenharmony_ci /* 53362306a36Sopenharmony_ci if (ioc->spi_data.sdp0length & 1) 53462306a36Sopenharmony_ci size += size + 4; 53562306a36Sopenharmony_ci size += 2048; 53662306a36Sopenharmony_ci */ 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci spi_dev_pg0 = dma_alloc_coherent(&ioc->pcidev->dev, size, &spi_dev_pg0_dma, GFP_KERNEL); 53962306a36Sopenharmony_ci if (spi_dev_pg0 == NULL) { 54062306a36Sopenharmony_ci starget_printk(KERN_ERR, starget, MYIOC_s_FMT 54162306a36Sopenharmony_ci "dma_alloc_coherent for parameters failed\n", ioc->name); 54262306a36Sopenharmony_ci return -EINVAL; 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci memset(&hdr, 0, sizeof(hdr)); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci hdr.PageVersion = ioc->spi_data.sdp0version; 54862306a36Sopenharmony_ci hdr.PageLength = ioc->spi_data.sdp0length; 54962306a36Sopenharmony_ci hdr.PageNumber = 0; 55062306a36Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci memset(&cfg, 0, sizeof(cfg)); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci cfg.cfghdr.hdr = &hdr; 55562306a36Sopenharmony_ci cfg.physAddr = spi_dev_pg0_dma; 55662306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 55762306a36Sopenharmony_ci cfg.dir = 0; 55862306a36Sopenharmony_ci cfg.pageAddr = starget->id; 55962306a36Sopenharmony_ci cfg.timeout = 60; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci if (mpt_config(ioc, &cfg)) { 56262306a36Sopenharmony_ci starget_printk(KERN_ERR, starget, MYIOC_s_FMT "mpt_config failed\n", ioc->name); 56362306a36Sopenharmony_ci goto out_free; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci err = 0; 56662306a36Sopenharmony_ci memcpy(pass_pg0, spi_dev_pg0, size); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci mptspi_print_read_nego(hd, starget, le32_to_cpu(spi_dev_pg0->NegotiatedParameters)); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci out_free: 57162306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, size, spi_dev_pg0, spi_dev_pg0_dma); 57262306a36Sopenharmony_ci return err; 57362306a36Sopenharmony_ci} 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_cistatic u32 mptspi_getRP(struct scsi_target *starget) 57662306a36Sopenharmony_ci{ 57762306a36Sopenharmony_ci u32 nego = 0; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci nego |= spi_iu(starget) ? MPI_SCSIDEVPAGE1_RP_IU : 0; 58062306a36Sopenharmony_ci nego |= spi_dt(starget) ? MPI_SCSIDEVPAGE1_RP_DT : 0; 58162306a36Sopenharmony_ci nego |= spi_qas(starget) ? MPI_SCSIDEVPAGE1_RP_QAS : 0; 58262306a36Sopenharmony_ci nego |= spi_hold_mcs(starget) ? MPI_SCSIDEVPAGE1_RP_HOLD_MCS : 0; 58362306a36Sopenharmony_ci nego |= spi_wr_flow(starget) ? MPI_SCSIDEVPAGE1_RP_WR_FLOW : 0; 58462306a36Sopenharmony_ci nego |= spi_rd_strm(starget) ? MPI_SCSIDEVPAGE1_RP_RD_STRM : 0; 58562306a36Sopenharmony_ci nego |= spi_rti(starget) ? MPI_SCSIDEVPAGE1_RP_RTI : 0; 58662306a36Sopenharmony_ci nego |= spi_pcomp_en(starget) ? MPI_SCSIDEVPAGE1_RP_PCOMP_EN : 0; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci nego |= (spi_period(starget) << MPI_SCSIDEVPAGE1_RP_SHIFT_MIN_SYNC_PERIOD) & MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK; 58962306a36Sopenharmony_ci nego |= (spi_offset(starget) << MPI_SCSIDEVPAGE1_RP_SHIFT_MAX_SYNC_OFFSET) & MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK; 59062306a36Sopenharmony_ci nego |= spi_width(starget) ? MPI_SCSIDEVPAGE1_RP_WIDE : 0; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci return nego; 59362306a36Sopenharmony_ci} 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_cistatic void mptspi_read_parameters(struct scsi_target *starget) 59662306a36Sopenharmony_ci{ 59762306a36Sopenharmony_ci int nego; 59862306a36Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_0 spi_dev_pg0; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci mptspi_read_spi_device_pg0(starget, &spi_dev_pg0); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci nego = le32_to_cpu(spi_dev_pg0.NegotiatedParameters); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci spi_iu(starget) = (nego & MPI_SCSIDEVPAGE0_NP_IU) ? 1 : 0; 60562306a36Sopenharmony_ci spi_dt(starget) = (nego & MPI_SCSIDEVPAGE0_NP_DT) ? 1 : 0; 60662306a36Sopenharmony_ci spi_qas(starget) = (nego & MPI_SCSIDEVPAGE0_NP_QAS) ? 1 : 0; 60762306a36Sopenharmony_ci spi_wr_flow(starget) = (nego & MPI_SCSIDEVPAGE0_NP_WR_FLOW) ? 1 : 0; 60862306a36Sopenharmony_ci spi_rd_strm(starget) = (nego & MPI_SCSIDEVPAGE0_NP_RD_STRM) ? 1 : 0; 60962306a36Sopenharmony_ci spi_rti(starget) = (nego & MPI_SCSIDEVPAGE0_NP_RTI) ? 1 : 0; 61062306a36Sopenharmony_ci spi_pcomp_en(starget) = (nego & MPI_SCSIDEVPAGE0_NP_PCOMP_EN) ? 1 : 0; 61162306a36Sopenharmony_ci spi_hold_mcs(starget) = (nego & MPI_SCSIDEVPAGE0_NP_HOLD_MCS) ? 1 : 0; 61262306a36Sopenharmony_ci spi_period(starget) = (nego & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> MPI_SCSIDEVPAGE0_NP_SHIFT_SYNC_PERIOD; 61362306a36Sopenharmony_ci spi_offset(starget) = (nego & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) >> MPI_SCSIDEVPAGE0_NP_SHIFT_SYNC_OFFSET; 61462306a36Sopenharmony_ci spi_width(starget) = (nego & MPI_SCSIDEVPAGE0_NP_WIDE) ? 1 : 0; 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_cistatic int 61862306a36Sopenharmony_cimptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id) 61962306a36Sopenharmony_ci{ 62062306a36Sopenharmony_ci MPT_ADAPTER *ioc = hd->ioc; 62162306a36Sopenharmony_ci MpiRaidActionRequest_t *pReq; 62262306a36Sopenharmony_ci MPT_FRAME_HDR *mf; 62362306a36Sopenharmony_ci int ret; 62462306a36Sopenharmony_ci unsigned long timeleft; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci mutex_lock(&ioc->internal_cmds.mutex); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci /* Get and Populate a free Frame 62962306a36Sopenharmony_ci */ 63062306a36Sopenharmony_ci if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) { 63162306a36Sopenharmony_ci dfailprintk(hd->ioc, printk(MYIOC_s_WARN_FMT 63262306a36Sopenharmony_ci "%s: no msg frames!\n", ioc->name, __func__)); 63362306a36Sopenharmony_ci ret = -EAGAIN; 63462306a36Sopenharmony_ci goto out; 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci pReq = (MpiRaidActionRequest_t *)mf; 63762306a36Sopenharmony_ci if (quiesce) 63862306a36Sopenharmony_ci pReq->Action = MPI_RAID_ACTION_QUIESCE_PHYS_IO; 63962306a36Sopenharmony_ci else 64062306a36Sopenharmony_ci pReq->Action = MPI_RAID_ACTION_ENABLE_PHYS_IO; 64162306a36Sopenharmony_ci pReq->Reserved1 = 0; 64262306a36Sopenharmony_ci pReq->ChainOffset = 0; 64362306a36Sopenharmony_ci pReq->Function = MPI_FUNCTION_RAID_ACTION; 64462306a36Sopenharmony_ci pReq->VolumeID = id; 64562306a36Sopenharmony_ci pReq->VolumeBus = channel; 64662306a36Sopenharmony_ci pReq->PhysDiskNum = 0; 64762306a36Sopenharmony_ci pReq->MsgFlags = 0; 64862306a36Sopenharmony_ci pReq->Reserved2 = 0; 64962306a36Sopenharmony_ci pReq->ActionDataWord = 0; /* Reserved for this action */ 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci ioc->add_sge((char *)&pReq->ActionDataSGE, 65262306a36Sopenharmony_ci MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n", 65562306a36Sopenharmony_ci ioc->name, pReq->Action, channel, id)); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status) 65862306a36Sopenharmony_ci mpt_put_msg_frame(ioc->InternalCtx, ioc, mf); 65962306a36Sopenharmony_ci timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done, 10*HZ); 66062306a36Sopenharmony_ci if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { 66162306a36Sopenharmony_ci ret = -ETIME; 66262306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: TIMED OUT!\n", 66362306a36Sopenharmony_ci ioc->name, __func__)); 66462306a36Sopenharmony_ci if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) 66562306a36Sopenharmony_ci goto out; 66662306a36Sopenharmony_ci if (!timeleft) { 66762306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", 66862306a36Sopenharmony_ci ioc->name, __func__); 66962306a36Sopenharmony_ci mpt_HardResetHandler(ioc, CAN_SLEEP); 67062306a36Sopenharmony_ci mpt_free_msg_frame(ioc, mf); 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci goto out; 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci ret = ioc->internal_cmds.completion_code; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci out: 67862306a36Sopenharmony_ci CLEAR_MGMT_STATUS(ioc->internal_cmds.status) 67962306a36Sopenharmony_ci mutex_unlock(&ioc->internal_cmds.mutex); 68062306a36Sopenharmony_ci return ret; 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_cistatic void mptspi_dv_device(struct _MPT_SCSI_HOST *hd, 68462306a36Sopenharmony_ci struct scsi_device *sdev) 68562306a36Sopenharmony_ci{ 68662306a36Sopenharmony_ci VirtTarget *vtarget = scsi_target(sdev)->hostdata; 68762306a36Sopenharmony_ci MPT_ADAPTER *ioc = hd->ioc; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci /* no DV on RAID devices */ 69062306a36Sopenharmony_ci if (sdev->channel == 0 && 69162306a36Sopenharmony_ci mptspi_is_raid(hd, sdev->id)) 69262306a36Sopenharmony_ci return; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci /* If this is a piece of a RAID, then quiesce first */ 69562306a36Sopenharmony_ci if (sdev->channel == 1 && 69662306a36Sopenharmony_ci mptscsih_quiesce_raid(hd, 1, vtarget->channel, vtarget->id) < 0) { 69762306a36Sopenharmony_ci starget_printk(KERN_ERR, scsi_target(sdev), MYIOC_s_FMT 69862306a36Sopenharmony_ci "Integrated RAID quiesce failed\n", ioc->name); 69962306a36Sopenharmony_ci return; 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci hd->spi_pending |= (1 << sdev->id); 70362306a36Sopenharmony_ci spi_dv_device(sdev); 70462306a36Sopenharmony_ci hd->spi_pending &= ~(1 << sdev->id); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci if (sdev->channel == 1 && 70762306a36Sopenharmony_ci mptscsih_quiesce_raid(hd, 0, vtarget->channel, vtarget->id) < 0) 70862306a36Sopenharmony_ci starget_printk(KERN_ERR, scsi_target(sdev), MYIOC_s_FMT 70962306a36Sopenharmony_ci "Integrated RAID resume failed\n", ioc->name); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci mptspi_read_parameters(sdev->sdev_target); 71262306a36Sopenharmony_ci spi_display_xfer_agreement(sdev->sdev_target); 71362306a36Sopenharmony_ci mptspi_read_parameters(sdev->sdev_target); 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_cistatic int mptspi_slave_alloc(struct scsi_device *sdev) 71762306a36Sopenharmony_ci{ 71862306a36Sopenharmony_ci MPT_SCSI_HOST *hd = shost_priv(sdev->host); 71962306a36Sopenharmony_ci VirtTarget *vtarget; 72062306a36Sopenharmony_ci VirtDevice *vdevice; 72162306a36Sopenharmony_ci struct scsi_target *starget; 72262306a36Sopenharmony_ci MPT_ADAPTER *ioc = hd->ioc; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci if (sdev->channel == 1 && 72562306a36Sopenharmony_ci mptscsih_is_phys_disk(ioc, 0, sdev->id) == 0) 72662306a36Sopenharmony_ci return -ENXIO; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL); 72962306a36Sopenharmony_ci if (!vdevice) { 73062306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", 73162306a36Sopenharmony_ci ioc->name, sizeof(VirtDevice)); 73262306a36Sopenharmony_ci return -ENOMEM; 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci vdevice->lun = sdev->lun; 73662306a36Sopenharmony_ci sdev->hostdata = vdevice; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci starget = scsi_target(sdev); 73962306a36Sopenharmony_ci vtarget = starget->hostdata; 74062306a36Sopenharmony_ci vdevice->vtarget = vtarget; 74162306a36Sopenharmony_ci vtarget->num_luns++; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci if (sdev->channel == 1) 74462306a36Sopenharmony_ci sdev->no_uld_attach = 1; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci return 0; 74762306a36Sopenharmony_ci} 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_cistatic int mptspi_slave_configure(struct scsi_device *sdev) 75062306a36Sopenharmony_ci{ 75162306a36Sopenharmony_ci struct _MPT_SCSI_HOST *hd = shost_priv(sdev->host); 75262306a36Sopenharmony_ci VirtTarget *vtarget = scsi_target(sdev)->hostdata; 75362306a36Sopenharmony_ci int ret; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci mptspi_initTarget(hd, vtarget, sdev); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci ret = mptscsih_slave_configure(sdev); 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci if (ret) 76062306a36Sopenharmony_ci return ret; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d min_period=0x%02x" 76362306a36Sopenharmony_ci " max_offset=0x%02x max_width=%d\n", hd->ioc->name, 76462306a36Sopenharmony_ci sdev->id, spi_min_period(scsi_target(sdev)), 76562306a36Sopenharmony_ci spi_max_offset(scsi_target(sdev)), 76662306a36Sopenharmony_ci spi_max_width(scsi_target(sdev)))); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci if ((sdev->channel == 1 || 76962306a36Sopenharmony_ci !(mptspi_is_raid(hd, sdev->id))) && 77062306a36Sopenharmony_ci !spi_initial_dv(sdev->sdev_target)) 77162306a36Sopenharmony_ci mptspi_dv_device(hd, sdev); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci return 0; 77462306a36Sopenharmony_ci} 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_cistatic int 77762306a36Sopenharmony_cimptspi_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt) 77862306a36Sopenharmony_ci{ 77962306a36Sopenharmony_ci struct _MPT_SCSI_HOST *hd = shost_priv(shost); 78062306a36Sopenharmony_ci VirtDevice *vdevice = SCpnt->device->hostdata; 78162306a36Sopenharmony_ci MPT_ADAPTER *ioc = hd->ioc; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci if (!vdevice || !vdevice->vtarget) { 78462306a36Sopenharmony_ci SCpnt->result = DID_NO_CONNECT << 16; 78562306a36Sopenharmony_ci scsi_done(SCpnt); 78662306a36Sopenharmony_ci return 0; 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci if (SCpnt->device->channel == 1 && 79062306a36Sopenharmony_ci mptscsih_is_phys_disk(ioc, 0, SCpnt->device->id) == 0) { 79162306a36Sopenharmony_ci SCpnt->result = DID_NO_CONNECT << 16; 79262306a36Sopenharmony_ci scsi_done(SCpnt); 79362306a36Sopenharmony_ci return 0; 79462306a36Sopenharmony_ci } 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci if (spi_dv_pending(scsi_target(SCpnt->device))) 79762306a36Sopenharmony_ci ddvprintk(ioc, scsi_print_command(SCpnt)); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci return mptscsih_qcmd(SCpnt); 80062306a36Sopenharmony_ci} 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_cistatic void mptspi_slave_destroy(struct scsi_device *sdev) 80362306a36Sopenharmony_ci{ 80462306a36Sopenharmony_ci struct scsi_target *starget = scsi_target(sdev); 80562306a36Sopenharmony_ci VirtTarget *vtarget = starget->hostdata; 80662306a36Sopenharmony_ci VirtDevice *vdevice = sdev->hostdata; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci /* Will this be the last lun on a non-raid device? */ 80962306a36Sopenharmony_ci if (vtarget->num_luns == 1 && vdevice->configured_lun) { 81062306a36Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci /* Async Narrow */ 81362306a36Sopenharmony_ci pg1.RequestedParameters = 0; 81462306a36Sopenharmony_ci pg1.Reserved = 0; 81562306a36Sopenharmony_ci pg1.Configuration = 0; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci mptspi_write_spi_device_pg1(starget, &pg1); 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci mptscsih_slave_destroy(sdev); 82162306a36Sopenharmony_ci} 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_cistatic const struct scsi_host_template mptspi_driver_template = { 82462306a36Sopenharmony_ci .module = THIS_MODULE, 82562306a36Sopenharmony_ci .proc_name = "mptspi", 82662306a36Sopenharmony_ci .show_info = mptscsih_show_info, 82762306a36Sopenharmony_ci .name = "MPT SPI Host", 82862306a36Sopenharmony_ci .info = mptscsih_info, 82962306a36Sopenharmony_ci .queuecommand = mptspi_qcmd, 83062306a36Sopenharmony_ci .target_alloc = mptspi_target_alloc, 83162306a36Sopenharmony_ci .slave_alloc = mptspi_slave_alloc, 83262306a36Sopenharmony_ci .slave_configure = mptspi_slave_configure, 83362306a36Sopenharmony_ci .target_destroy = mptspi_target_destroy, 83462306a36Sopenharmony_ci .slave_destroy = mptspi_slave_destroy, 83562306a36Sopenharmony_ci .change_queue_depth = mptscsih_change_queue_depth, 83662306a36Sopenharmony_ci .eh_abort_handler = mptscsih_abort, 83762306a36Sopenharmony_ci .eh_device_reset_handler = mptscsih_dev_reset, 83862306a36Sopenharmony_ci .eh_bus_reset_handler = mptscsih_bus_reset, 83962306a36Sopenharmony_ci .eh_host_reset_handler = mptscsih_host_reset, 84062306a36Sopenharmony_ci .bios_param = mptscsih_bios_param, 84162306a36Sopenharmony_ci .can_queue = MPT_SCSI_CAN_QUEUE, 84262306a36Sopenharmony_ci .this_id = -1, 84362306a36Sopenharmony_ci .sg_tablesize = MPT_SCSI_SG_DEPTH, 84462306a36Sopenharmony_ci .max_sectors = 8192, 84562306a36Sopenharmony_ci .cmd_per_lun = 7, 84662306a36Sopenharmony_ci .shost_groups = mptscsih_host_attr_groups, 84762306a36Sopenharmony_ci}; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_cistatic int mptspi_write_spi_device_pg1(struct scsi_target *starget, 85062306a36Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_1 *pass_pg1) 85162306a36Sopenharmony_ci{ 85262306a36Sopenharmony_ci struct Scsi_Host *shost = dev_to_shost(&starget->dev); 85362306a36Sopenharmony_ci struct _MPT_SCSI_HOST *hd = shost_priv(shost); 85462306a36Sopenharmony_ci struct _MPT_ADAPTER *ioc = hd->ioc; 85562306a36Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_1 *pg1; 85662306a36Sopenharmony_ci dma_addr_t pg1_dma; 85762306a36Sopenharmony_ci int size; 85862306a36Sopenharmony_ci struct _x_config_parms cfg; 85962306a36Sopenharmony_ci struct _CONFIG_PAGE_HEADER hdr; 86062306a36Sopenharmony_ci int err = -EBUSY; 86162306a36Sopenharmony_ci u32 nego_parms; 86262306a36Sopenharmony_ci u32 period; 86362306a36Sopenharmony_ci struct scsi_device *sdev; 86462306a36Sopenharmony_ci int i; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci /* don't allow updating nego parameters on RAID devices */ 86762306a36Sopenharmony_ci if (starget->channel == 0 && 86862306a36Sopenharmony_ci mptspi_is_raid(hd, starget->id)) 86962306a36Sopenharmony_ci return -1; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci size = ioc->spi_data.sdp1length * 4; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci pg1 = dma_alloc_coherent(&ioc->pcidev->dev, size, &pg1_dma, GFP_KERNEL); 87462306a36Sopenharmony_ci if (pg1 == NULL) { 87562306a36Sopenharmony_ci starget_printk(KERN_ERR, starget, MYIOC_s_FMT 87662306a36Sopenharmony_ci "dma_alloc_coherent for parameters failed\n", ioc->name); 87762306a36Sopenharmony_ci return -EINVAL; 87862306a36Sopenharmony_ci } 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci memset(&hdr, 0, sizeof(hdr)); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci hdr.PageVersion = ioc->spi_data.sdp1version; 88362306a36Sopenharmony_ci hdr.PageLength = ioc->spi_data.sdp1length; 88462306a36Sopenharmony_ci hdr.PageNumber = 1; 88562306a36Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci memset(&cfg, 0, sizeof(cfg)); 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci cfg.cfghdr.hdr = &hdr; 89062306a36Sopenharmony_ci cfg.physAddr = pg1_dma; 89162306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; 89262306a36Sopenharmony_ci cfg.dir = 1; 89362306a36Sopenharmony_ci cfg.pageAddr = starget->id; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci memcpy(pg1, pass_pg1, size); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci pg1->Header.PageVersion = hdr.PageVersion; 89862306a36Sopenharmony_ci pg1->Header.PageLength = hdr.PageLength; 89962306a36Sopenharmony_ci pg1->Header.PageNumber = hdr.PageNumber; 90062306a36Sopenharmony_ci pg1->Header.PageType = hdr.PageType; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci nego_parms = le32_to_cpu(pg1->RequestedParameters); 90362306a36Sopenharmony_ci period = (nego_parms & MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK) >> 90462306a36Sopenharmony_ci MPI_SCSIDEVPAGE1_RP_SHIFT_MIN_SYNC_PERIOD; 90562306a36Sopenharmony_ci if (period == 8) { 90662306a36Sopenharmony_ci /* Turn on inline data padding for TAPE when running U320 */ 90762306a36Sopenharmony_ci for (i = 0 ; i < 16; i++) { 90862306a36Sopenharmony_ci sdev = scsi_device_lookup_by_target(starget, i); 90962306a36Sopenharmony_ci if (sdev && sdev->type == TYPE_TAPE) { 91062306a36Sopenharmony_ci sdev_printk(KERN_DEBUG, sdev, MYIOC_s_FMT 91162306a36Sopenharmony_ci "IDP:ON\n", ioc->name); 91262306a36Sopenharmony_ci nego_parms |= MPI_SCSIDEVPAGE1_RP_IDP; 91362306a36Sopenharmony_ci pg1->RequestedParameters = 91462306a36Sopenharmony_ci cpu_to_le32(nego_parms); 91562306a36Sopenharmony_ci break; 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci } 91862306a36Sopenharmony_ci } 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci mptspi_print_write_nego(hd, starget, le32_to_cpu(pg1->RequestedParameters)); 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci if (mpt_config(ioc, &cfg)) { 92362306a36Sopenharmony_ci starget_printk(KERN_ERR, starget, MYIOC_s_FMT 92462306a36Sopenharmony_ci "mpt_config failed\n", ioc->name); 92562306a36Sopenharmony_ci goto out_free; 92662306a36Sopenharmony_ci } 92762306a36Sopenharmony_ci err = 0; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci out_free: 93062306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, size, pg1, pg1_dma); 93162306a36Sopenharmony_ci return err; 93262306a36Sopenharmony_ci} 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_cistatic void mptspi_write_offset(struct scsi_target *starget, int offset) 93562306a36Sopenharmony_ci{ 93662306a36Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; 93762306a36Sopenharmony_ci u32 nego; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci if (offset < 0) 94062306a36Sopenharmony_ci offset = 0; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci if (offset > 255) 94362306a36Sopenharmony_ci offset = 255; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci if (spi_offset(starget) == -1) 94662306a36Sopenharmony_ci mptspi_read_parameters(starget); 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci spi_offset(starget) = offset; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci nego = mptspi_getRP(starget); 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci pg1.RequestedParameters = cpu_to_le32(nego); 95362306a36Sopenharmony_ci pg1.Reserved = 0; 95462306a36Sopenharmony_ci pg1.Configuration = 0; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci mptspi_write_spi_device_pg1(starget, &pg1); 95762306a36Sopenharmony_ci} 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_cistatic void mptspi_write_period(struct scsi_target *starget, int period) 96062306a36Sopenharmony_ci{ 96162306a36Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; 96262306a36Sopenharmony_ci u32 nego; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci if (period < 8) 96562306a36Sopenharmony_ci period = 8; 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci if (period > 255) 96862306a36Sopenharmony_ci period = 255; 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci if (spi_period(starget) == -1) 97162306a36Sopenharmony_ci mptspi_read_parameters(starget); 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci if (period == 8) { 97462306a36Sopenharmony_ci spi_iu(starget) = 1; 97562306a36Sopenharmony_ci spi_dt(starget) = 1; 97662306a36Sopenharmony_ci } else if (period == 9) { 97762306a36Sopenharmony_ci spi_dt(starget) = 1; 97862306a36Sopenharmony_ci } 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci spi_period(starget) = period; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci nego = mptspi_getRP(starget); 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci pg1.RequestedParameters = cpu_to_le32(nego); 98562306a36Sopenharmony_ci pg1.Reserved = 0; 98662306a36Sopenharmony_ci pg1.Configuration = 0; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci mptspi_write_spi_device_pg1(starget, &pg1); 98962306a36Sopenharmony_ci} 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_cistatic void mptspi_write_dt(struct scsi_target *starget, int dt) 99262306a36Sopenharmony_ci{ 99362306a36Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; 99462306a36Sopenharmony_ci u32 nego; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci if (spi_period(starget) == -1) 99762306a36Sopenharmony_ci mptspi_read_parameters(starget); 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci if (!dt && spi_period(starget) < 10) 100062306a36Sopenharmony_ci spi_period(starget) = 10; 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci spi_dt(starget) = dt; 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci nego = mptspi_getRP(starget); 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci pg1.RequestedParameters = cpu_to_le32(nego); 100862306a36Sopenharmony_ci pg1.Reserved = 0; 100962306a36Sopenharmony_ci pg1.Configuration = 0; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci mptspi_write_spi_device_pg1(starget, &pg1); 101262306a36Sopenharmony_ci} 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_cistatic void mptspi_write_iu(struct scsi_target *starget, int iu) 101562306a36Sopenharmony_ci{ 101662306a36Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; 101762306a36Sopenharmony_ci u32 nego; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci if (spi_period(starget) == -1) 102062306a36Sopenharmony_ci mptspi_read_parameters(starget); 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci if (!iu && spi_period(starget) < 9) 102362306a36Sopenharmony_ci spi_period(starget) = 9; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci spi_iu(starget) = iu; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci nego = mptspi_getRP(starget); 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci pg1.RequestedParameters = cpu_to_le32(nego); 103062306a36Sopenharmony_ci pg1.Reserved = 0; 103162306a36Sopenharmony_ci pg1.Configuration = 0; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci mptspi_write_spi_device_pg1(starget, &pg1); 103462306a36Sopenharmony_ci} 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci#define MPTSPI_SIMPLE_TRANSPORT_PARM(parm) \ 103762306a36Sopenharmony_cistatic void mptspi_write_##parm(struct scsi_target *starget, int parm)\ 103862306a36Sopenharmony_ci{ \ 103962306a36Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; \ 104062306a36Sopenharmony_ci u32 nego; \ 104162306a36Sopenharmony_ci \ 104262306a36Sopenharmony_ci spi_##parm(starget) = parm; \ 104362306a36Sopenharmony_ci \ 104462306a36Sopenharmony_ci nego = mptspi_getRP(starget); \ 104562306a36Sopenharmony_ci \ 104662306a36Sopenharmony_ci pg1.RequestedParameters = cpu_to_le32(nego); \ 104762306a36Sopenharmony_ci pg1.Reserved = 0; \ 104862306a36Sopenharmony_ci pg1.Configuration = 0; \ 104962306a36Sopenharmony_ci \ 105062306a36Sopenharmony_ci mptspi_write_spi_device_pg1(starget, &pg1); \ 105162306a36Sopenharmony_ci} 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ciMPTSPI_SIMPLE_TRANSPORT_PARM(rd_strm) 105462306a36Sopenharmony_ciMPTSPI_SIMPLE_TRANSPORT_PARM(wr_flow) 105562306a36Sopenharmony_ciMPTSPI_SIMPLE_TRANSPORT_PARM(rti) 105662306a36Sopenharmony_ciMPTSPI_SIMPLE_TRANSPORT_PARM(hold_mcs) 105762306a36Sopenharmony_ciMPTSPI_SIMPLE_TRANSPORT_PARM(pcomp_en) 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_cistatic void mptspi_write_qas(struct scsi_target *starget, int qas) 106062306a36Sopenharmony_ci{ 106162306a36Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; 106262306a36Sopenharmony_ci struct Scsi_Host *shost = dev_to_shost(&starget->dev); 106362306a36Sopenharmony_ci struct _MPT_SCSI_HOST *hd = shost_priv(shost); 106462306a36Sopenharmony_ci VirtTarget *vtarget = starget->hostdata; 106562306a36Sopenharmony_ci u32 nego; 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci if ((vtarget->negoFlags & MPT_TARGET_NO_NEGO_QAS) || 106862306a36Sopenharmony_ci hd->ioc->spi_data.noQas) 106962306a36Sopenharmony_ci spi_qas(starget) = 0; 107062306a36Sopenharmony_ci else 107162306a36Sopenharmony_ci spi_qas(starget) = qas; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci nego = mptspi_getRP(starget); 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci pg1.RequestedParameters = cpu_to_le32(nego); 107662306a36Sopenharmony_ci pg1.Reserved = 0; 107762306a36Sopenharmony_ci pg1.Configuration = 0; 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci mptspi_write_spi_device_pg1(starget, &pg1); 108062306a36Sopenharmony_ci} 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_cistatic void mptspi_write_width(struct scsi_target *starget, int width) 108362306a36Sopenharmony_ci{ 108462306a36Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; 108562306a36Sopenharmony_ci u32 nego; 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci if (!width) { 108862306a36Sopenharmony_ci spi_dt(starget) = 0; 108962306a36Sopenharmony_ci if (spi_period(starget) < 10) 109062306a36Sopenharmony_ci spi_period(starget) = 10; 109162306a36Sopenharmony_ci } 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci spi_width(starget) = width; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci nego = mptspi_getRP(starget); 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci pg1.RequestedParameters = cpu_to_le32(nego); 109862306a36Sopenharmony_ci pg1.Reserved = 0; 109962306a36Sopenharmony_ci pg1.Configuration = 0; 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci mptspi_write_spi_device_pg1(starget, &pg1); 110262306a36Sopenharmony_ci} 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_cistruct work_queue_wrapper { 110562306a36Sopenharmony_ci struct work_struct work; 110662306a36Sopenharmony_ci struct _MPT_SCSI_HOST *hd; 110762306a36Sopenharmony_ci int disk; 110862306a36Sopenharmony_ci}; 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_cistatic void mpt_work_wrapper(struct work_struct *work) 111162306a36Sopenharmony_ci{ 111262306a36Sopenharmony_ci struct work_queue_wrapper *wqw = 111362306a36Sopenharmony_ci container_of(work, struct work_queue_wrapper, work); 111462306a36Sopenharmony_ci struct _MPT_SCSI_HOST *hd = wqw->hd; 111562306a36Sopenharmony_ci MPT_ADAPTER *ioc = hd->ioc; 111662306a36Sopenharmony_ci struct Scsi_Host *shost = ioc->sh; 111762306a36Sopenharmony_ci struct scsi_device *sdev; 111862306a36Sopenharmony_ci int disk = wqw->disk; 111962306a36Sopenharmony_ci struct _CONFIG_PAGE_IOC_3 *pg3; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci kfree(wqw); 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci mpt_findImVolumes(ioc); 112462306a36Sopenharmony_ci pg3 = ioc->raid_data.pIocPg3; 112562306a36Sopenharmony_ci if (!pg3) 112662306a36Sopenharmony_ci return; 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci shost_for_each_device(sdev,shost) { 112962306a36Sopenharmony_ci struct scsi_target *starget = scsi_target(sdev); 113062306a36Sopenharmony_ci VirtTarget *vtarget = starget->hostdata; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci /* only want to search RAID components */ 113362306a36Sopenharmony_ci if (sdev->channel != 1) 113462306a36Sopenharmony_ci continue; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci /* The id is the raid PhysDiskNum, even if 113762306a36Sopenharmony_ci * starget->id is the actual target address */ 113862306a36Sopenharmony_ci if(vtarget->id != disk) 113962306a36Sopenharmony_ci continue; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci starget_printk(KERN_INFO, vtarget->starget, MYIOC_s_FMT 114262306a36Sopenharmony_ci "Integrated RAID requests DV of new device\n", ioc->name); 114362306a36Sopenharmony_ci mptspi_dv_device(hd, sdev); 114462306a36Sopenharmony_ci } 114562306a36Sopenharmony_ci shost_printk(KERN_INFO, shost, MYIOC_s_FMT 114662306a36Sopenharmony_ci "Integrated RAID detects new device %d\n", ioc->name, disk); 114762306a36Sopenharmony_ci scsi_scan_target(&ioc->sh->shost_gendev, 1, disk, 0, SCSI_SCAN_RESCAN); 114862306a36Sopenharmony_ci} 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_cistatic void mpt_dv_raid(struct _MPT_SCSI_HOST *hd, int disk) 115262306a36Sopenharmony_ci{ 115362306a36Sopenharmony_ci struct work_queue_wrapper *wqw = kmalloc(sizeof(*wqw), GFP_ATOMIC); 115462306a36Sopenharmony_ci MPT_ADAPTER *ioc = hd->ioc; 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci if (!wqw) { 115762306a36Sopenharmony_ci shost_printk(KERN_ERR, ioc->sh, MYIOC_s_FMT 115862306a36Sopenharmony_ci "Failed to act on RAID event for physical disk %d\n", 115962306a36Sopenharmony_ci ioc->name, disk); 116062306a36Sopenharmony_ci return; 116162306a36Sopenharmony_ci } 116262306a36Sopenharmony_ci INIT_WORK(&wqw->work, mpt_work_wrapper); 116362306a36Sopenharmony_ci wqw->hd = hd; 116462306a36Sopenharmony_ci wqw->disk = disk; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci schedule_work(&wqw->work); 116762306a36Sopenharmony_ci} 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_cistatic int 117062306a36Sopenharmony_cimptspi_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) 117162306a36Sopenharmony_ci{ 117262306a36Sopenharmony_ci u8 event = le32_to_cpu(pEvReply->Event) & 0xFF; 117362306a36Sopenharmony_ci struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh); 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci if (ioc->bus_type != SPI) 117662306a36Sopenharmony_ci return 0; 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci if (hd && event == MPI_EVENT_INTEGRATED_RAID) { 117962306a36Sopenharmony_ci int reason 118062306a36Sopenharmony_ci = (le32_to_cpu(pEvReply->Data[0]) & 0x00FF0000) >> 16; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) { 118362306a36Sopenharmony_ci int disk = (le32_to_cpu(pEvReply->Data[0]) & 0xFF000000) >> 24; 118462306a36Sopenharmony_ci mpt_dv_raid(hd, disk); 118562306a36Sopenharmony_ci } 118662306a36Sopenharmony_ci } 118762306a36Sopenharmony_ci return mptscsih_event_process(ioc, pEvReply); 118862306a36Sopenharmony_ci} 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_cistatic int 119162306a36Sopenharmony_cimptspi_deny_binding(struct scsi_target *starget) 119262306a36Sopenharmony_ci{ 119362306a36Sopenharmony_ci struct _MPT_SCSI_HOST *hd = 119462306a36Sopenharmony_ci (struct _MPT_SCSI_HOST *)dev_to_shost(starget->dev.parent)->hostdata; 119562306a36Sopenharmony_ci return ((mptspi_is_raid(hd, starget->id)) && 119662306a36Sopenharmony_ci starget->channel == 0) ? 1 : 0; 119762306a36Sopenharmony_ci} 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_cistatic struct spi_function_template mptspi_transport_functions = { 120062306a36Sopenharmony_ci .get_offset = mptspi_read_parameters, 120162306a36Sopenharmony_ci .set_offset = mptspi_write_offset, 120262306a36Sopenharmony_ci .show_offset = 1, 120362306a36Sopenharmony_ci .get_period = mptspi_read_parameters, 120462306a36Sopenharmony_ci .set_period = mptspi_write_period, 120562306a36Sopenharmony_ci .show_period = 1, 120662306a36Sopenharmony_ci .get_width = mptspi_read_parameters, 120762306a36Sopenharmony_ci .set_width = mptspi_write_width, 120862306a36Sopenharmony_ci .show_width = 1, 120962306a36Sopenharmony_ci .get_iu = mptspi_read_parameters, 121062306a36Sopenharmony_ci .set_iu = mptspi_write_iu, 121162306a36Sopenharmony_ci .show_iu = 1, 121262306a36Sopenharmony_ci .get_dt = mptspi_read_parameters, 121362306a36Sopenharmony_ci .set_dt = mptspi_write_dt, 121462306a36Sopenharmony_ci .show_dt = 1, 121562306a36Sopenharmony_ci .get_qas = mptspi_read_parameters, 121662306a36Sopenharmony_ci .set_qas = mptspi_write_qas, 121762306a36Sopenharmony_ci .show_qas = 1, 121862306a36Sopenharmony_ci .get_wr_flow = mptspi_read_parameters, 121962306a36Sopenharmony_ci .set_wr_flow = mptspi_write_wr_flow, 122062306a36Sopenharmony_ci .show_wr_flow = 1, 122162306a36Sopenharmony_ci .get_rd_strm = mptspi_read_parameters, 122262306a36Sopenharmony_ci .set_rd_strm = mptspi_write_rd_strm, 122362306a36Sopenharmony_ci .show_rd_strm = 1, 122462306a36Sopenharmony_ci .get_rti = mptspi_read_parameters, 122562306a36Sopenharmony_ci .set_rti = mptspi_write_rti, 122662306a36Sopenharmony_ci .show_rti = 1, 122762306a36Sopenharmony_ci .get_pcomp_en = mptspi_read_parameters, 122862306a36Sopenharmony_ci .set_pcomp_en = mptspi_write_pcomp_en, 122962306a36Sopenharmony_ci .show_pcomp_en = 1, 123062306a36Sopenharmony_ci .get_hold_mcs = mptspi_read_parameters, 123162306a36Sopenharmony_ci .set_hold_mcs = mptspi_write_hold_mcs, 123262306a36Sopenharmony_ci .show_hold_mcs = 1, 123362306a36Sopenharmony_ci .deny_binding = mptspi_deny_binding, 123462306a36Sopenharmony_ci}; 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci/**************************************************************************** 123762306a36Sopenharmony_ci * Supported hardware 123862306a36Sopenharmony_ci */ 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_cistatic struct pci_device_id mptspi_pci_table[] = { 124162306a36Sopenharmony_ci { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1030, 124262306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID }, 124362306a36Sopenharmony_ci { PCI_VENDOR_ID_ATTO, MPI_MANUFACTPAGE_DEVID_53C1030, 124462306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID }, 124562306a36Sopenharmony_ci { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1035, 124662306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID }, 124762306a36Sopenharmony_ci {0} /* Terminating entry */ 124862306a36Sopenharmony_ci}; 124962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mptspi_pci_table); 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci/* 125362306a36Sopenharmony_ci * renegotiate for a given target 125462306a36Sopenharmony_ci */ 125562306a36Sopenharmony_cistatic void 125662306a36Sopenharmony_cimptspi_dv_renegotiate_work(struct work_struct *work) 125762306a36Sopenharmony_ci{ 125862306a36Sopenharmony_ci struct work_queue_wrapper *wqw = 125962306a36Sopenharmony_ci container_of(work, struct work_queue_wrapper, work); 126062306a36Sopenharmony_ci struct _MPT_SCSI_HOST *hd = wqw->hd; 126162306a36Sopenharmony_ci struct scsi_device *sdev; 126262306a36Sopenharmony_ci struct scsi_target *starget; 126362306a36Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; 126462306a36Sopenharmony_ci u32 nego; 126562306a36Sopenharmony_ci MPT_ADAPTER *ioc = hd->ioc; 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci kfree(wqw); 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci if (hd->spi_pending) { 127062306a36Sopenharmony_ci shost_for_each_device(sdev, ioc->sh) { 127162306a36Sopenharmony_ci if (hd->spi_pending & (1 << sdev->id)) 127262306a36Sopenharmony_ci continue; 127362306a36Sopenharmony_ci starget = scsi_target(sdev); 127462306a36Sopenharmony_ci nego = mptspi_getRP(starget); 127562306a36Sopenharmony_ci pg1.RequestedParameters = cpu_to_le32(nego); 127662306a36Sopenharmony_ci pg1.Reserved = 0; 127762306a36Sopenharmony_ci pg1.Configuration = 0; 127862306a36Sopenharmony_ci mptspi_write_spi_device_pg1(starget, &pg1); 127962306a36Sopenharmony_ci } 128062306a36Sopenharmony_ci } else { 128162306a36Sopenharmony_ci shost_for_each_device(sdev, ioc->sh) 128262306a36Sopenharmony_ci mptspi_dv_device(hd, sdev); 128362306a36Sopenharmony_ci } 128462306a36Sopenharmony_ci} 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_cistatic void 128762306a36Sopenharmony_cimptspi_dv_renegotiate(struct _MPT_SCSI_HOST *hd) 128862306a36Sopenharmony_ci{ 128962306a36Sopenharmony_ci struct work_queue_wrapper *wqw = kmalloc(sizeof(*wqw), GFP_ATOMIC); 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci if (!wqw) 129262306a36Sopenharmony_ci return; 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci INIT_WORK(&wqw->work, mptspi_dv_renegotiate_work); 129562306a36Sopenharmony_ci wqw->hd = hd; 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci schedule_work(&wqw->work); 129862306a36Sopenharmony_ci} 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci/* 130162306a36Sopenharmony_ci * spi module reset handler 130262306a36Sopenharmony_ci */ 130362306a36Sopenharmony_cistatic int 130462306a36Sopenharmony_cimptspi_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) 130562306a36Sopenharmony_ci{ 130662306a36Sopenharmony_ci int rc; 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci rc = mptscsih_ioc_reset(ioc, reset_phase); 130962306a36Sopenharmony_ci if ((ioc->bus_type != SPI) || (!rc)) 131062306a36Sopenharmony_ci return rc; 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci /* only try to do a renegotiation if we're properly set up 131362306a36Sopenharmony_ci * if we get an ioc fault on bringup, ioc->sh will be NULL */ 131462306a36Sopenharmony_ci if (reset_phase == MPT_IOC_POST_RESET && 131562306a36Sopenharmony_ci ioc->sh) { 131662306a36Sopenharmony_ci struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh); 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci mptspi_dv_renegotiate(hd); 131962306a36Sopenharmony_ci } 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci return rc; 132262306a36Sopenharmony_ci} 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci#ifdef CONFIG_PM 132562306a36Sopenharmony_ci/* 132662306a36Sopenharmony_ci * spi module resume handler 132762306a36Sopenharmony_ci */ 132862306a36Sopenharmony_cistatic int 132962306a36Sopenharmony_cimptspi_resume(struct pci_dev *pdev) 133062306a36Sopenharmony_ci{ 133162306a36Sopenharmony_ci MPT_ADAPTER *ioc = pci_get_drvdata(pdev); 133262306a36Sopenharmony_ci struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh); 133362306a36Sopenharmony_ci int rc; 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci rc = mptscsih_resume(pdev); 133662306a36Sopenharmony_ci mptspi_dv_renegotiate(hd); 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci return rc; 133962306a36Sopenharmony_ci} 134062306a36Sopenharmony_ci#endif 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 134362306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 134462306a36Sopenharmony_ci/* 134562306a36Sopenharmony_ci * mptspi_probe - Installs scsi devices per bus. 134662306a36Sopenharmony_ci * @pdev: Pointer to pci_dev structure 134762306a36Sopenharmony_ci * 134862306a36Sopenharmony_ci * Returns 0 for success, non-zero for failure. 134962306a36Sopenharmony_ci * 135062306a36Sopenharmony_ci */ 135162306a36Sopenharmony_cistatic int 135262306a36Sopenharmony_cimptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id) 135362306a36Sopenharmony_ci{ 135462306a36Sopenharmony_ci struct Scsi_Host *sh; 135562306a36Sopenharmony_ci MPT_SCSI_HOST *hd; 135662306a36Sopenharmony_ci MPT_ADAPTER *ioc; 135762306a36Sopenharmony_ci unsigned long flags; 135862306a36Sopenharmony_ci int ii; 135962306a36Sopenharmony_ci int numSGE = 0; 136062306a36Sopenharmony_ci int scale; 136162306a36Sopenharmony_ci int ioc_cap; 136262306a36Sopenharmony_ci int error=0; 136362306a36Sopenharmony_ci int r; 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci if ((r = mpt_attach(pdev,id)) != 0) 136662306a36Sopenharmony_ci return r; 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci ioc = pci_get_drvdata(pdev); 136962306a36Sopenharmony_ci ioc->DoneCtx = mptspiDoneCtx; 137062306a36Sopenharmony_ci ioc->TaskCtx = mptspiTaskCtx; 137162306a36Sopenharmony_ci ioc->InternalCtx = mptspiInternalCtx; 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci /* Added sanity check on readiness of the MPT adapter. 137462306a36Sopenharmony_ci */ 137562306a36Sopenharmony_ci if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) { 137662306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT 137762306a36Sopenharmony_ci "Skipping because it's not operational!\n", 137862306a36Sopenharmony_ci ioc->name); 137962306a36Sopenharmony_ci error = -ENODEV; 138062306a36Sopenharmony_ci goto out_mptspi_probe; 138162306a36Sopenharmony_ci } 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci if (!ioc->active) { 138462306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n", 138562306a36Sopenharmony_ci ioc->name); 138662306a36Sopenharmony_ci error = -ENODEV; 138762306a36Sopenharmony_ci goto out_mptspi_probe; 138862306a36Sopenharmony_ci } 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci /* Sanity check - ensure at least 1 port is INITIATOR capable 139162306a36Sopenharmony_ci */ 139262306a36Sopenharmony_ci ioc_cap = 0; 139362306a36Sopenharmony_ci for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) { 139462306a36Sopenharmony_ci if (ioc->pfacts[ii].ProtocolFlags & 139562306a36Sopenharmony_ci MPI_PORTFACTS_PROTOCOL_INITIATOR) 139662306a36Sopenharmony_ci ioc_cap ++; 139762306a36Sopenharmony_ci } 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci if (!ioc_cap) { 140062306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT 140162306a36Sopenharmony_ci "Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n", 140262306a36Sopenharmony_ci ioc->name, ioc); 140362306a36Sopenharmony_ci return 0; 140462306a36Sopenharmony_ci } 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci sh = scsi_host_alloc(&mptspi_driver_template, sizeof(MPT_SCSI_HOST)); 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci if (!sh) { 140962306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT 141062306a36Sopenharmony_ci "Unable to register controller with SCSI subsystem\n", 141162306a36Sopenharmony_ci ioc->name); 141262306a36Sopenharmony_ci error = -1; 141362306a36Sopenharmony_ci goto out_mptspi_probe; 141462306a36Sopenharmony_ci } 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci /* VMWare emulation doesn't properly implement WRITE_SAME 141762306a36Sopenharmony_ci */ 141862306a36Sopenharmony_ci if (pdev->subsystem_vendor == 0x15AD) 141962306a36Sopenharmony_ci sh->no_write_same = 1; 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci spin_lock_irqsave(&ioc->FreeQlock, flags); 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci /* Attach the SCSI Host to the IOC structure 142462306a36Sopenharmony_ci */ 142562306a36Sopenharmony_ci ioc->sh = sh; 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci sh->io_port = 0; 142862306a36Sopenharmony_ci sh->n_io_port = 0; 142962306a36Sopenharmony_ci sh->irq = 0; 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci /* set 16 byte cdb's */ 143262306a36Sopenharmony_ci sh->max_cmd_len = 16; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci /* Yikes! This is important! 143562306a36Sopenharmony_ci * Otherwise, by default, linux 143662306a36Sopenharmony_ci * only scans target IDs 0-7! 143762306a36Sopenharmony_ci * pfactsN->MaxDevices unreliable 143862306a36Sopenharmony_ci * (not supported in early 143962306a36Sopenharmony_ci * versions of the FW). 144062306a36Sopenharmony_ci * max_id = 1 + actual max id, 144162306a36Sopenharmony_ci * max_lun = 1 + actual last lun, 144262306a36Sopenharmony_ci * see hosts.h :o( 144362306a36Sopenharmony_ci */ 144462306a36Sopenharmony_ci sh->max_id = ioc->devices_per_bus; 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci sh->max_lun = MPT_LAST_LUN + 1; 144762306a36Sopenharmony_ci /* 144862306a36Sopenharmony_ci * If RAID Firmware Detected, setup virtual channel 144962306a36Sopenharmony_ci */ 145062306a36Sopenharmony_ci if (ioc->ir_firmware) 145162306a36Sopenharmony_ci sh->max_channel = 1; 145262306a36Sopenharmony_ci else 145362306a36Sopenharmony_ci sh->max_channel = 0; 145462306a36Sopenharmony_ci sh->this_id = ioc->pfacts[0].PortSCSIID; 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci /* Required entry. 145762306a36Sopenharmony_ci */ 145862306a36Sopenharmony_ci sh->unique_id = ioc->id; 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci /* Verify that we won't exceed the maximum 146162306a36Sopenharmony_ci * number of chain buffers 146262306a36Sopenharmony_ci * We can optimize: ZZ = req_sz/sizeof(SGE) 146362306a36Sopenharmony_ci * For 32bit SGE's: 146462306a36Sopenharmony_ci * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ 146562306a36Sopenharmony_ci * + (req_sz - 64)/sizeof(SGE) 146662306a36Sopenharmony_ci * A slightly different algorithm is required for 146762306a36Sopenharmony_ci * 64bit SGEs. 146862306a36Sopenharmony_ci */ 146962306a36Sopenharmony_ci scale = ioc->req_sz/ioc->SGE_size; 147062306a36Sopenharmony_ci if (ioc->sg_addr_size == sizeof(u64)) { 147162306a36Sopenharmony_ci numSGE = (scale - 1) * 147262306a36Sopenharmony_ci (ioc->facts.MaxChainDepth-1) + scale + 147362306a36Sopenharmony_ci (ioc->req_sz - 60) / ioc->SGE_size; 147462306a36Sopenharmony_ci } else { 147562306a36Sopenharmony_ci numSGE = 1 + (scale - 1) * 147662306a36Sopenharmony_ci (ioc->facts.MaxChainDepth-1) + scale + 147762306a36Sopenharmony_ci (ioc->req_sz - 64) / ioc->SGE_size; 147862306a36Sopenharmony_ci } 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci if (numSGE < sh->sg_tablesize) { 148162306a36Sopenharmony_ci /* Reset this value */ 148262306a36Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_DEBUG_FMT 148362306a36Sopenharmony_ci "Resetting sg_tablesize to %d from %d\n", 148462306a36Sopenharmony_ci ioc->name, numSGE, sh->sg_tablesize)); 148562306a36Sopenharmony_ci sh->sg_tablesize = numSGE; 148662306a36Sopenharmony_ci } 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->FreeQlock, flags); 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci hd = shost_priv(sh); 149162306a36Sopenharmony_ci hd->ioc = ioc; 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci /* SCSI needs scsi_cmnd lookup table! 149462306a36Sopenharmony_ci * (with size equal to req_depth*PtrSz!) 149562306a36Sopenharmony_ci */ 149662306a36Sopenharmony_ci ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_KERNEL); 149762306a36Sopenharmony_ci if (!ioc->ScsiLookup) { 149862306a36Sopenharmony_ci error = -ENOMEM; 149962306a36Sopenharmony_ci goto out_mptspi_probe; 150062306a36Sopenharmony_ci } 150162306a36Sopenharmony_ci spin_lock_init(&ioc->scsi_lookup_lock); 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n", 150462306a36Sopenharmony_ci ioc->name, ioc->ScsiLookup)); 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci ioc->spi_data.Saf_Te = mpt_saf_te; 150762306a36Sopenharmony_ci ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT 150862306a36Sopenharmony_ci "saf_te %x\n", 150962306a36Sopenharmony_ci ioc->name, 151062306a36Sopenharmony_ci mpt_saf_te)); 151162306a36Sopenharmony_ci ioc->spi_data.noQas = 0; 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci hd->last_queue_full = 0; 151462306a36Sopenharmony_ci hd->spi_pending = 0; 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci /* Some versions of the firmware don't support page 0; without 151762306a36Sopenharmony_ci * that we can't get the parameters */ 151862306a36Sopenharmony_ci if (ioc->spi_data.sdp0length != 0) 151962306a36Sopenharmony_ci sh->transportt = mptspi_transport_template; 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci error = scsi_add_host (sh, &ioc->pcidev->dev); 152262306a36Sopenharmony_ci if(error) { 152362306a36Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_ERR_FMT 152462306a36Sopenharmony_ci "scsi_add_host failed\n", ioc->name)); 152562306a36Sopenharmony_ci goto out_mptspi_probe; 152662306a36Sopenharmony_ci } 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci /* 152962306a36Sopenharmony_ci * issue internal bus reset 153062306a36Sopenharmony_ci */ 153162306a36Sopenharmony_ci if (ioc->spi_data.bus_reset) 153262306a36Sopenharmony_ci mptscsih_IssueTaskMgmt(hd, 153362306a36Sopenharmony_ci MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, 153462306a36Sopenharmony_ci 0, 0, 0, 0, 5); 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci scsi_scan_host(sh); 153762306a36Sopenharmony_ci return 0; 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ciout_mptspi_probe: 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci mptscsih_remove(pdev); 154262306a36Sopenharmony_ci return error; 154362306a36Sopenharmony_ci} 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_cistatic void mptspi_remove(struct pci_dev *pdev) 154662306a36Sopenharmony_ci{ 154762306a36Sopenharmony_ci MPT_ADAPTER *ioc = pci_get_drvdata(pdev); 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci scsi_remove_host(ioc->sh); 155062306a36Sopenharmony_ci mptscsih_remove(pdev); 155162306a36Sopenharmony_ci} 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_cistatic struct pci_driver mptspi_driver = { 155462306a36Sopenharmony_ci .name = "mptspi", 155562306a36Sopenharmony_ci .id_table = mptspi_pci_table, 155662306a36Sopenharmony_ci .probe = mptspi_probe, 155762306a36Sopenharmony_ci .remove = mptspi_remove, 155862306a36Sopenharmony_ci .shutdown = mptscsih_shutdown, 155962306a36Sopenharmony_ci#ifdef CONFIG_PM 156062306a36Sopenharmony_ci .suspend = mptscsih_suspend, 156162306a36Sopenharmony_ci .resume = mptspi_resume, 156262306a36Sopenharmony_ci#endif 156362306a36Sopenharmony_ci}; 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 156662306a36Sopenharmony_ci/** 156762306a36Sopenharmony_ci * mptspi_init - Register MPT adapter(s) as SCSI host(s) with SCSI mid-layer. 156862306a36Sopenharmony_ci * 156962306a36Sopenharmony_ci * Returns 0 for success, non-zero for failure. 157062306a36Sopenharmony_ci */ 157162306a36Sopenharmony_cistatic int __init 157262306a36Sopenharmony_cimptspi_init(void) 157362306a36Sopenharmony_ci{ 157462306a36Sopenharmony_ci int error; 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci show_mptmod_ver(my_NAME, my_VERSION); 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci mptspi_transport_template = spi_attach_transport(&mptspi_transport_functions); 157962306a36Sopenharmony_ci if (!mptspi_transport_template) 158062306a36Sopenharmony_ci return -ENODEV; 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci mptspiDoneCtx = mpt_register(mptscsih_io_done, MPTSPI_DRIVER, 158362306a36Sopenharmony_ci "mptscsih_io_done"); 158462306a36Sopenharmony_ci mptspiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSPI_DRIVER, 158562306a36Sopenharmony_ci "mptscsih_taskmgmt_complete"); 158662306a36Sopenharmony_ci mptspiInternalCtx = mpt_register(mptscsih_scandv_complete, 158762306a36Sopenharmony_ci MPTSPI_DRIVER, "mptscsih_scandv_complete"); 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci mpt_event_register(mptspiDoneCtx, mptspi_event_process); 159062306a36Sopenharmony_ci mpt_reset_register(mptspiDoneCtx, mptspi_ioc_reset); 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci error = pci_register_driver(&mptspi_driver); 159362306a36Sopenharmony_ci if (error) 159462306a36Sopenharmony_ci spi_release_transport(mptspi_transport_template); 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci return error; 159762306a36Sopenharmony_ci} 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 160062306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 160162306a36Sopenharmony_ci/** 160262306a36Sopenharmony_ci * mptspi_exit - Unregisters MPT adapter(s) 160362306a36Sopenharmony_ci */ 160462306a36Sopenharmony_cistatic void __exit 160562306a36Sopenharmony_cimptspi_exit(void) 160662306a36Sopenharmony_ci{ 160762306a36Sopenharmony_ci pci_unregister_driver(&mptspi_driver); 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci mpt_reset_deregister(mptspiDoneCtx); 161062306a36Sopenharmony_ci mpt_event_deregister(mptspiDoneCtx); 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci mpt_deregister(mptspiInternalCtx); 161362306a36Sopenharmony_ci mpt_deregister(mptspiTaskCtx); 161462306a36Sopenharmony_ci mpt_deregister(mptspiDoneCtx); 161562306a36Sopenharmony_ci spi_release_transport(mptspi_transport_template); 161662306a36Sopenharmony_ci} 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_cimodule_init(mptspi_init); 161962306a36Sopenharmony_cimodule_exit(mptspi_exit); 1620