18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * linux/drivers/message/fusion/mptspi.c 38c2ecf20Sopenharmony_ci * For use with LSI PCI chip/adapter(s) 48c2ecf20Sopenharmony_ci * running LSI Fusion MPT (Message Passing Technology) firmware. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (c) 1999-2008 LSI Corporation 78c2ecf20Sopenharmony_ci * (mailto:DL-MPTFusionLinux@lsi.com) 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 118c2ecf20Sopenharmony_ci/* 128c2ecf20Sopenharmony_ci This program is free software; you can redistribute it and/or modify 138c2ecf20Sopenharmony_ci it under the terms of the GNU General Public License as published by 148c2ecf20Sopenharmony_ci the Free Software Foundation; version 2 of the License. 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci This program is distributed in the hope that it will be useful, 178c2ecf20Sopenharmony_ci but WITHOUT ANY WARRANTY; without even the implied warranty of 188c2ecf20Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 198c2ecf20Sopenharmony_ci GNU General Public License for more details. 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci NO WARRANTY 228c2ecf20Sopenharmony_ci THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR 238c2ecf20Sopenharmony_ci CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT 248c2ecf20Sopenharmony_ci LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, 258c2ecf20Sopenharmony_ci MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is 268c2ecf20Sopenharmony_ci solely responsible for determining the appropriateness of using and 278c2ecf20Sopenharmony_ci distributing the Program and assumes all risks associated with its 288c2ecf20Sopenharmony_ci exercise of rights under this Agreement, including but not limited to 298c2ecf20Sopenharmony_ci the risks and costs of program errors, damage to or loss of data, 308c2ecf20Sopenharmony_ci programs or equipment, and unavailability or interruption of operations. 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci DISCLAIMER OF LIABILITY 338c2ecf20Sopenharmony_ci NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY 348c2ecf20Sopenharmony_ci DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 358c2ecf20Sopenharmony_ci DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND 368c2ecf20Sopenharmony_ci ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 378c2ecf20Sopenharmony_ci TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 388c2ecf20Sopenharmony_ci USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED 398c2ecf20Sopenharmony_ci HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci You should have received a copy of the GNU General Public License 428c2ecf20Sopenharmony_ci along with this program; if not, write to the Free Software 438c2ecf20Sopenharmony_ci Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 448c2ecf20Sopenharmony_ci*/ 458c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#include <linux/module.h> 488c2ecf20Sopenharmony_ci#include <linux/kernel.h> 498c2ecf20Sopenharmony_ci#include <linux/slab.h> 508c2ecf20Sopenharmony_ci#include <linux/init.h> 518c2ecf20Sopenharmony_ci#include <linux/errno.h> 528c2ecf20Sopenharmony_ci#include <linux/kdev_t.h> 538c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 548c2ecf20Sopenharmony_ci#include <linux/delay.h> /* for mdelay */ 558c2ecf20Sopenharmony_ci#include <linux/interrupt.h> /* needed for in_interrupt() proto */ 568c2ecf20Sopenharmony_ci#include <linux/reboot.h> /* notifier code */ 578c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 588c2ecf20Sopenharmony_ci#include <linux/raid_class.h> 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 618c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 628c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h> 638c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 648c2ecf20Sopenharmony_ci#include <scsi/scsi_tcq.h> 658c2ecf20Sopenharmony_ci#include <scsi/scsi_transport.h> 668c2ecf20Sopenharmony_ci#include <scsi/scsi_transport_spi.h> 678c2ecf20Sopenharmony_ci#include <scsi/scsi_dbg.h> 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#include "mptbase.h" 708c2ecf20Sopenharmony_ci#include "mptscsih.h" 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 738c2ecf20Sopenharmony_ci#define my_NAME "Fusion MPT SPI Host driver" 748c2ecf20Sopenharmony_ci#define my_VERSION MPT_LINUX_VERSION_COMMON 758c2ecf20Sopenharmony_ci#define MYNAM "mptspi" 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ciMODULE_AUTHOR(MODULEAUTHOR); 788c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(my_NAME); 798c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 808c2ecf20Sopenharmony_ciMODULE_VERSION(my_VERSION); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/* Command line args */ 838c2ecf20Sopenharmony_cistatic int mpt_saf_te = MPTSCSIH_SAF_TE; 848c2ecf20Sopenharmony_cimodule_param(mpt_saf_te, int, 0); 858c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mpt_saf_te, " Force enabling SEP Processor: enable=1 (default=MPTSCSIH_SAF_TE=0)"); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic void mptspi_write_offset(struct scsi_target *, int); 888c2ecf20Sopenharmony_cistatic void mptspi_write_width(struct scsi_target *, int); 898c2ecf20Sopenharmony_cistatic int mptspi_write_spi_device_pg1(struct scsi_target *, 908c2ecf20Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_1 *); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic struct scsi_transport_template *mptspi_transport_template = NULL; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic u8 mptspiDoneCtx = MPT_MAX_PROTOCOL_DRIVERS; 958c2ecf20Sopenharmony_cistatic u8 mptspiTaskCtx = MPT_MAX_PROTOCOL_DRIVERS; 968c2ecf20Sopenharmony_cistatic u8 mptspiInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */ 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/** 998c2ecf20Sopenharmony_ci * mptspi_setTargetNegoParms - Update the target negotiation parameters 1008c2ecf20Sopenharmony_ci * @hd: Pointer to a SCSI Host Structure 1018c2ecf20Sopenharmony_ci * @target: per target private data 1028c2ecf20Sopenharmony_ci * @sdev: SCSI device 1038c2ecf20Sopenharmony_ci * 1048c2ecf20Sopenharmony_ci * Update the target negotiation parameters based on the the Inquiry 1058c2ecf20Sopenharmony_ci * data, adapter capabilities, and NVRAM settings. 1068c2ecf20Sopenharmony_ci **/ 1078c2ecf20Sopenharmony_cistatic void 1088c2ecf20Sopenharmony_cimptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target, 1098c2ecf20Sopenharmony_ci struct scsi_device *sdev) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc = hd->ioc; 1128c2ecf20Sopenharmony_ci SpiCfgData *pspi_data = &ioc->spi_data; 1138c2ecf20Sopenharmony_ci int id = (int) target->id; 1148c2ecf20Sopenharmony_ci int nvram; 1158c2ecf20Sopenharmony_ci u8 width = MPT_NARROW; 1168c2ecf20Sopenharmony_ci u8 factor = MPT_ASYNC; 1178c2ecf20Sopenharmony_ci u8 offset = 0; 1188c2ecf20Sopenharmony_ci u8 nfactor; 1198c2ecf20Sopenharmony_ci u8 noQas = 1; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci target->negoFlags = pspi_data->noQas; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (sdev->scsi_level < SCSI_2) { 1248c2ecf20Sopenharmony_ci width = 0; 1258c2ecf20Sopenharmony_ci factor = MPT_ULTRA2; 1268c2ecf20Sopenharmony_ci offset = pspi_data->maxSyncOffset; 1278c2ecf20Sopenharmony_ci target->tflags &= ~MPT_TARGET_FLAGS_Q_YES; 1288c2ecf20Sopenharmony_ci } else { 1298c2ecf20Sopenharmony_ci if (scsi_device_wide(sdev)) 1308c2ecf20Sopenharmony_ci width = 1; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if (scsi_device_sync(sdev)) { 1338c2ecf20Sopenharmony_ci factor = pspi_data->minSyncFactor; 1348c2ecf20Sopenharmony_ci if (!scsi_device_dt(sdev)) 1358c2ecf20Sopenharmony_ci factor = MPT_ULTRA2; 1368c2ecf20Sopenharmony_ci else { 1378c2ecf20Sopenharmony_ci if (!scsi_device_ius(sdev) && 1388c2ecf20Sopenharmony_ci !scsi_device_qas(sdev)) 1398c2ecf20Sopenharmony_ci factor = MPT_ULTRA160; 1408c2ecf20Sopenharmony_ci else { 1418c2ecf20Sopenharmony_ci factor = MPT_ULTRA320; 1428c2ecf20Sopenharmony_ci if (scsi_device_qas(sdev)) { 1438c2ecf20Sopenharmony_ci ddvprintk(ioc, 1448c2ecf20Sopenharmony_ci printk(MYIOC_s_DEBUG_FMT "Enabling QAS due to " 1458c2ecf20Sopenharmony_ci "byte56=%02x on id=%d!\n", ioc->name, 1468c2ecf20Sopenharmony_ci scsi_device_qas(sdev), id)); 1478c2ecf20Sopenharmony_ci noQas = 0; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci if (sdev->type == TYPE_TAPE && 1508c2ecf20Sopenharmony_ci scsi_device_ius(sdev)) 1518c2ecf20Sopenharmony_ci target->negoFlags |= MPT_TAPE_NEGO_IDP; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci offset = pspi_data->maxSyncOffset; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci /* If RAID, never disable QAS 1578c2ecf20Sopenharmony_ci * else if non RAID, do not disable 1588c2ecf20Sopenharmony_ci * QAS if bit 1 is set 1598c2ecf20Sopenharmony_ci * bit 1 QAS support, non-raid only 1608c2ecf20Sopenharmony_ci * bit 0 IU support 1618c2ecf20Sopenharmony_ci */ 1628c2ecf20Sopenharmony_ci if (target->raidVolume == 1) 1638c2ecf20Sopenharmony_ci noQas = 0; 1648c2ecf20Sopenharmony_ci } else { 1658c2ecf20Sopenharmony_ci factor = MPT_ASYNC; 1668c2ecf20Sopenharmony_ci offset = 0; 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (!sdev->tagged_supported) 1718c2ecf20Sopenharmony_ci target->tflags &= ~MPT_TARGET_FLAGS_Q_YES; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci /* Update tflags based on NVRAM settings. (SCSI only) 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_ci if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) { 1768c2ecf20Sopenharmony_ci nvram = pspi_data->nvram[id]; 1778c2ecf20Sopenharmony_ci nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci if (width) 1808c2ecf20Sopenharmony_ci width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci if (offset > 0) { 1838c2ecf20Sopenharmony_ci /* Ensure factor is set to the 1848c2ecf20Sopenharmony_ci * maximum of: adapter, nvram, inquiry 1858c2ecf20Sopenharmony_ci */ 1868c2ecf20Sopenharmony_ci if (nfactor) { 1878c2ecf20Sopenharmony_ci if (nfactor < pspi_data->minSyncFactor ) 1888c2ecf20Sopenharmony_ci nfactor = pspi_data->minSyncFactor; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci factor = max(factor, nfactor); 1918c2ecf20Sopenharmony_ci if (factor == MPT_ASYNC) 1928c2ecf20Sopenharmony_ci offset = 0; 1938c2ecf20Sopenharmony_ci } else { 1948c2ecf20Sopenharmony_ci offset = 0; 1958c2ecf20Sopenharmony_ci factor = MPT_ASYNC; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci } else { 1988c2ecf20Sopenharmony_ci factor = MPT_ASYNC; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* Make sure data is consistent 2038c2ecf20Sopenharmony_ci */ 2048c2ecf20Sopenharmony_ci if ((!width) && (factor < MPT_ULTRA2)) 2058c2ecf20Sopenharmony_ci factor = MPT_ULTRA2; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci /* Save the data to the target structure. 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_ci target->minSyncFactor = factor; 2108c2ecf20Sopenharmony_ci target->maxOffset = offset; 2118c2ecf20Sopenharmony_ci target->maxWidth = width; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci spi_min_period(scsi_target(sdev)) = factor; 2148c2ecf20Sopenharmony_ci spi_max_offset(scsi_target(sdev)) = offset; 2158c2ecf20Sopenharmony_ci spi_max_width(scsi_target(sdev)) = width; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* Disable unused features. 2208c2ecf20Sopenharmony_ci */ 2218c2ecf20Sopenharmony_ci if (!width) 2228c2ecf20Sopenharmony_ci target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci if (!offset) 2258c2ecf20Sopenharmony_ci target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci if ( factor > MPT_ULTRA320 ) 2288c2ecf20Sopenharmony_ci noQas = 0; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (noQas && (pspi_data->noQas == 0)) { 2318c2ecf20Sopenharmony_ci pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS; 2328c2ecf20Sopenharmony_ci target->negoFlags |= MPT_TARGET_NO_NEGO_QAS; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci /* Disable QAS in a mixed configuration case 2358c2ecf20Sopenharmony_ci */ 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT 2388c2ecf20Sopenharmony_ci "Disabling QAS due to noQas=%02x on id=%d!\n", ioc->name, noQas, id)); 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci/** 2438c2ecf20Sopenharmony_ci * mptspi_writeIOCPage4 - write IOC Page 4 2448c2ecf20Sopenharmony_ci * @hd: Pointer to a SCSI Host Structure 2458c2ecf20Sopenharmony_ci * @channel: channel number 2468c2ecf20Sopenharmony_ci * @id: write IOC Page4 for this ID & Bus 2478c2ecf20Sopenharmony_ci * 2488c2ecf20Sopenharmony_ci * Return: -EAGAIN if unable to obtain a Message Frame 2498c2ecf20Sopenharmony_ci * or 0 if success. 2508c2ecf20Sopenharmony_ci * 2518c2ecf20Sopenharmony_ci * Remark: We do not wait for a return, write pages sequentially. 2528c2ecf20Sopenharmony_ci **/ 2538c2ecf20Sopenharmony_cistatic int 2548c2ecf20Sopenharmony_cimptspi_writeIOCPage4(MPT_SCSI_HOST *hd, u8 channel , u8 id) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc = hd->ioc; 2578c2ecf20Sopenharmony_ci Config_t *pReq; 2588c2ecf20Sopenharmony_ci IOCPage4_t *IOCPage4Ptr; 2598c2ecf20Sopenharmony_ci MPT_FRAME_HDR *mf; 2608c2ecf20Sopenharmony_ci dma_addr_t dataDma; 2618c2ecf20Sopenharmony_ci u32 flagsLength; 2628c2ecf20Sopenharmony_ci int ii; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci /* Get a MF for this command. 2658c2ecf20Sopenharmony_ci */ 2668c2ecf20Sopenharmony_ci if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) { 2678c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_WARN_FMT 2688c2ecf20Sopenharmony_ci "writeIOCPage4 : no msg frames!\n",ioc->name)); 2698c2ecf20Sopenharmony_ci return -EAGAIN; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci /* Set the request and the data pointers. 2738c2ecf20Sopenharmony_ci * Place data at end of MF. 2748c2ecf20Sopenharmony_ci */ 2758c2ecf20Sopenharmony_ci pReq = (Config_t *)mf; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci /* Complete the request frame (same for all requests). 2788c2ecf20Sopenharmony_ci */ 2798c2ecf20Sopenharmony_ci pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; 2808c2ecf20Sopenharmony_ci pReq->Reserved = 0; 2818c2ecf20Sopenharmony_ci pReq->ChainOffset = 0; 2828c2ecf20Sopenharmony_ci pReq->Function = MPI_FUNCTION_CONFIG; 2838c2ecf20Sopenharmony_ci pReq->ExtPageLength = 0; 2848c2ecf20Sopenharmony_ci pReq->ExtPageType = 0; 2858c2ecf20Sopenharmony_ci pReq->MsgFlags = 0; 2868c2ecf20Sopenharmony_ci for (ii=0; ii < 8; ii++) { 2878c2ecf20Sopenharmony_ci pReq->Reserved2[ii] = 0; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci IOCPage4Ptr = ioc->spi_data.pIocPg4; 2918c2ecf20Sopenharmony_ci dataDma = ioc->spi_data.IocPg4_dma; 2928c2ecf20Sopenharmony_ci ii = IOCPage4Ptr->ActiveSEP++; 2938c2ecf20Sopenharmony_ci IOCPage4Ptr->SEP[ii].SEPTargetID = id; 2948c2ecf20Sopenharmony_ci IOCPage4Ptr->SEP[ii].SEPBus = channel; 2958c2ecf20Sopenharmony_ci pReq->Header = IOCPage4Ptr->Header; 2968c2ecf20Sopenharmony_ci pReq->PageAddress = cpu_to_le32(id | (channel << 8 )); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci /* Add a SGE to the config request. 2998c2ecf20Sopenharmony_ci */ 3008c2ecf20Sopenharmony_ci flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE | 3018c2ecf20Sopenharmony_ci (IOCPage4Ptr->Header.PageLength + ii) * 4; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT 3068c2ecf20Sopenharmony_ci "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n", 3078c2ecf20Sopenharmony_ci ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel)); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci mpt_put_msg_frame(ioc->DoneCtx, ioc, mf); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci return 0; 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci/** 3158c2ecf20Sopenharmony_ci * mptspi_initTarget - Target, LUN alloc/free functionality. 3168c2ecf20Sopenharmony_ci * @hd: Pointer to MPT_SCSI_HOST structure 3178c2ecf20Sopenharmony_ci * @vtarget: per target private data 3188c2ecf20Sopenharmony_ci * @sdev: SCSI device 3198c2ecf20Sopenharmony_ci * 3208c2ecf20Sopenharmony_ci * NOTE: It's only SAFE to call this routine if data points to 3218c2ecf20Sopenharmony_ci * sane & valid STANDARD INQUIRY data! 3228c2ecf20Sopenharmony_ci * 3238c2ecf20Sopenharmony_ci * Allocate and initialize memory for this target. 3248c2ecf20Sopenharmony_ci * Save inquiry data. 3258c2ecf20Sopenharmony_ci * 3268c2ecf20Sopenharmony_ci **/ 3278c2ecf20Sopenharmony_cistatic void 3288c2ecf20Sopenharmony_cimptspi_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget, 3298c2ecf20Sopenharmony_ci struct scsi_device *sdev) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* Is LUN supported? If so, upper 2 bits will be 0 3338c2ecf20Sopenharmony_ci * in first byte of inquiry data. 3348c2ecf20Sopenharmony_ci */ 3358c2ecf20Sopenharmony_ci if (sdev->inq_periph_qual != 0) 3368c2ecf20Sopenharmony_ci return; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci if (vtarget == NULL) 3398c2ecf20Sopenharmony_ci return; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci vtarget->type = sdev->type; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci if ((sdev->type == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) { 3448c2ecf20Sopenharmony_ci /* Treat all Processors as SAF-TE if 3458c2ecf20Sopenharmony_ci * command line option is set */ 3468c2ecf20Sopenharmony_ci vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED; 3478c2ecf20Sopenharmony_ci mptspi_writeIOCPage4(hd, vtarget->channel, vtarget->id); 3488c2ecf20Sopenharmony_ci }else if ((sdev->type == TYPE_PROCESSOR) && 3498c2ecf20Sopenharmony_ci !(vtarget->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) { 3508c2ecf20Sopenharmony_ci if (sdev->inquiry_len > 49 ) { 3518c2ecf20Sopenharmony_ci if (sdev->inquiry[44] == 'S' && 3528c2ecf20Sopenharmony_ci sdev->inquiry[45] == 'A' && 3538c2ecf20Sopenharmony_ci sdev->inquiry[46] == 'F' && 3548c2ecf20Sopenharmony_ci sdev->inquiry[47] == '-' && 3558c2ecf20Sopenharmony_ci sdev->inquiry[48] == 'T' && 3568c2ecf20Sopenharmony_ci sdev->inquiry[49] == 'E' ) { 3578c2ecf20Sopenharmony_ci vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED; 3588c2ecf20Sopenharmony_ci mptspi_writeIOCPage4(hd, vtarget->channel, vtarget->id); 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci mptspi_setTargetNegoParms(hd, vtarget, sdev); 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci/** 3668c2ecf20Sopenharmony_ci * mptspi_is_raid - Determines whether target is belonging to volume 3678c2ecf20Sopenharmony_ci * @hd: Pointer to a SCSI HOST structure 3688c2ecf20Sopenharmony_ci * @id: target device id 3698c2ecf20Sopenharmony_ci * 3708c2ecf20Sopenharmony_ci * Return: 3718c2ecf20Sopenharmony_ci * non-zero = true 3728c2ecf20Sopenharmony_ci * zero = false 3738c2ecf20Sopenharmony_ci * 3748c2ecf20Sopenharmony_ci */ 3758c2ecf20Sopenharmony_cistatic int 3768c2ecf20Sopenharmony_cimptspi_is_raid(struct _MPT_SCSI_HOST *hd, u32 id) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci int i, rc = 0; 3798c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc = hd->ioc; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci if (!ioc->raid_data.pIocPg2) 3828c2ecf20Sopenharmony_ci goto out; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (!ioc->raid_data.pIocPg2->NumActiveVolumes) 3858c2ecf20Sopenharmony_ci goto out; 3868c2ecf20Sopenharmony_ci for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { 3878c2ecf20Sopenharmony_ci if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) { 3888c2ecf20Sopenharmony_ci rc = 1; 3898c2ecf20Sopenharmony_ci goto out; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci out: 3948c2ecf20Sopenharmony_ci return rc; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic int mptspi_target_alloc(struct scsi_target *starget) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci struct Scsi_Host *shost = dev_to_shost(&starget->dev); 4008c2ecf20Sopenharmony_ci struct _MPT_SCSI_HOST *hd = shost_priv(shost); 4018c2ecf20Sopenharmony_ci VirtTarget *vtarget; 4028c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (hd == NULL) 4058c2ecf20Sopenharmony_ci return -ENODEV; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci ioc = hd->ioc; 4088c2ecf20Sopenharmony_ci vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL); 4098c2ecf20Sopenharmony_ci if (!vtarget) 4108c2ecf20Sopenharmony_ci return -ENOMEM; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci vtarget->ioc_id = ioc->id; 4138c2ecf20Sopenharmony_ci vtarget->tflags = MPT_TARGET_FLAGS_Q_YES; 4148c2ecf20Sopenharmony_ci vtarget->id = (u8)starget->id; 4158c2ecf20Sopenharmony_ci vtarget->channel = (u8)starget->channel; 4168c2ecf20Sopenharmony_ci vtarget->starget = starget; 4178c2ecf20Sopenharmony_ci starget->hostdata = vtarget; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (starget->channel == 1) { 4208c2ecf20Sopenharmony_ci if (mptscsih_is_phys_disk(ioc, 0, starget->id) == 0) 4218c2ecf20Sopenharmony_ci return 0; 4228c2ecf20Sopenharmony_ci vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; 4238c2ecf20Sopenharmony_ci /* The real channel for this device is zero */ 4248c2ecf20Sopenharmony_ci vtarget->channel = 0; 4258c2ecf20Sopenharmony_ci /* The actual physdisknum (for RAID passthrough) */ 4268c2ecf20Sopenharmony_ci vtarget->id = mptscsih_raid_id_to_num(ioc, 0, 4278c2ecf20Sopenharmony_ci starget->id); 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci if (starget->channel == 0 && 4318c2ecf20Sopenharmony_ci mptspi_is_raid(hd, starget->id)) { 4328c2ecf20Sopenharmony_ci vtarget->raidVolume = 1; 4338c2ecf20Sopenharmony_ci ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT 4348c2ecf20Sopenharmony_ci "RAID Volume @ channel=%d id=%d\n", ioc->name, starget->channel, 4358c2ecf20Sopenharmony_ci starget->id)); 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci if (ioc->spi_data.nvram && 4398c2ecf20Sopenharmony_ci ioc->spi_data.nvram[starget->id] != MPT_HOST_NVRAM_INVALID) { 4408c2ecf20Sopenharmony_ci u32 nvram = ioc->spi_data.nvram[starget->id]; 4418c2ecf20Sopenharmony_ci spi_min_period(starget) = (nvram & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT; 4428c2ecf20Sopenharmony_ci spi_max_width(starget) = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1; 4438c2ecf20Sopenharmony_ci } else { 4448c2ecf20Sopenharmony_ci spi_min_period(starget) = ioc->spi_data.minSyncFactor; 4458c2ecf20Sopenharmony_ci spi_max_width(starget) = ioc->spi_data.maxBusWidth; 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci spi_max_offset(starget) = ioc->spi_data.maxSyncOffset; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci spi_offset(starget) = 0; 4508c2ecf20Sopenharmony_ci spi_period(starget) = 0xFF; 4518c2ecf20Sopenharmony_ci mptspi_write_width(starget, 0); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci return 0; 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_cistatic void 4578c2ecf20Sopenharmony_cimptspi_target_destroy(struct scsi_target *starget) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci kfree(starget->hostdata); 4608c2ecf20Sopenharmony_ci starget->hostdata = NULL; 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci/** 4648c2ecf20Sopenharmony_ci * mptspi_print_write_nego - negotiation parameters debug info that is being sent 4658c2ecf20Sopenharmony_ci * @hd: Pointer to a SCSI HOST structure 4668c2ecf20Sopenharmony_ci * @starget: SCSI target 4678c2ecf20Sopenharmony_ci * @ii: negotiation parameters 4688c2ecf20Sopenharmony_ci * 4698c2ecf20Sopenharmony_ci */ 4708c2ecf20Sopenharmony_cistatic void 4718c2ecf20Sopenharmony_cimptspi_print_write_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u32 ii) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d Requested = 0x%08x" 4748c2ecf20Sopenharmony_ci " ( %s factor = 0x%02x @ offset = 0x%02x %s%s%s%s%s%s%s%s)\n", 4758c2ecf20Sopenharmony_ci hd->ioc->name, starget->id, ii, 4768c2ecf20Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_WIDE ? "Wide ": "", 4778c2ecf20Sopenharmony_ci ((ii >> 8) & 0xFF), ((ii >> 16) & 0xFF), 4788c2ecf20Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_IU ? "IU ": "", 4798c2ecf20Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_DT ? "DT ": "", 4808c2ecf20Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_QAS ? "QAS ": "", 4818c2ecf20Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_HOLD_MCS ? "HOLDMCS ": "", 4828c2ecf20Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_WR_FLOW ? "WRFLOW ": "", 4838c2ecf20Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_RD_STRM ? "RDSTRM ": "", 4848c2ecf20Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_RTI ? "RTI ": "", 4858c2ecf20Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": "")); 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci/** 4898c2ecf20Sopenharmony_ci * mptspi_print_read_nego - negotiation parameters debug info that is being read 4908c2ecf20Sopenharmony_ci * @hd: Pointer to a SCSI HOST structure 4918c2ecf20Sopenharmony_ci * @starget: SCSI target 4928c2ecf20Sopenharmony_ci * @ii: negotiation parameters 4938c2ecf20Sopenharmony_ci * 4948c2ecf20Sopenharmony_ci */ 4958c2ecf20Sopenharmony_cistatic void 4968c2ecf20Sopenharmony_cimptspi_print_read_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u32 ii) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d Read = 0x%08x" 4998c2ecf20Sopenharmony_ci " ( %s factor = 0x%02x @ offset = 0x%02x %s%s%s%s%s%s%s%s)\n", 5008c2ecf20Sopenharmony_ci hd->ioc->name, starget->id, ii, 5018c2ecf20Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_WIDE ? "Wide ": "", 5028c2ecf20Sopenharmony_ci ((ii >> 8) & 0xFF), ((ii >> 16) & 0xFF), 5038c2ecf20Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_IU ? "IU ": "", 5048c2ecf20Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_DT ? "DT ": "", 5058c2ecf20Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_QAS ? "QAS ": "", 5068c2ecf20Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_HOLD_MCS ? "HOLDMCS ": "", 5078c2ecf20Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_WR_FLOW ? "WRFLOW ": "", 5088c2ecf20Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_RD_STRM ? "RDSTRM ": "", 5098c2ecf20Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_RTI ? "RTI ": "", 5108c2ecf20Sopenharmony_ci ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": "")); 5118c2ecf20Sopenharmony_ci} 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_cistatic int mptspi_read_spi_device_pg0(struct scsi_target *starget, 5148c2ecf20Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_0 *pass_pg0) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci struct Scsi_Host *shost = dev_to_shost(&starget->dev); 5178c2ecf20Sopenharmony_ci struct _MPT_SCSI_HOST *hd = shost_priv(shost); 5188c2ecf20Sopenharmony_ci struct _MPT_ADAPTER *ioc = hd->ioc; 5198c2ecf20Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_0 *spi_dev_pg0; 5208c2ecf20Sopenharmony_ci dma_addr_t spi_dev_pg0_dma; 5218c2ecf20Sopenharmony_ci int size; 5228c2ecf20Sopenharmony_ci struct _x_config_parms cfg; 5238c2ecf20Sopenharmony_ci struct _CONFIG_PAGE_HEADER hdr; 5248c2ecf20Sopenharmony_ci int err = -EBUSY; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci /* No SPI parameters for RAID devices */ 5278c2ecf20Sopenharmony_ci if (starget->channel == 0 && 5288c2ecf20Sopenharmony_ci mptspi_is_raid(hd, starget->id)) 5298c2ecf20Sopenharmony_ci return -1; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci size = ioc->spi_data.sdp0length * 4; 5328c2ecf20Sopenharmony_ci /* 5338c2ecf20Sopenharmony_ci if (ioc->spi_data.sdp0length & 1) 5348c2ecf20Sopenharmony_ci size += size + 4; 5358c2ecf20Sopenharmony_ci size += 2048; 5368c2ecf20Sopenharmony_ci */ 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci spi_dev_pg0 = dma_alloc_coherent(&ioc->pcidev->dev, size, &spi_dev_pg0_dma, GFP_KERNEL); 5398c2ecf20Sopenharmony_ci if (spi_dev_pg0 == NULL) { 5408c2ecf20Sopenharmony_ci starget_printk(KERN_ERR, starget, MYIOC_s_FMT 5418c2ecf20Sopenharmony_ci "dma_alloc_coherent for parameters failed\n", ioc->name); 5428c2ecf20Sopenharmony_ci return -EINVAL; 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci memset(&hdr, 0, sizeof(hdr)); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci hdr.PageVersion = ioc->spi_data.sdp0version; 5488c2ecf20Sopenharmony_ci hdr.PageLength = ioc->spi_data.sdp0length; 5498c2ecf20Sopenharmony_ci hdr.PageNumber = 0; 5508c2ecf20Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci memset(&cfg, 0, sizeof(cfg)); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci cfg.cfghdr.hdr = &hdr; 5558c2ecf20Sopenharmony_ci cfg.physAddr = spi_dev_pg0_dma; 5568c2ecf20Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 5578c2ecf20Sopenharmony_ci cfg.dir = 0; 5588c2ecf20Sopenharmony_ci cfg.pageAddr = starget->id; 5598c2ecf20Sopenharmony_ci cfg.timeout = 60; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci if (mpt_config(ioc, &cfg)) { 5628c2ecf20Sopenharmony_ci starget_printk(KERN_ERR, starget, MYIOC_s_FMT "mpt_config failed\n", ioc->name); 5638c2ecf20Sopenharmony_ci goto out_free; 5648c2ecf20Sopenharmony_ci } 5658c2ecf20Sopenharmony_ci err = 0; 5668c2ecf20Sopenharmony_ci memcpy(pass_pg0, spi_dev_pg0, size); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci mptspi_print_read_nego(hd, starget, le32_to_cpu(spi_dev_pg0->NegotiatedParameters)); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci out_free: 5718c2ecf20Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, size, spi_dev_pg0, spi_dev_pg0_dma); 5728c2ecf20Sopenharmony_ci return err; 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_cistatic u32 mptspi_getRP(struct scsi_target *starget) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci u32 nego = 0; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci nego |= spi_iu(starget) ? MPI_SCSIDEVPAGE1_RP_IU : 0; 5808c2ecf20Sopenharmony_ci nego |= spi_dt(starget) ? MPI_SCSIDEVPAGE1_RP_DT : 0; 5818c2ecf20Sopenharmony_ci nego |= spi_qas(starget) ? MPI_SCSIDEVPAGE1_RP_QAS : 0; 5828c2ecf20Sopenharmony_ci nego |= spi_hold_mcs(starget) ? MPI_SCSIDEVPAGE1_RP_HOLD_MCS : 0; 5838c2ecf20Sopenharmony_ci nego |= spi_wr_flow(starget) ? MPI_SCSIDEVPAGE1_RP_WR_FLOW : 0; 5848c2ecf20Sopenharmony_ci nego |= spi_rd_strm(starget) ? MPI_SCSIDEVPAGE1_RP_RD_STRM : 0; 5858c2ecf20Sopenharmony_ci nego |= spi_rti(starget) ? MPI_SCSIDEVPAGE1_RP_RTI : 0; 5868c2ecf20Sopenharmony_ci nego |= spi_pcomp_en(starget) ? MPI_SCSIDEVPAGE1_RP_PCOMP_EN : 0; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci nego |= (spi_period(starget) << MPI_SCSIDEVPAGE1_RP_SHIFT_MIN_SYNC_PERIOD) & MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK; 5898c2ecf20Sopenharmony_ci nego |= (spi_offset(starget) << MPI_SCSIDEVPAGE1_RP_SHIFT_MAX_SYNC_OFFSET) & MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK; 5908c2ecf20Sopenharmony_ci nego |= spi_width(starget) ? MPI_SCSIDEVPAGE1_RP_WIDE : 0; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci return nego; 5938c2ecf20Sopenharmony_ci} 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_cistatic void mptspi_read_parameters(struct scsi_target *starget) 5968c2ecf20Sopenharmony_ci{ 5978c2ecf20Sopenharmony_ci int nego; 5988c2ecf20Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_0 spi_dev_pg0; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci mptspi_read_spi_device_pg0(starget, &spi_dev_pg0); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci nego = le32_to_cpu(spi_dev_pg0.NegotiatedParameters); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci spi_iu(starget) = (nego & MPI_SCSIDEVPAGE0_NP_IU) ? 1 : 0; 6058c2ecf20Sopenharmony_ci spi_dt(starget) = (nego & MPI_SCSIDEVPAGE0_NP_DT) ? 1 : 0; 6068c2ecf20Sopenharmony_ci spi_qas(starget) = (nego & MPI_SCSIDEVPAGE0_NP_QAS) ? 1 : 0; 6078c2ecf20Sopenharmony_ci spi_wr_flow(starget) = (nego & MPI_SCSIDEVPAGE0_NP_WR_FLOW) ? 1 : 0; 6088c2ecf20Sopenharmony_ci spi_rd_strm(starget) = (nego & MPI_SCSIDEVPAGE0_NP_RD_STRM) ? 1 : 0; 6098c2ecf20Sopenharmony_ci spi_rti(starget) = (nego & MPI_SCSIDEVPAGE0_NP_RTI) ? 1 : 0; 6108c2ecf20Sopenharmony_ci spi_pcomp_en(starget) = (nego & MPI_SCSIDEVPAGE0_NP_PCOMP_EN) ? 1 : 0; 6118c2ecf20Sopenharmony_ci spi_hold_mcs(starget) = (nego & MPI_SCSIDEVPAGE0_NP_HOLD_MCS) ? 1 : 0; 6128c2ecf20Sopenharmony_ci spi_period(starget) = (nego & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> MPI_SCSIDEVPAGE0_NP_SHIFT_SYNC_PERIOD; 6138c2ecf20Sopenharmony_ci spi_offset(starget) = (nego & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) >> MPI_SCSIDEVPAGE0_NP_SHIFT_SYNC_OFFSET; 6148c2ecf20Sopenharmony_ci spi_width(starget) = (nego & MPI_SCSIDEVPAGE0_NP_WIDE) ? 1 : 0; 6158c2ecf20Sopenharmony_ci} 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_cistatic int 6188c2ecf20Sopenharmony_cimptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc = hd->ioc; 6218c2ecf20Sopenharmony_ci MpiRaidActionRequest_t *pReq; 6228c2ecf20Sopenharmony_ci MPT_FRAME_HDR *mf; 6238c2ecf20Sopenharmony_ci int ret; 6248c2ecf20Sopenharmony_ci unsigned long timeleft; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci mutex_lock(&ioc->internal_cmds.mutex); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci /* Get and Populate a free Frame 6298c2ecf20Sopenharmony_ci */ 6308c2ecf20Sopenharmony_ci if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) { 6318c2ecf20Sopenharmony_ci dfailprintk(hd->ioc, printk(MYIOC_s_WARN_FMT 6328c2ecf20Sopenharmony_ci "%s: no msg frames!\n", ioc->name, __func__)); 6338c2ecf20Sopenharmony_ci ret = -EAGAIN; 6348c2ecf20Sopenharmony_ci goto out; 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci pReq = (MpiRaidActionRequest_t *)mf; 6378c2ecf20Sopenharmony_ci if (quiesce) 6388c2ecf20Sopenharmony_ci pReq->Action = MPI_RAID_ACTION_QUIESCE_PHYS_IO; 6398c2ecf20Sopenharmony_ci else 6408c2ecf20Sopenharmony_ci pReq->Action = MPI_RAID_ACTION_ENABLE_PHYS_IO; 6418c2ecf20Sopenharmony_ci pReq->Reserved1 = 0; 6428c2ecf20Sopenharmony_ci pReq->ChainOffset = 0; 6438c2ecf20Sopenharmony_ci pReq->Function = MPI_FUNCTION_RAID_ACTION; 6448c2ecf20Sopenharmony_ci pReq->VolumeID = id; 6458c2ecf20Sopenharmony_ci pReq->VolumeBus = channel; 6468c2ecf20Sopenharmony_ci pReq->PhysDiskNum = 0; 6478c2ecf20Sopenharmony_ci pReq->MsgFlags = 0; 6488c2ecf20Sopenharmony_ci pReq->Reserved2 = 0; 6498c2ecf20Sopenharmony_ci pReq->ActionDataWord = 0; /* Reserved for this action */ 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci ioc->add_sge((char *)&pReq->ActionDataSGE, 6528c2ecf20Sopenharmony_ci MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n", 6558c2ecf20Sopenharmony_ci ioc->name, pReq->Action, channel, id)); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status) 6588c2ecf20Sopenharmony_ci mpt_put_msg_frame(ioc->InternalCtx, ioc, mf); 6598c2ecf20Sopenharmony_ci timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done, 10*HZ); 6608c2ecf20Sopenharmony_ci if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { 6618c2ecf20Sopenharmony_ci ret = -ETIME; 6628c2ecf20Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: TIMED OUT!\n", 6638c2ecf20Sopenharmony_ci ioc->name, __func__)); 6648c2ecf20Sopenharmony_ci if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) 6658c2ecf20Sopenharmony_ci goto out; 6668c2ecf20Sopenharmony_ci if (!timeleft) { 6678c2ecf20Sopenharmony_ci printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", 6688c2ecf20Sopenharmony_ci ioc->name, __func__); 6698c2ecf20Sopenharmony_ci mpt_HardResetHandler(ioc, CAN_SLEEP); 6708c2ecf20Sopenharmony_ci mpt_free_msg_frame(ioc, mf); 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci goto out; 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci ret = ioc->internal_cmds.completion_code; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci out: 6788c2ecf20Sopenharmony_ci CLEAR_MGMT_STATUS(ioc->internal_cmds.status) 6798c2ecf20Sopenharmony_ci mutex_unlock(&ioc->internal_cmds.mutex); 6808c2ecf20Sopenharmony_ci return ret; 6818c2ecf20Sopenharmony_ci} 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_cistatic void mptspi_dv_device(struct _MPT_SCSI_HOST *hd, 6848c2ecf20Sopenharmony_ci struct scsi_device *sdev) 6858c2ecf20Sopenharmony_ci{ 6868c2ecf20Sopenharmony_ci VirtTarget *vtarget = scsi_target(sdev)->hostdata; 6878c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc = hd->ioc; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci /* no DV on RAID devices */ 6908c2ecf20Sopenharmony_ci if (sdev->channel == 0 && 6918c2ecf20Sopenharmony_ci mptspi_is_raid(hd, sdev->id)) 6928c2ecf20Sopenharmony_ci return; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci /* If this is a piece of a RAID, then quiesce first */ 6958c2ecf20Sopenharmony_ci if (sdev->channel == 1 && 6968c2ecf20Sopenharmony_ci mptscsih_quiesce_raid(hd, 1, vtarget->channel, vtarget->id) < 0) { 6978c2ecf20Sopenharmony_ci starget_printk(KERN_ERR, scsi_target(sdev), MYIOC_s_FMT 6988c2ecf20Sopenharmony_ci "Integrated RAID quiesce failed\n", ioc->name); 6998c2ecf20Sopenharmony_ci return; 7008c2ecf20Sopenharmony_ci } 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci hd->spi_pending |= (1 << sdev->id); 7038c2ecf20Sopenharmony_ci spi_dv_device(sdev); 7048c2ecf20Sopenharmony_ci hd->spi_pending &= ~(1 << sdev->id); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci if (sdev->channel == 1 && 7078c2ecf20Sopenharmony_ci mptscsih_quiesce_raid(hd, 0, vtarget->channel, vtarget->id) < 0) 7088c2ecf20Sopenharmony_ci starget_printk(KERN_ERR, scsi_target(sdev), MYIOC_s_FMT 7098c2ecf20Sopenharmony_ci "Integrated RAID resume failed\n", ioc->name); 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci mptspi_read_parameters(sdev->sdev_target); 7128c2ecf20Sopenharmony_ci spi_display_xfer_agreement(sdev->sdev_target); 7138c2ecf20Sopenharmony_ci mptspi_read_parameters(sdev->sdev_target); 7148c2ecf20Sopenharmony_ci} 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_cistatic int mptspi_slave_alloc(struct scsi_device *sdev) 7178c2ecf20Sopenharmony_ci{ 7188c2ecf20Sopenharmony_ci MPT_SCSI_HOST *hd = shost_priv(sdev->host); 7198c2ecf20Sopenharmony_ci VirtTarget *vtarget; 7208c2ecf20Sopenharmony_ci VirtDevice *vdevice; 7218c2ecf20Sopenharmony_ci struct scsi_target *starget; 7228c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc = hd->ioc; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci if (sdev->channel == 1 && 7258c2ecf20Sopenharmony_ci mptscsih_is_phys_disk(ioc, 0, sdev->id) == 0) 7268c2ecf20Sopenharmony_ci return -ENXIO; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL); 7298c2ecf20Sopenharmony_ci if (!vdevice) { 7308c2ecf20Sopenharmony_ci printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", 7318c2ecf20Sopenharmony_ci ioc->name, sizeof(VirtDevice)); 7328c2ecf20Sopenharmony_ci return -ENOMEM; 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci vdevice->lun = sdev->lun; 7368c2ecf20Sopenharmony_ci sdev->hostdata = vdevice; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci starget = scsi_target(sdev); 7398c2ecf20Sopenharmony_ci vtarget = starget->hostdata; 7408c2ecf20Sopenharmony_ci vdevice->vtarget = vtarget; 7418c2ecf20Sopenharmony_ci vtarget->num_luns++; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci if (sdev->channel == 1) 7448c2ecf20Sopenharmony_ci sdev->no_uld_attach = 1; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci return 0; 7478c2ecf20Sopenharmony_ci} 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_cistatic int mptspi_slave_configure(struct scsi_device *sdev) 7508c2ecf20Sopenharmony_ci{ 7518c2ecf20Sopenharmony_ci struct _MPT_SCSI_HOST *hd = shost_priv(sdev->host); 7528c2ecf20Sopenharmony_ci VirtTarget *vtarget = scsi_target(sdev)->hostdata; 7538c2ecf20Sopenharmony_ci int ret; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci mptspi_initTarget(hd, vtarget, sdev); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci ret = mptscsih_slave_configure(sdev); 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci if (ret) 7608c2ecf20Sopenharmony_ci return ret; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d min_period=0x%02x" 7638c2ecf20Sopenharmony_ci " max_offset=0x%02x max_width=%d\n", hd->ioc->name, 7648c2ecf20Sopenharmony_ci sdev->id, spi_min_period(scsi_target(sdev)), 7658c2ecf20Sopenharmony_ci spi_max_offset(scsi_target(sdev)), 7668c2ecf20Sopenharmony_ci spi_max_width(scsi_target(sdev)))); 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci if ((sdev->channel == 1 || 7698c2ecf20Sopenharmony_ci !(mptspi_is_raid(hd, sdev->id))) && 7708c2ecf20Sopenharmony_ci !spi_initial_dv(sdev->sdev_target)) 7718c2ecf20Sopenharmony_ci mptspi_dv_device(hd, sdev); 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci return 0; 7748c2ecf20Sopenharmony_ci} 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_cistatic int 7778c2ecf20Sopenharmony_cimptspi_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt) 7788c2ecf20Sopenharmony_ci{ 7798c2ecf20Sopenharmony_ci struct _MPT_SCSI_HOST *hd = shost_priv(shost); 7808c2ecf20Sopenharmony_ci VirtDevice *vdevice = SCpnt->device->hostdata; 7818c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc = hd->ioc; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci if (!vdevice || !vdevice->vtarget) { 7848c2ecf20Sopenharmony_ci SCpnt->result = DID_NO_CONNECT << 16; 7858c2ecf20Sopenharmony_ci SCpnt->scsi_done(SCpnt); 7868c2ecf20Sopenharmony_ci return 0; 7878c2ecf20Sopenharmony_ci } 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci if (SCpnt->device->channel == 1 && 7908c2ecf20Sopenharmony_ci mptscsih_is_phys_disk(ioc, 0, SCpnt->device->id) == 0) { 7918c2ecf20Sopenharmony_ci SCpnt->result = DID_NO_CONNECT << 16; 7928c2ecf20Sopenharmony_ci SCpnt->scsi_done(SCpnt); 7938c2ecf20Sopenharmony_ci return 0; 7948c2ecf20Sopenharmony_ci } 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci if (spi_dv_pending(scsi_target(SCpnt->device))) 7978c2ecf20Sopenharmony_ci ddvprintk(ioc, scsi_print_command(SCpnt)); 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci return mptscsih_qcmd(SCpnt); 8008c2ecf20Sopenharmony_ci} 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_cistatic void mptspi_slave_destroy(struct scsi_device *sdev) 8038c2ecf20Sopenharmony_ci{ 8048c2ecf20Sopenharmony_ci struct scsi_target *starget = scsi_target(sdev); 8058c2ecf20Sopenharmony_ci VirtTarget *vtarget = starget->hostdata; 8068c2ecf20Sopenharmony_ci VirtDevice *vdevice = sdev->hostdata; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci /* Will this be the last lun on a non-raid device? */ 8098c2ecf20Sopenharmony_ci if (vtarget->num_luns == 1 && vdevice->configured_lun) { 8108c2ecf20Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci /* Async Narrow */ 8138c2ecf20Sopenharmony_ci pg1.RequestedParameters = 0; 8148c2ecf20Sopenharmony_ci pg1.Reserved = 0; 8158c2ecf20Sopenharmony_ci pg1.Configuration = 0; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci mptspi_write_spi_device_pg1(starget, &pg1); 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci mptscsih_slave_destroy(sdev); 8218c2ecf20Sopenharmony_ci} 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_cistatic struct scsi_host_template mptspi_driver_template = { 8248c2ecf20Sopenharmony_ci .module = THIS_MODULE, 8258c2ecf20Sopenharmony_ci .proc_name = "mptspi", 8268c2ecf20Sopenharmony_ci .show_info = mptscsih_show_info, 8278c2ecf20Sopenharmony_ci .name = "MPT SPI Host", 8288c2ecf20Sopenharmony_ci .info = mptscsih_info, 8298c2ecf20Sopenharmony_ci .queuecommand = mptspi_qcmd, 8308c2ecf20Sopenharmony_ci .target_alloc = mptspi_target_alloc, 8318c2ecf20Sopenharmony_ci .slave_alloc = mptspi_slave_alloc, 8328c2ecf20Sopenharmony_ci .slave_configure = mptspi_slave_configure, 8338c2ecf20Sopenharmony_ci .target_destroy = mptspi_target_destroy, 8348c2ecf20Sopenharmony_ci .slave_destroy = mptspi_slave_destroy, 8358c2ecf20Sopenharmony_ci .change_queue_depth = mptscsih_change_queue_depth, 8368c2ecf20Sopenharmony_ci .eh_abort_handler = mptscsih_abort, 8378c2ecf20Sopenharmony_ci .eh_device_reset_handler = mptscsih_dev_reset, 8388c2ecf20Sopenharmony_ci .eh_bus_reset_handler = mptscsih_bus_reset, 8398c2ecf20Sopenharmony_ci .eh_host_reset_handler = mptscsih_host_reset, 8408c2ecf20Sopenharmony_ci .bios_param = mptscsih_bios_param, 8418c2ecf20Sopenharmony_ci .can_queue = MPT_SCSI_CAN_QUEUE, 8428c2ecf20Sopenharmony_ci .this_id = -1, 8438c2ecf20Sopenharmony_ci .sg_tablesize = MPT_SCSI_SG_DEPTH, 8448c2ecf20Sopenharmony_ci .max_sectors = 8192, 8458c2ecf20Sopenharmony_ci .cmd_per_lun = 7, 8468c2ecf20Sopenharmony_ci .shost_attrs = mptscsih_host_attrs, 8478c2ecf20Sopenharmony_ci}; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_cistatic int mptspi_write_spi_device_pg1(struct scsi_target *starget, 8508c2ecf20Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_1 *pass_pg1) 8518c2ecf20Sopenharmony_ci{ 8528c2ecf20Sopenharmony_ci struct Scsi_Host *shost = dev_to_shost(&starget->dev); 8538c2ecf20Sopenharmony_ci struct _MPT_SCSI_HOST *hd = shost_priv(shost); 8548c2ecf20Sopenharmony_ci struct _MPT_ADAPTER *ioc = hd->ioc; 8558c2ecf20Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_1 *pg1; 8568c2ecf20Sopenharmony_ci dma_addr_t pg1_dma; 8578c2ecf20Sopenharmony_ci int size; 8588c2ecf20Sopenharmony_ci struct _x_config_parms cfg; 8598c2ecf20Sopenharmony_ci struct _CONFIG_PAGE_HEADER hdr; 8608c2ecf20Sopenharmony_ci int err = -EBUSY; 8618c2ecf20Sopenharmony_ci u32 nego_parms; 8628c2ecf20Sopenharmony_ci u32 period; 8638c2ecf20Sopenharmony_ci struct scsi_device *sdev; 8648c2ecf20Sopenharmony_ci int i; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci /* don't allow updating nego parameters on RAID devices */ 8678c2ecf20Sopenharmony_ci if (starget->channel == 0 && 8688c2ecf20Sopenharmony_ci mptspi_is_raid(hd, starget->id)) 8698c2ecf20Sopenharmony_ci return -1; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci size = ioc->spi_data.sdp1length * 4; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci pg1 = dma_alloc_coherent(&ioc->pcidev->dev, size, &pg1_dma, GFP_KERNEL); 8748c2ecf20Sopenharmony_ci if (pg1 == NULL) { 8758c2ecf20Sopenharmony_ci starget_printk(KERN_ERR, starget, MYIOC_s_FMT 8768c2ecf20Sopenharmony_ci "dma_alloc_coherent for parameters failed\n", ioc->name); 8778c2ecf20Sopenharmony_ci return -EINVAL; 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci memset(&hdr, 0, sizeof(hdr)); 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci hdr.PageVersion = ioc->spi_data.sdp1version; 8838c2ecf20Sopenharmony_ci hdr.PageLength = ioc->spi_data.sdp1length; 8848c2ecf20Sopenharmony_ci hdr.PageNumber = 1; 8858c2ecf20Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci memset(&cfg, 0, sizeof(cfg)); 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci cfg.cfghdr.hdr = &hdr; 8908c2ecf20Sopenharmony_ci cfg.physAddr = pg1_dma; 8918c2ecf20Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; 8928c2ecf20Sopenharmony_ci cfg.dir = 1; 8938c2ecf20Sopenharmony_ci cfg.pageAddr = starget->id; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci memcpy(pg1, pass_pg1, size); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci pg1->Header.PageVersion = hdr.PageVersion; 8988c2ecf20Sopenharmony_ci pg1->Header.PageLength = hdr.PageLength; 8998c2ecf20Sopenharmony_ci pg1->Header.PageNumber = hdr.PageNumber; 9008c2ecf20Sopenharmony_ci pg1->Header.PageType = hdr.PageType; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci nego_parms = le32_to_cpu(pg1->RequestedParameters); 9038c2ecf20Sopenharmony_ci period = (nego_parms & MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK) >> 9048c2ecf20Sopenharmony_ci MPI_SCSIDEVPAGE1_RP_SHIFT_MIN_SYNC_PERIOD; 9058c2ecf20Sopenharmony_ci if (period == 8) { 9068c2ecf20Sopenharmony_ci /* Turn on inline data padding for TAPE when running U320 */ 9078c2ecf20Sopenharmony_ci for (i = 0 ; i < 16; i++) { 9088c2ecf20Sopenharmony_ci sdev = scsi_device_lookup_by_target(starget, i); 9098c2ecf20Sopenharmony_ci if (sdev && sdev->type == TYPE_TAPE) { 9108c2ecf20Sopenharmony_ci sdev_printk(KERN_DEBUG, sdev, MYIOC_s_FMT 9118c2ecf20Sopenharmony_ci "IDP:ON\n", ioc->name); 9128c2ecf20Sopenharmony_ci nego_parms |= MPI_SCSIDEVPAGE1_RP_IDP; 9138c2ecf20Sopenharmony_ci pg1->RequestedParameters = 9148c2ecf20Sopenharmony_ci cpu_to_le32(nego_parms); 9158c2ecf20Sopenharmony_ci break; 9168c2ecf20Sopenharmony_ci } 9178c2ecf20Sopenharmony_ci } 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci mptspi_print_write_nego(hd, starget, le32_to_cpu(pg1->RequestedParameters)); 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci if (mpt_config(ioc, &cfg)) { 9238c2ecf20Sopenharmony_ci starget_printk(KERN_ERR, starget, MYIOC_s_FMT 9248c2ecf20Sopenharmony_ci "mpt_config failed\n", ioc->name); 9258c2ecf20Sopenharmony_ci goto out_free; 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci err = 0; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci out_free: 9308c2ecf20Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, size, pg1, pg1_dma); 9318c2ecf20Sopenharmony_ci return err; 9328c2ecf20Sopenharmony_ci} 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_cistatic void mptspi_write_offset(struct scsi_target *starget, int offset) 9358c2ecf20Sopenharmony_ci{ 9368c2ecf20Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; 9378c2ecf20Sopenharmony_ci u32 nego; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci if (offset < 0) 9408c2ecf20Sopenharmony_ci offset = 0; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci if (offset > 255) 9438c2ecf20Sopenharmony_ci offset = 255; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci if (spi_offset(starget) == -1) 9468c2ecf20Sopenharmony_ci mptspi_read_parameters(starget); 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci spi_offset(starget) = offset; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci nego = mptspi_getRP(starget); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci pg1.RequestedParameters = cpu_to_le32(nego); 9538c2ecf20Sopenharmony_ci pg1.Reserved = 0; 9548c2ecf20Sopenharmony_ci pg1.Configuration = 0; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci mptspi_write_spi_device_pg1(starget, &pg1); 9578c2ecf20Sopenharmony_ci} 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_cistatic void mptspi_write_period(struct scsi_target *starget, int period) 9608c2ecf20Sopenharmony_ci{ 9618c2ecf20Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; 9628c2ecf20Sopenharmony_ci u32 nego; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci if (period < 8) 9658c2ecf20Sopenharmony_ci period = 8; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci if (period > 255) 9688c2ecf20Sopenharmony_ci period = 255; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci if (spi_period(starget) == -1) 9718c2ecf20Sopenharmony_ci mptspi_read_parameters(starget); 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci if (period == 8) { 9748c2ecf20Sopenharmony_ci spi_iu(starget) = 1; 9758c2ecf20Sopenharmony_ci spi_dt(starget) = 1; 9768c2ecf20Sopenharmony_ci } else if (period == 9) { 9778c2ecf20Sopenharmony_ci spi_dt(starget) = 1; 9788c2ecf20Sopenharmony_ci } 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci spi_period(starget) = period; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci nego = mptspi_getRP(starget); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci pg1.RequestedParameters = cpu_to_le32(nego); 9858c2ecf20Sopenharmony_ci pg1.Reserved = 0; 9868c2ecf20Sopenharmony_ci pg1.Configuration = 0; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci mptspi_write_spi_device_pg1(starget, &pg1); 9898c2ecf20Sopenharmony_ci} 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_cistatic void mptspi_write_dt(struct scsi_target *starget, int dt) 9928c2ecf20Sopenharmony_ci{ 9938c2ecf20Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; 9948c2ecf20Sopenharmony_ci u32 nego; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci if (spi_period(starget) == -1) 9978c2ecf20Sopenharmony_ci mptspi_read_parameters(starget); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci if (!dt && spi_period(starget) < 10) 10008c2ecf20Sopenharmony_ci spi_period(starget) = 10; 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci spi_dt(starget) = dt; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci nego = mptspi_getRP(starget); 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci pg1.RequestedParameters = cpu_to_le32(nego); 10088c2ecf20Sopenharmony_ci pg1.Reserved = 0; 10098c2ecf20Sopenharmony_ci pg1.Configuration = 0; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci mptspi_write_spi_device_pg1(starget, &pg1); 10128c2ecf20Sopenharmony_ci} 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_cistatic void mptspi_write_iu(struct scsi_target *starget, int iu) 10158c2ecf20Sopenharmony_ci{ 10168c2ecf20Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; 10178c2ecf20Sopenharmony_ci u32 nego; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci if (spi_period(starget) == -1) 10208c2ecf20Sopenharmony_ci mptspi_read_parameters(starget); 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci if (!iu && spi_period(starget) < 9) 10238c2ecf20Sopenharmony_ci spi_period(starget) = 9; 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci spi_iu(starget) = iu; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci nego = mptspi_getRP(starget); 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci pg1.RequestedParameters = cpu_to_le32(nego); 10308c2ecf20Sopenharmony_ci pg1.Reserved = 0; 10318c2ecf20Sopenharmony_ci pg1.Configuration = 0; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci mptspi_write_spi_device_pg1(starget, &pg1); 10348c2ecf20Sopenharmony_ci} 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci#define MPTSPI_SIMPLE_TRANSPORT_PARM(parm) \ 10378c2ecf20Sopenharmony_cistatic void mptspi_write_##parm(struct scsi_target *starget, int parm)\ 10388c2ecf20Sopenharmony_ci{ \ 10398c2ecf20Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; \ 10408c2ecf20Sopenharmony_ci u32 nego; \ 10418c2ecf20Sopenharmony_ci \ 10428c2ecf20Sopenharmony_ci spi_##parm(starget) = parm; \ 10438c2ecf20Sopenharmony_ci \ 10448c2ecf20Sopenharmony_ci nego = mptspi_getRP(starget); \ 10458c2ecf20Sopenharmony_ci \ 10468c2ecf20Sopenharmony_ci pg1.RequestedParameters = cpu_to_le32(nego); \ 10478c2ecf20Sopenharmony_ci pg1.Reserved = 0; \ 10488c2ecf20Sopenharmony_ci pg1.Configuration = 0; \ 10498c2ecf20Sopenharmony_ci \ 10508c2ecf20Sopenharmony_ci mptspi_write_spi_device_pg1(starget, &pg1); \ 10518c2ecf20Sopenharmony_ci} 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ciMPTSPI_SIMPLE_TRANSPORT_PARM(rd_strm) 10548c2ecf20Sopenharmony_ciMPTSPI_SIMPLE_TRANSPORT_PARM(wr_flow) 10558c2ecf20Sopenharmony_ciMPTSPI_SIMPLE_TRANSPORT_PARM(rti) 10568c2ecf20Sopenharmony_ciMPTSPI_SIMPLE_TRANSPORT_PARM(hold_mcs) 10578c2ecf20Sopenharmony_ciMPTSPI_SIMPLE_TRANSPORT_PARM(pcomp_en) 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_cistatic void mptspi_write_qas(struct scsi_target *starget, int qas) 10608c2ecf20Sopenharmony_ci{ 10618c2ecf20Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; 10628c2ecf20Sopenharmony_ci struct Scsi_Host *shost = dev_to_shost(&starget->dev); 10638c2ecf20Sopenharmony_ci struct _MPT_SCSI_HOST *hd = shost_priv(shost); 10648c2ecf20Sopenharmony_ci VirtTarget *vtarget = starget->hostdata; 10658c2ecf20Sopenharmony_ci u32 nego; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci if ((vtarget->negoFlags & MPT_TARGET_NO_NEGO_QAS) || 10688c2ecf20Sopenharmony_ci hd->ioc->spi_data.noQas) 10698c2ecf20Sopenharmony_ci spi_qas(starget) = 0; 10708c2ecf20Sopenharmony_ci else 10718c2ecf20Sopenharmony_ci spi_qas(starget) = qas; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci nego = mptspi_getRP(starget); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci pg1.RequestedParameters = cpu_to_le32(nego); 10768c2ecf20Sopenharmony_ci pg1.Reserved = 0; 10778c2ecf20Sopenharmony_ci pg1.Configuration = 0; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci mptspi_write_spi_device_pg1(starget, &pg1); 10808c2ecf20Sopenharmony_ci} 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_cistatic void mptspi_write_width(struct scsi_target *starget, int width) 10838c2ecf20Sopenharmony_ci{ 10848c2ecf20Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; 10858c2ecf20Sopenharmony_ci u32 nego; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci if (!width) { 10888c2ecf20Sopenharmony_ci spi_dt(starget) = 0; 10898c2ecf20Sopenharmony_ci if (spi_period(starget) < 10) 10908c2ecf20Sopenharmony_ci spi_period(starget) = 10; 10918c2ecf20Sopenharmony_ci } 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci spi_width(starget) = width; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci nego = mptspi_getRP(starget); 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci pg1.RequestedParameters = cpu_to_le32(nego); 10988c2ecf20Sopenharmony_ci pg1.Reserved = 0; 10998c2ecf20Sopenharmony_ci pg1.Configuration = 0; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci mptspi_write_spi_device_pg1(starget, &pg1); 11028c2ecf20Sopenharmony_ci} 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_cistruct work_queue_wrapper { 11058c2ecf20Sopenharmony_ci struct work_struct work; 11068c2ecf20Sopenharmony_ci struct _MPT_SCSI_HOST *hd; 11078c2ecf20Sopenharmony_ci int disk; 11088c2ecf20Sopenharmony_ci}; 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_cistatic void mpt_work_wrapper(struct work_struct *work) 11118c2ecf20Sopenharmony_ci{ 11128c2ecf20Sopenharmony_ci struct work_queue_wrapper *wqw = 11138c2ecf20Sopenharmony_ci container_of(work, struct work_queue_wrapper, work); 11148c2ecf20Sopenharmony_ci struct _MPT_SCSI_HOST *hd = wqw->hd; 11158c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc = hd->ioc; 11168c2ecf20Sopenharmony_ci struct Scsi_Host *shost = ioc->sh; 11178c2ecf20Sopenharmony_ci struct scsi_device *sdev; 11188c2ecf20Sopenharmony_ci int disk = wqw->disk; 11198c2ecf20Sopenharmony_ci struct _CONFIG_PAGE_IOC_3 *pg3; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci kfree(wqw); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci mpt_findImVolumes(ioc); 11248c2ecf20Sopenharmony_ci pg3 = ioc->raid_data.pIocPg3; 11258c2ecf20Sopenharmony_ci if (!pg3) 11268c2ecf20Sopenharmony_ci return; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci shost_for_each_device(sdev,shost) { 11298c2ecf20Sopenharmony_ci struct scsi_target *starget = scsi_target(sdev); 11308c2ecf20Sopenharmony_ci VirtTarget *vtarget = starget->hostdata; 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci /* only want to search RAID components */ 11338c2ecf20Sopenharmony_ci if (sdev->channel != 1) 11348c2ecf20Sopenharmony_ci continue; 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci /* The id is the raid PhysDiskNum, even if 11378c2ecf20Sopenharmony_ci * starget->id is the actual target address */ 11388c2ecf20Sopenharmony_ci if(vtarget->id != disk) 11398c2ecf20Sopenharmony_ci continue; 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci starget_printk(KERN_INFO, vtarget->starget, MYIOC_s_FMT 11428c2ecf20Sopenharmony_ci "Integrated RAID requests DV of new device\n", ioc->name); 11438c2ecf20Sopenharmony_ci mptspi_dv_device(hd, sdev); 11448c2ecf20Sopenharmony_ci } 11458c2ecf20Sopenharmony_ci shost_printk(KERN_INFO, shost, MYIOC_s_FMT 11468c2ecf20Sopenharmony_ci "Integrated RAID detects new device %d\n", ioc->name, disk); 11478c2ecf20Sopenharmony_ci scsi_scan_target(&ioc->sh->shost_gendev, 1, disk, 0, SCSI_SCAN_RESCAN); 11488c2ecf20Sopenharmony_ci} 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_cistatic void mpt_dv_raid(struct _MPT_SCSI_HOST *hd, int disk) 11528c2ecf20Sopenharmony_ci{ 11538c2ecf20Sopenharmony_ci struct work_queue_wrapper *wqw = kmalloc(sizeof(*wqw), GFP_ATOMIC); 11548c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc = hd->ioc; 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci if (!wqw) { 11578c2ecf20Sopenharmony_ci shost_printk(KERN_ERR, ioc->sh, MYIOC_s_FMT 11588c2ecf20Sopenharmony_ci "Failed to act on RAID event for physical disk %d\n", 11598c2ecf20Sopenharmony_ci ioc->name, disk); 11608c2ecf20Sopenharmony_ci return; 11618c2ecf20Sopenharmony_ci } 11628c2ecf20Sopenharmony_ci INIT_WORK(&wqw->work, mpt_work_wrapper); 11638c2ecf20Sopenharmony_ci wqw->hd = hd; 11648c2ecf20Sopenharmony_ci wqw->disk = disk; 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci schedule_work(&wqw->work); 11678c2ecf20Sopenharmony_ci} 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_cistatic int 11708c2ecf20Sopenharmony_cimptspi_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) 11718c2ecf20Sopenharmony_ci{ 11728c2ecf20Sopenharmony_ci u8 event = le32_to_cpu(pEvReply->Event) & 0xFF; 11738c2ecf20Sopenharmony_ci struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh); 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci if (ioc->bus_type != SPI) 11768c2ecf20Sopenharmony_ci return 0; 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci if (hd && event == MPI_EVENT_INTEGRATED_RAID) { 11798c2ecf20Sopenharmony_ci int reason 11808c2ecf20Sopenharmony_ci = (le32_to_cpu(pEvReply->Data[0]) & 0x00FF0000) >> 16; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) { 11838c2ecf20Sopenharmony_ci int disk = (le32_to_cpu(pEvReply->Data[0]) & 0xFF000000) >> 24; 11848c2ecf20Sopenharmony_ci mpt_dv_raid(hd, disk); 11858c2ecf20Sopenharmony_ci } 11868c2ecf20Sopenharmony_ci } 11878c2ecf20Sopenharmony_ci return mptscsih_event_process(ioc, pEvReply); 11888c2ecf20Sopenharmony_ci} 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_cistatic int 11918c2ecf20Sopenharmony_cimptspi_deny_binding(struct scsi_target *starget) 11928c2ecf20Sopenharmony_ci{ 11938c2ecf20Sopenharmony_ci struct _MPT_SCSI_HOST *hd = 11948c2ecf20Sopenharmony_ci (struct _MPT_SCSI_HOST *)dev_to_shost(starget->dev.parent)->hostdata; 11958c2ecf20Sopenharmony_ci return ((mptspi_is_raid(hd, starget->id)) && 11968c2ecf20Sopenharmony_ci starget->channel == 0) ? 1 : 0; 11978c2ecf20Sopenharmony_ci} 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_cistatic struct spi_function_template mptspi_transport_functions = { 12008c2ecf20Sopenharmony_ci .get_offset = mptspi_read_parameters, 12018c2ecf20Sopenharmony_ci .set_offset = mptspi_write_offset, 12028c2ecf20Sopenharmony_ci .show_offset = 1, 12038c2ecf20Sopenharmony_ci .get_period = mptspi_read_parameters, 12048c2ecf20Sopenharmony_ci .set_period = mptspi_write_period, 12058c2ecf20Sopenharmony_ci .show_period = 1, 12068c2ecf20Sopenharmony_ci .get_width = mptspi_read_parameters, 12078c2ecf20Sopenharmony_ci .set_width = mptspi_write_width, 12088c2ecf20Sopenharmony_ci .show_width = 1, 12098c2ecf20Sopenharmony_ci .get_iu = mptspi_read_parameters, 12108c2ecf20Sopenharmony_ci .set_iu = mptspi_write_iu, 12118c2ecf20Sopenharmony_ci .show_iu = 1, 12128c2ecf20Sopenharmony_ci .get_dt = mptspi_read_parameters, 12138c2ecf20Sopenharmony_ci .set_dt = mptspi_write_dt, 12148c2ecf20Sopenharmony_ci .show_dt = 1, 12158c2ecf20Sopenharmony_ci .get_qas = mptspi_read_parameters, 12168c2ecf20Sopenharmony_ci .set_qas = mptspi_write_qas, 12178c2ecf20Sopenharmony_ci .show_qas = 1, 12188c2ecf20Sopenharmony_ci .get_wr_flow = mptspi_read_parameters, 12198c2ecf20Sopenharmony_ci .set_wr_flow = mptspi_write_wr_flow, 12208c2ecf20Sopenharmony_ci .show_wr_flow = 1, 12218c2ecf20Sopenharmony_ci .get_rd_strm = mptspi_read_parameters, 12228c2ecf20Sopenharmony_ci .set_rd_strm = mptspi_write_rd_strm, 12238c2ecf20Sopenharmony_ci .show_rd_strm = 1, 12248c2ecf20Sopenharmony_ci .get_rti = mptspi_read_parameters, 12258c2ecf20Sopenharmony_ci .set_rti = mptspi_write_rti, 12268c2ecf20Sopenharmony_ci .show_rti = 1, 12278c2ecf20Sopenharmony_ci .get_pcomp_en = mptspi_read_parameters, 12288c2ecf20Sopenharmony_ci .set_pcomp_en = mptspi_write_pcomp_en, 12298c2ecf20Sopenharmony_ci .show_pcomp_en = 1, 12308c2ecf20Sopenharmony_ci .get_hold_mcs = mptspi_read_parameters, 12318c2ecf20Sopenharmony_ci .set_hold_mcs = mptspi_write_hold_mcs, 12328c2ecf20Sopenharmony_ci .show_hold_mcs = 1, 12338c2ecf20Sopenharmony_ci .deny_binding = mptspi_deny_binding, 12348c2ecf20Sopenharmony_ci}; 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci/**************************************************************************** 12378c2ecf20Sopenharmony_ci * Supported hardware 12388c2ecf20Sopenharmony_ci */ 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_cistatic struct pci_device_id mptspi_pci_table[] = { 12418c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1030, 12428c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID }, 12438c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_ATTO, MPI_MANUFACTPAGE_DEVID_53C1030, 12448c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID }, 12458c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1035, 12468c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID }, 12478c2ecf20Sopenharmony_ci {0} /* Terminating entry */ 12488c2ecf20Sopenharmony_ci}; 12498c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mptspi_pci_table); 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci/* 12538c2ecf20Sopenharmony_ci * renegotiate for a given target 12548c2ecf20Sopenharmony_ci */ 12558c2ecf20Sopenharmony_cistatic void 12568c2ecf20Sopenharmony_cimptspi_dv_renegotiate_work(struct work_struct *work) 12578c2ecf20Sopenharmony_ci{ 12588c2ecf20Sopenharmony_ci struct work_queue_wrapper *wqw = 12598c2ecf20Sopenharmony_ci container_of(work, struct work_queue_wrapper, work); 12608c2ecf20Sopenharmony_ci struct _MPT_SCSI_HOST *hd = wqw->hd; 12618c2ecf20Sopenharmony_ci struct scsi_device *sdev; 12628c2ecf20Sopenharmony_ci struct scsi_target *starget; 12638c2ecf20Sopenharmony_ci struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; 12648c2ecf20Sopenharmony_ci u32 nego; 12658c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc = hd->ioc; 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci kfree(wqw); 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci if (hd->spi_pending) { 12708c2ecf20Sopenharmony_ci shost_for_each_device(sdev, ioc->sh) { 12718c2ecf20Sopenharmony_ci if (hd->spi_pending & (1 << sdev->id)) 12728c2ecf20Sopenharmony_ci continue; 12738c2ecf20Sopenharmony_ci starget = scsi_target(sdev); 12748c2ecf20Sopenharmony_ci nego = mptspi_getRP(starget); 12758c2ecf20Sopenharmony_ci pg1.RequestedParameters = cpu_to_le32(nego); 12768c2ecf20Sopenharmony_ci pg1.Reserved = 0; 12778c2ecf20Sopenharmony_ci pg1.Configuration = 0; 12788c2ecf20Sopenharmony_ci mptspi_write_spi_device_pg1(starget, &pg1); 12798c2ecf20Sopenharmony_ci } 12808c2ecf20Sopenharmony_ci } else { 12818c2ecf20Sopenharmony_ci shost_for_each_device(sdev, ioc->sh) 12828c2ecf20Sopenharmony_ci mptspi_dv_device(hd, sdev); 12838c2ecf20Sopenharmony_ci } 12848c2ecf20Sopenharmony_ci} 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_cistatic void 12878c2ecf20Sopenharmony_cimptspi_dv_renegotiate(struct _MPT_SCSI_HOST *hd) 12888c2ecf20Sopenharmony_ci{ 12898c2ecf20Sopenharmony_ci struct work_queue_wrapper *wqw = kmalloc(sizeof(*wqw), GFP_ATOMIC); 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci if (!wqw) 12928c2ecf20Sopenharmony_ci return; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci INIT_WORK(&wqw->work, mptspi_dv_renegotiate_work); 12958c2ecf20Sopenharmony_ci wqw->hd = hd; 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci schedule_work(&wqw->work); 12988c2ecf20Sopenharmony_ci} 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci/* 13018c2ecf20Sopenharmony_ci * spi module reset handler 13028c2ecf20Sopenharmony_ci */ 13038c2ecf20Sopenharmony_cistatic int 13048c2ecf20Sopenharmony_cimptspi_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) 13058c2ecf20Sopenharmony_ci{ 13068c2ecf20Sopenharmony_ci int rc; 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci rc = mptscsih_ioc_reset(ioc, reset_phase); 13098c2ecf20Sopenharmony_ci if ((ioc->bus_type != SPI) || (!rc)) 13108c2ecf20Sopenharmony_ci return rc; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci /* only try to do a renegotiation if we're properly set up 13138c2ecf20Sopenharmony_ci * if we get an ioc fault on bringup, ioc->sh will be NULL */ 13148c2ecf20Sopenharmony_ci if (reset_phase == MPT_IOC_POST_RESET && 13158c2ecf20Sopenharmony_ci ioc->sh) { 13168c2ecf20Sopenharmony_ci struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh); 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci mptspi_dv_renegotiate(hd); 13198c2ecf20Sopenharmony_ci } 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci return rc; 13228c2ecf20Sopenharmony_ci} 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 13258c2ecf20Sopenharmony_ci/* 13268c2ecf20Sopenharmony_ci * spi module resume handler 13278c2ecf20Sopenharmony_ci */ 13288c2ecf20Sopenharmony_cistatic int 13298c2ecf20Sopenharmony_cimptspi_resume(struct pci_dev *pdev) 13308c2ecf20Sopenharmony_ci{ 13318c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc = pci_get_drvdata(pdev); 13328c2ecf20Sopenharmony_ci struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh); 13338c2ecf20Sopenharmony_ci int rc; 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci rc = mptscsih_resume(pdev); 13368c2ecf20Sopenharmony_ci mptspi_dv_renegotiate(hd); 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci return rc; 13398c2ecf20Sopenharmony_ci} 13408c2ecf20Sopenharmony_ci#endif 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 13438c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 13448c2ecf20Sopenharmony_ci/* 13458c2ecf20Sopenharmony_ci * mptspi_probe - Installs scsi devices per bus. 13468c2ecf20Sopenharmony_ci * @pdev: Pointer to pci_dev structure 13478c2ecf20Sopenharmony_ci * 13488c2ecf20Sopenharmony_ci * Returns 0 for success, non-zero for failure. 13498c2ecf20Sopenharmony_ci * 13508c2ecf20Sopenharmony_ci */ 13518c2ecf20Sopenharmony_cistatic int 13528c2ecf20Sopenharmony_cimptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id) 13538c2ecf20Sopenharmony_ci{ 13548c2ecf20Sopenharmony_ci struct Scsi_Host *sh; 13558c2ecf20Sopenharmony_ci MPT_SCSI_HOST *hd; 13568c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc; 13578c2ecf20Sopenharmony_ci unsigned long flags; 13588c2ecf20Sopenharmony_ci int ii; 13598c2ecf20Sopenharmony_ci int numSGE = 0; 13608c2ecf20Sopenharmony_ci int scale; 13618c2ecf20Sopenharmony_ci int ioc_cap; 13628c2ecf20Sopenharmony_ci int error=0; 13638c2ecf20Sopenharmony_ci int r; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci if ((r = mpt_attach(pdev,id)) != 0) 13668c2ecf20Sopenharmony_ci return r; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci ioc = pci_get_drvdata(pdev); 13698c2ecf20Sopenharmony_ci ioc->DoneCtx = mptspiDoneCtx; 13708c2ecf20Sopenharmony_ci ioc->TaskCtx = mptspiTaskCtx; 13718c2ecf20Sopenharmony_ci ioc->InternalCtx = mptspiInternalCtx; 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci /* Added sanity check on readiness of the MPT adapter. 13748c2ecf20Sopenharmony_ci */ 13758c2ecf20Sopenharmony_ci if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) { 13768c2ecf20Sopenharmony_ci printk(MYIOC_s_WARN_FMT 13778c2ecf20Sopenharmony_ci "Skipping because it's not operational!\n", 13788c2ecf20Sopenharmony_ci ioc->name); 13798c2ecf20Sopenharmony_ci error = -ENODEV; 13808c2ecf20Sopenharmony_ci goto out_mptspi_probe; 13818c2ecf20Sopenharmony_ci } 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci if (!ioc->active) { 13848c2ecf20Sopenharmony_ci printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n", 13858c2ecf20Sopenharmony_ci ioc->name); 13868c2ecf20Sopenharmony_ci error = -ENODEV; 13878c2ecf20Sopenharmony_ci goto out_mptspi_probe; 13888c2ecf20Sopenharmony_ci } 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci /* Sanity check - ensure at least 1 port is INITIATOR capable 13918c2ecf20Sopenharmony_ci */ 13928c2ecf20Sopenharmony_ci ioc_cap = 0; 13938c2ecf20Sopenharmony_ci for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) { 13948c2ecf20Sopenharmony_ci if (ioc->pfacts[ii].ProtocolFlags & 13958c2ecf20Sopenharmony_ci MPI_PORTFACTS_PROTOCOL_INITIATOR) 13968c2ecf20Sopenharmony_ci ioc_cap ++; 13978c2ecf20Sopenharmony_ci } 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci if (!ioc_cap) { 14008c2ecf20Sopenharmony_ci printk(MYIOC_s_WARN_FMT 14018c2ecf20Sopenharmony_ci "Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n", 14028c2ecf20Sopenharmony_ci ioc->name, ioc); 14038c2ecf20Sopenharmony_ci return 0; 14048c2ecf20Sopenharmony_ci } 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci sh = scsi_host_alloc(&mptspi_driver_template, sizeof(MPT_SCSI_HOST)); 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci if (!sh) { 14098c2ecf20Sopenharmony_ci printk(MYIOC_s_WARN_FMT 14108c2ecf20Sopenharmony_ci "Unable to register controller with SCSI subsystem\n", 14118c2ecf20Sopenharmony_ci ioc->name); 14128c2ecf20Sopenharmony_ci error = -1; 14138c2ecf20Sopenharmony_ci goto out_mptspi_probe; 14148c2ecf20Sopenharmony_ci } 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci /* VMWare emulation doesn't properly implement WRITE_SAME 14178c2ecf20Sopenharmony_ci */ 14188c2ecf20Sopenharmony_ci if (pdev->subsystem_vendor == 0x15AD) 14198c2ecf20Sopenharmony_ci sh->no_write_same = 1; 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci spin_lock_irqsave(&ioc->FreeQlock, flags); 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci /* Attach the SCSI Host to the IOC structure 14248c2ecf20Sopenharmony_ci */ 14258c2ecf20Sopenharmony_ci ioc->sh = sh; 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci sh->io_port = 0; 14288c2ecf20Sopenharmony_ci sh->n_io_port = 0; 14298c2ecf20Sopenharmony_ci sh->irq = 0; 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci /* set 16 byte cdb's */ 14328c2ecf20Sopenharmony_ci sh->max_cmd_len = 16; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci /* Yikes! This is important! 14358c2ecf20Sopenharmony_ci * Otherwise, by default, linux 14368c2ecf20Sopenharmony_ci * only scans target IDs 0-7! 14378c2ecf20Sopenharmony_ci * pfactsN->MaxDevices unreliable 14388c2ecf20Sopenharmony_ci * (not supported in early 14398c2ecf20Sopenharmony_ci * versions of the FW). 14408c2ecf20Sopenharmony_ci * max_id = 1 + actual max id, 14418c2ecf20Sopenharmony_ci * max_lun = 1 + actual last lun, 14428c2ecf20Sopenharmony_ci * see hosts.h :o( 14438c2ecf20Sopenharmony_ci */ 14448c2ecf20Sopenharmony_ci sh->max_id = ioc->devices_per_bus; 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci sh->max_lun = MPT_LAST_LUN + 1; 14478c2ecf20Sopenharmony_ci /* 14488c2ecf20Sopenharmony_ci * If RAID Firmware Detected, setup virtual channel 14498c2ecf20Sopenharmony_ci */ 14508c2ecf20Sopenharmony_ci if (ioc->ir_firmware) 14518c2ecf20Sopenharmony_ci sh->max_channel = 1; 14528c2ecf20Sopenharmony_ci else 14538c2ecf20Sopenharmony_ci sh->max_channel = 0; 14548c2ecf20Sopenharmony_ci sh->this_id = ioc->pfacts[0].PortSCSIID; 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci /* Required entry. 14578c2ecf20Sopenharmony_ci */ 14588c2ecf20Sopenharmony_ci sh->unique_id = ioc->id; 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci /* Verify that we won't exceed the maximum 14618c2ecf20Sopenharmony_ci * number of chain buffers 14628c2ecf20Sopenharmony_ci * We can optimize: ZZ = req_sz/sizeof(SGE) 14638c2ecf20Sopenharmony_ci * For 32bit SGE's: 14648c2ecf20Sopenharmony_ci * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ 14658c2ecf20Sopenharmony_ci * + (req_sz - 64)/sizeof(SGE) 14668c2ecf20Sopenharmony_ci * A slightly different algorithm is required for 14678c2ecf20Sopenharmony_ci * 64bit SGEs. 14688c2ecf20Sopenharmony_ci */ 14698c2ecf20Sopenharmony_ci scale = ioc->req_sz/ioc->SGE_size; 14708c2ecf20Sopenharmony_ci if (ioc->sg_addr_size == sizeof(u64)) { 14718c2ecf20Sopenharmony_ci numSGE = (scale - 1) * 14728c2ecf20Sopenharmony_ci (ioc->facts.MaxChainDepth-1) + scale + 14738c2ecf20Sopenharmony_ci (ioc->req_sz - 60) / ioc->SGE_size; 14748c2ecf20Sopenharmony_ci } else { 14758c2ecf20Sopenharmony_ci numSGE = 1 + (scale - 1) * 14768c2ecf20Sopenharmony_ci (ioc->facts.MaxChainDepth-1) + scale + 14778c2ecf20Sopenharmony_ci (ioc->req_sz - 64) / ioc->SGE_size; 14788c2ecf20Sopenharmony_ci } 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci if (numSGE < sh->sg_tablesize) { 14818c2ecf20Sopenharmony_ci /* Reset this value */ 14828c2ecf20Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_DEBUG_FMT 14838c2ecf20Sopenharmony_ci "Resetting sg_tablesize to %d from %d\n", 14848c2ecf20Sopenharmony_ci ioc->name, numSGE, sh->sg_tablesize)); 14858c2ecf20Sopenharmony_ci sh->sg_tablesize = numSGE; 14868c2ecf20Sopenharmony_ci } 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ioc->FreeQlock, flags); 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci hd = shost_priv(sh); 14918c2ecf20Sopenharmony_ci hd->ioc = ioc; 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci /* SCSI needs scsi_cmnd lookup table! 14948c2ecf20Sopenharmony_ci * (with size equal to req_depth*PtrSz!) 14958c2ecf20Sopenharmony_ci */ 14968c2ecf20Sopenharmony_ci ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC); 14978c2ecf20Sopenharmony_ci if (!ioc->ScsiLookup) { 14988c2ecf20Sopenharmony_ci error = -ENOMEM; 14998c2ecf20Sopenharmony_ci goto out_mptspi_probe; 15008c2ecf20Sopenharmony_ci } 15018c2ecf20Sopenharmony_ci spin_lock_init(&ioc->scsi_lookup_lock); 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n", 15048c2ecf20Sopenharmony_ci ioc->name, ioc->ScsiLookup)); 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci ioc->spi_data.Saf_Te = mpt_saf_te; 15078c2ecf20Sopenharmony_ci ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT 15088c2ecf20Sopenharmony_ci "saf_te %x\n", 15098c2ecf20Sopenharmony_ci ioc->name, 15108c2ecf20Sopenharmony_ci mpt_saf_te)); 15118c2ecf20Sopenharmony_ci ioc->spi_data.noQas = 0; 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci hd->last_queue_full = 0; 15148c2ecf20Sopenharmony_ci hd->spi_pending = 0; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci /* Some versions of the firmware don't support page 0; without 15178c2ecf20Sopenharmony_ci * that we can't get the parameters */ 15188c2ecf20Sopenharmony_ci if (ioc->spi_data.sdp0length != 0) 15198c2ecf20Sopenharmony_ci sh->transportt = mptspi_transport_template; 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci error = scsi_add_host (sh, &ioc->pcidev->dev); 15228c2ecf20Sopenharmony_ci if(error) { 15238c2ecf20Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_ERR_FMT 15248c2ecf20Sopenharmony_ci "scsi_add_host failed\n", ioc->name)); 15258c2ecf20Sopenharmony_ci goto out_mptspi_probe; 15268c2ecf20Sopenharmony_ci } 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci /* 15298c2ecf20Sopenharmony_ci * issue internal bus reset 15308c2ecf20Sopenharmony_ci */ 15318c2ecf20Sopenharmony_ci if (ioc->spi_data.bus_reset) 15328c2ecf20Sopenharmony_ci mptscsih_IssueTaskMgmt(hd, 15338c2ecf20Sopenharmony_ci MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, 15348c2ecf20Sopenharmony_ci 0, 0, 0, 0, 5); 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci scsi_scan_host(sh); 15378c2ecf20Sopenharmony_ci return 0; 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ciout_mptspi_probe: 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci mptscsih_remove(pdev); 15428c2ecf20Sopenharmony_ci return error; 15438c2ecf20Sopenharmony_ci} 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_cistatic void mptspi_remove(struct pci_dev *pdev) 15468c2ecf20Sopenharmony_ci{ 15478c2ecf20Sopenharmony_ci MPT_ADAPTER *ioc = pci_get_drvdata(pdev); 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci scsi_remove_host(ioc->sh); 15508c2ecf20Sopenharmony_ci mptscsih_remove(pdev); 15518c2ecf20Sopenharmony_ci} 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_cistatic struct pci_driver mptspi_driver = { 15548c2ecf20Sopenharmony_ci .name = "mptspi", 15558c2ecf20Sopenharmony_ci .id_table = mptspi_pci_table, 15568c2ecf20Sopenharmony_ci .probe = mptspi_probe, 15578c2ecf20Sopenharmony_ci .remove = mptspi_remove, 15588c2ecf20Sopenharmony_ci .shutdown = mptscsih_shutdown, 15598c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 15608c2ecf20Sopenharmony_ci .suspend = mptscsih_suspend, 15618c2ecf20Sopenharmony_ci .resume = mptspi_resume, 15628c2ecf20Sopenharmony_ci#endif 15638c2ecf20Sopenharmony_ci}; 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 15668c2ecf20Sopenharmony_ci/** 15678c2ecf20Sopenharmony_ci * mptspi_init - Register MPT adapter(s) as SCSI host(s) with SCSI mid-layer. 15688c2ecf20Sopenharmony_ci * 15698c2ecf20Sopenharmony_ci * Returns 0 for success, non-zero for failure. 15708c2ecf20Sopenharmony_ci */ 15718c2ecf20Sopenharmony_cistatic int __init 15728c2ecf20Sopenharmony_cimptspi_init(void) 15738c2ecf20Sopenharmony_ci{ 15748c2ecf20Sopenharmony_ci int error; 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci show_mptmod_ver(my_NAME, my_VERSION); 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci mptspi_transport_template = spi_attach_transport(&mptspi_transport_functions); 15798c2ecf20Sopenharmony_ci if (!mptspi_transport_template) 15808c2ecf20Sopenharmony_ci return -ENODEV; 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci mptspiDoneCtx = mpt_register(mptscsih_io_done, MPTSPI_DRIVER, 15838c2ecf20Sopenharmony_ci "mptscsih_io_done"); 15848c2ecf20Sopenharmony_ci mptspiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSPI_DRIVER, 15858c2ecf20Sopenharmony_ci "mptscsih_taskmgmt_complete"); 15868c2ecf20Sopenharmony_ci mptspiInternalCtx = mpt_register(mptscsih_scandv_complete, 15878c2ecf20Sopenharmony_ci MPTSPI_DRIVER, "mptscsih_scandv_complete"); 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci mpt_event_register(mptspiDoneCtx, mptspi_event_process); 15908c2ecf20Sopenharmony_ci mpt_reset_register(mptspiDoneCtx, mptspi_ioc_reset); 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci error = pci_register_driver(&mptspi_driver); 15938c2ecf20Sopenharmony_ci if (error) 15948c2ecf20Sopenharmony_ci spi_release_transport(mptspi_transport_template); 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci return error; 15978c2ecf20Sopenharmony_ci} 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 16008c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 16018c2ecf20Sopenharmony_ci/** 16028c2ecf20Sopenharmony_ci * mptspi_exit - Unregisters MPT adapter(s) 16038c2ecf20Sopenharmony_ci */ 16048c2ecf20Sopenharmony_cistatic void __exit 16058c2ecf20Sopenharmony_cimptspi_exit(void) 16068c2ecf20Sopenharmony_ci{ 16078c2ecf20Sopenharmony_ci pci_unregister_driver(&mptspi_driver); 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci mpt_reset_deregister(mptspiDoneCtx); 16108c2ecf20Sopenharmony_ci mpt_event_deregister(mptspiDoneCtx); 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci mpt_deregister(mptspiInternalCtx); 16138c2ecf20Sopenharmony_ci mpt_deregister(mptspiTaskCtx); 16148c2ecf20Sopenharmony_ci mpt_deregister(mptspiDoneCtx); 16158c2ecf20Sopenharmony_ci spi_release_transport(mptspi_transport_template); 16168c2ecf20Sopenharmony_ci} 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_cimodule_init(mptspi_init); 16198c2ecf20Sopenharmony_cimodule_exit(mptspi_exit); 1620