1243eabcfSMoore, Eric Dean /*
2243eabcfSMoore, Eric Dean * linux/drivers/message/fusion/mptspi.c
3f36789e2SPrakash, Sathya * For use with LSI PCI chip/adapter(s)
4f36789e2SPrakash, Sathya * running LSI Fusion MPT (Message Passing Technology) firmware.
5243eabcfSMoore, Eric Dean *
6cddc0ab7SPrakash, Sathya * Copyright (c) 1999-2008 LSI Corporation
716d20101SEric Moore * (mailto:DL-MPTFusionLinux@lsi.com)
8243eabcfSMoore, Eric Dean *
9243eabcfSMoore, Eric Dean */
10243eabcfSMoore, Eric Dean /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11243eabcfSMoore, Eric Dean /*
12243eabcfSMoore, Eric Dean This program is free software; you can redistribute it and/or modify
13243eabcfSMoore, Eric Dean it under the terms of the GNU General Public License as published by
14243eabcfSMoore, Eric Dean the Free Software Foundation; version 2 of the License.
15243eabcfSMoore, Eric Dean
16243eabcfSMoore, Eric Dean This program is distributed in the hope that it will be useful,
17243eabcfSMoore, Eric Dean but WITHOUT ANY WARRANTY; without even the implied warranty of
18243eabcfSMoore, Eric Dean MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19243eabcfSMoore, Eric Dean GNU General Public License for more details.
20243eabcfSMoore, Eric Dean
21243eabcfSMoore, Eric Dean NO WARRANTY
22243eabcfSMoore, Eric Dean THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
23243eabcfSMoore, Eric Dean CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
24243eabcfSMoore, Eric Dean LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
25243eabcfSMoore, Eric Dean MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
26243eabcfSMoore, Eric Dean solely responsible for determining the appropriateness of using and
27243eabcfSMoore, Eric Dean distributing the Program and assumes all risks associated with its
28243eabcfSMoore, Eric Dean exercise of rights under this Agreement, including but not limited to
29243eabcfSMoore, Eric Dean the risks and costs of program errors, damage to or loss of data,
30243eabcfSMoore, Eric Dean programs or equipment, and unavailability or interruption of operations.
31243eabcfSMoore, Eric Dean
32243eabcfSMoore, Eric Dean DISCLAIMER OF LIABILITY
33243eabcfSMoore, Eric Dean NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
34243eabcfSMoore, Eric Dean DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35243eabcfSMoore, Eric Dean DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
36243eabcfSMoore, Eric Dean ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
37243eabcfSMoore, Eric Dean TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
38243eabcfSMoore, Eric Dean USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
39243eabcfSMoore, Eric Dean HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
40243eabcfSMoore, Eric Dean
41243eabcfSMoore, Eric Dean You should have received a copy of the GNU General Public License
42243eabcfSMoore, Eric Dean along with this program; if not, write to the Free Software
43243eabcfSMoore, Eric Dean Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
44243eabcfSMoore, Eric Dean */
45243eabcfSMoore, Eric Dean /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
46243eabcfSMoore, Eric Dean
47243eabcfSMoore, Eric Dean #include <linux/module.h>
48243eabcfSMoore, Eric Dean #include <linux/kernel.h>
495a0e3ad6STejun Heo #include <linux/slab.h>
50243eabcfSMoore, Eric Dean #include <linux/init.h>
51243eabcfSMoore, Eric Dean #include <linux/errno.h>
52243eabcfSMoore, Eric Dean #include <linux/kdev_t.h>
53243eabcfSMoore, Eric Dean #include <linux/blkdev.h>
54243eabcfSMoore, Eric Dean #include <linux/delay.h> /* for mdelay */
55b8a51443SThomas Gleixner #include <linux/interrupt.h>
56243eabcfSMoore, Eric Dean #include <linux/reboot.h> /* notifier code */
57243eabcfSMoore, Eric Dean #include <linux/workqueue.h>
58c92f222eSJames Bottomley #include <linux/raid_class.h>
59243eabcfSMoore, Eric Dean
60243eabcfSMoore, Eric Dean #include <scsi/scsi.h>
61243eabcfSMoore, Eric Dean #include <scsi/scsi_cmnd.h>
62243eabcfSMoore, Eric Dean #include <scsi/scsi_device.h>
63243eabcfSMoore, Eric Dean #include <scsi/scsi_host.h>
64243eabcfSMoore, Eric Dean #include <scsi/scsi_tcq.h>
65c92f222eSJames Bottomley #include <scsi/scsi_transport.h>
66c92f222eSJames Bottomley #include <scsi/scsi_transport_spi.h>
67873c82edSEric Moore #include <scsi/scsi_dbg.h>
68243eabcfSMoore, Eric Dean
69243eabcfSMoore, Eric Dean #include "mptbase.h"
70243eabcfSMoore, Eric Dean #include "mptscsih.h"
71243eabcfSMoore, Eric Dean
72243eabcfSMoore, Eric Dean /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
73243eabcfSMoore, Eric Dean #define my_NAME "Fusion MPT SPI Host driver"
74243eabcfSMoore, Eric Dean #define my_VERSION MPT_LINUX_VERSION_COMMON
75243eabcfSMoore, Eric Dean #define MYNAM "mptspi"
76243eabcfSMoore, Eric Dean
77243eabcfSMoore, Eric Dean MODULE_AUTHOR(MODULEAUTHOR);
78243eabcfSMoore, Eric Dean MODULE_DESCRIPTION(my_NAME);
79243eabcfSMoore, Eric Dean MODULE_LICENSE("GPL");
809f4203b3SEric Moore MODULE_VERSION(my_VERSION);
81243eabcfSMoore, Eric Dean
82243eabcfSMoore, Eric Dean /* Command line args */
83243eabcfSMoore, Eric Dean static int mpt_saf_te = MPTSCSIH_SAF_TE;
84243eabcfSMoore, Eric Dean module_param(mpt_saf_te, int, 0);
85243eabcfSMoore, Eric Dean MODULE_PARM_DESC(mpt_saf_te, " Force enabling SEP Processor: enable=1 (default=MPTSCSIH_SAF_TE=0)");
86243eabcfSMoore, Eric Dean
87c92f222eSJames Bottomley static void mptspi_write_offset(struct scsi_target *, int);
88c92f222eSJames Bottomley static void mptspi_write_width(struct scsi_target *, int);
89c92f222eSJames Bottomley static int mptspi_write_spi_device_pg1(struct scsi_target *,
90c92f222eSJames Bottomley struct _CONFIG_PAGE_SCSI_DEVICE_1 *);
91c92f222eSJames Bottomley
92c92f222eSJames Bottomley static struct scsi_transport_template *mptspi_transport_template = NULL;
93c92f222eSJames Bottomley
94f606f571SPrakash, Sathya static u8 mptspiDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
95f606f571SPrakash, Sathya static u8 mptspiTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
96f606f571SPrakash, Sathya static u8 mptspiInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
97243eabcfSMoore, Eric Dean
985a9c47b1SEric Moore /**
991544d677SRandy Dunlap * mptspi_setTargetNegoParms - Update the target negotiation parameters
1005a9c47b1SEric Moore * @hd: Pointer to a SCSI Host Structure
1011544d677SRandy Dunlap * @target: per target private data
1025a9c47b1SEric Moore * @sdev: SCSI device
1035a9c47b1SEric Moore *
104950d2867SJiang Jian * Update the target negotiation parameters based on the Inquiry
1051544d677SRandy Dunlap * data, adapter capabilities, and NVRAM settings.
1065a9c47b1SEric Moore **/
1075a9c47b1SEric Moore static void
mptspi_setTargetNegoParms(MPT_SCSI_HOST * hd,VirtTarget * target,struct scsi_device * sdev)1085a9c47b1SEric Moore mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
1095a9c47b1SEric Moore struct scsi_device *sdev)
1105a9c47b1SEric Moore {
111e80b002bSEric Moore MPT_ADAPTER *ioc = hd->ioc;
112e80b002bSEric Moore SpiCfgData *pspi_data = &ioc->spi_data;
1135a9c47b1SEric Moore int id = (int) target->id;
1145a9c47b1SEric Moore int nvram;
1155a9c47b1SEric Moore u8 width = MPT_NARROW;
1165a9c47b1SEric Moore u8 factor = MPT_ASYNC;
1175a9c47b1SEric Moore u8 offset = 0;
1185a9c47b1SEric Moore u8 nfactor;
1195a9c47b1SEric Moore u8 noQas = 1;
1205a9c47b1SEric Moore
1215a9c47b1SEric Moore target->negoFlags = pspi_data->noQas;
1225a9c47b1SEric Moore
1235a9c47b1SEric Moore if (sdev->scsi_level < SCSI_2) {
1245a9c47b1SEric Moore width = 0;
1255a9c47b1SEric Moore factor = MPT_ULTRA2;
1265a9c47b1SEric Moore offset = pspi_data->maxSyncOffset;
1275a9c47b1SEric Moore target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
1285a9c47b1SEric Moore } else {
1295a9c47b1SEric Moore if (scsi_device_wide(sdev))
1305a9c47b1SEric Moore width = 1;
1315a9c47b1SEric Moore
1325a9c47b1SEric Moore if (scsi_device_sync(sdev)) {
1335a9c47b1SEric Moore factor = pspi_data->minSyncFactor;
1345a9c47b1SEric Moore if (!scsi_device_dt(sdev))
1355a9c47b1SEric Moore factor = MPT_ULTRA2;
1365a9c47b1SEric Moore else {
1375a9c47b1SEric Moore if (!scsi_device_ius(sdev) &&
1385a9c47b1SEric Moore !scsi_device_qas(sdev))
1395a9c47b1SEric Moore factor = MPT_ULTRA160;
1405a9c47b1SEric Moore else {
1415a9c47b1SEric Moore factor = MPT_ULTRA320;
1425a9c47b1SEric Moore if (scsi_device_qas(sdev)) {
143e80b002bSEric Moore ddvprintk(ioc,
14429dd3609SEric Moore printk(MYIOC_s_DEBUG_FMT "Enabling QAS due to "
145e80b002bSEric Moore "byte56=%02x on id=%d!\n", ioc->name,
14629dd3609SEric Moore scsi_device_qas(sdev), id));
1475a9c47b1SEric Moore noQas = 0;
1485a9c47b1SEric Moore }
1495a9c47b1SEric Moore if (sdev->type == TYPE_TAPE &&
1505a9c47b1SEric Moore scsi_device_ius(sdev))
1515a9c47b1SEric Moore target->negoFlags |= MPT_TAPE_NEGO_IDP;
1525a9c47b1SEric Moore }
1535a9c47b1SEric Moore }
1545a9c47b1SEric Moore offset = pspi_data->maxSyncOffset;
1555a9c47b1SEric Moore
1565a9c47b1SEric Moore /* If RAID, never disable QAS
1575a9c47b1SEric Moore * else if non RAID, do not disable
1585a9c47b1SEric Moore * QAS if bit 1 is set
1595a9c47b1SEric Moore * bit 1 QAS support, non-raid only
1605a9c47b1SEric Moore * bit 0 IU support
1615a9c47b1SEric Moore */
1625a9c47b1SEric Moore if (target->raidVolume == 1)
1635a9c47b1SEric Moore noQas = 0;
1645a9c47b1SEric Moore } else {
1655a9c47b1SEric Moore factor = MPT_ASYNC;
1665a9c47b1SEric Moore offset = 0;
1675a9c47b1SEric Moore }
1685a9c47b1SEric Moore }
1695a9c47b1SEric Moore
1705a9c47b1SEric Moore if (!sdev->tagged_supported)
1715a9c47b1SEric Moore target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
1725a9c47b1SEric Moore
1735a9c47b1SEric Moore /* Update tflags based on NVRAM settings. (SCSI only)
1745a9c47b1SEric Moore */
1755a9c47b1SEric Moore if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
1765a9c47b1SEric Moore nvram = pspi_data->nvram[id];
1775a9c47b1SEric Moore nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
1785a9c47b1SEric Moore
1795a9c47b1SEric Moore if (width)
1805a9c47b1SEric Moore width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
1815a9c47b1SEric Moore
1825a9c47b1SEric Moore if (offset > 0) {
1835a9c47b1SEric Moore /* Ensure factor is set to the
1845a9c47b1SEric Moore * maximum of: adapter, nvram, inquiry
1855a9c47b1SEric Moore */
1865a9c47b1SEric Moore if (nfactor) {
1875a9c47b1SEric Moore if (nfactor < pspi_data->minSyncFactor )
1885a9c47b1SEric Moore nfactor = pspi_data->minSyncFactor;
1895a9c47b1SEric Moore
1905a9c47b1SEric Moore factor = max(factor, nfactor);
1915a9c47b1SEric Moore if (factor == MPT_ASYNC)
1925a9c47b1SEric Moore offset = 0;
1935a9c47b1SEric Moore } else {
1945a9c47b1SEric Moore offset = 0;
1955a9c47b1SEric Moore factor = MPT_ASYNC;
1965a9c47b1SEric Moore }
1975a9c47b1SEric Moore } else {
1985a9c47b1SEric Moore factor = MPT_ASYNC;
1995a9c47b1SEric Moore }
2005a9c47b1SEric Moore }
2015a9c47b1SEric Moore
2025a9c47b1SEric Moore /* Make sure data is consistent
2035a9c47b1SEric Moore */
2045a9c47b1SEric Moore if ((!width) && (factor < MPT_ULTRA2))
2055a9c47b1SEric Moore factor = MPT_ULTRA2;
2065a9c47b1SEric Moore
2075a9c47b1SEric Moore /* Save the data to the target structure.
2085a9c47b1SEric Moore */
2095a9c47b1SEric Moore target->minSyncFactor = factor;
2105a9c47b1SEric Moore target->maxOffset = offset;
2115a9c47b1SEric Moore target->maxWidth = width;
2125a9c47b1SEric Moore
213f8c23bdeSKashyap, Desai spi_min_period(scsi_target(sdev)) = factor;
214f8c23bdeSKashyap, Desai spi_max_offset(scsi_target(sdev)) = offset;
215f8c23bdeSKashyap, Desai spi_max_width(scsi_target(sdev)) = width;
216f8c23bdeSKashyap, Desai
2175a9c47b1SEric Moore target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
2185a9c47b1SEric Moore
2195a9c47b1SEric Moore /* Disable unused features.
2205a9c47b1SEric Moore */
2215a9c47b1SEric Moore if (!width)
2225a9c47b1SEric Moore target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
2235a9c47b1SEric Moore
2245a9c47b1SEric Moore if (!offset)
2255a9c47b1SEric Moore target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
2265a9c47b1SEric Moore
2275a9c47b1SEric Moore if ( factor > MPT_ULTRA320 )
2285a9c47b1SEric Moore noQas = 0;
2295a9c47b1SEric Moore
2305a9c47b1SEric Moore if (noQas && (pspi_data->noQas == 0)) {
2315a9c47b1SEric Moore pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS;
2325a9c47b1SEric Moore target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
2335a9c47b1SEric Moore
2345a9c47b1SEric Moore /* Disable QAS in a mixed configuration case
2355a9c47b1SEric Moore */
2365a9c47b1SEric Moore
237e80b002bSEric Moore ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
238e80b002bSEric Moore "Disabling QAS due to noQas=%02x on id=%d!\n", ioc->name, noQas, id));
2395a9c47b1SEric Moore }
2405a9c47b1SEric Moore }
2415a9c47b1SEric Moore
2425a9c47b1SEric Moore /**
2435a9c47b1SEric Moore * mptspi_writeIOCPage4 - write IOC Page 4
2445a9c47b1SEric Moore * @hd: Pointer to a SCSI Host Structure
2451544d677SRandy Dunlap * @channel: channel number
2465a9c47b1SEric Moore * @id: write IOC Page4 for this ID & Bus
2475a9c47b1SEric Moore *
2485a9c47b1SEric Moore * Return: -EAGAIN if unable to obtain a Message Frame
2495a9c47b1SEric Moore * or 0 if success.
2505a9c47b1SEric Moore *
2515a9c47b1SEric Moore * Remark: We do not wait for a return, write pages sequentially.
2525a9c47b1SEric Moore **/
2535a9c47b1SEric Moore static int
mptspi_writeIOCPage4(MPT_SCSI_HOST * hd,u8 channel,u8 id)2545a9c47b1SEric Moore mptspi_writeIOCPage4(MPT_SCSI_HOST *hd, u8 channel , u8 id)
2555a9c47b1SEric Moore {
2565a9c47b1SEric Moore MPT_ADAPTER *ioc = hd->ioc;
2575a9c47b1SEric Moore Config_t *pReq;
2585a9c47b1SEric Moore IOCPage4_t *IOCPage4Ptr;
2595a9c47b1SEric Moore MPT_FRAME_HDR *mf;
2605a9c47b1SEric Moore dma_addr_t dataDma;
2615a9c47b1SEric Moore u32 flagsLength;
2625a9c47b1SEric Moore int ii;
2635a9c47b1SEric Moore
2645a9c47b1SEric Moore /* Get a MF for this command.
2655a9c47b1SEric Moore */
2665a9c47b1SEric Moore if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
267d6ecdd63SPrakash, Sathya dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
268d6ecdd63SPrakash, Sathya "writeIOCPage4 : no msg frames!\n",ioc->name));
2695a9c47b1SEric Moore return -EAGAIN;
2705a9c47b1SEric Moore }
2715a9c47b1SEric Moore
2725a9c47b1SEric Moore /* Set the request and the data pointers.
2735a9c47b1SEric Moore * Place data at end of MF.
2745a9c47b1SEric Moore */
2755a9c47b1SEric Moore pReq = (Config_t *)mf;
2765a9c47b1SEric Moore
2775a9c47b1SEric Moore /* Complete the request frame (same for all requests).
2785a9c47b1SEric Moore */
2795a9c47b1SEric Moore pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
2805a9c47b1SEric Moore pReq->Reserved = 0;
2815a9c47b1SEric Moore pReq->ChainOffset = 0;
2825a9c47b1SEric Moore pReq->Function = MPI_FUNCTION_CONFIG;
2835a9c47b1SEric Moore pReq->ExtPageLength = 0;
2845a9c47b1SEric Moore pReq->ExtPageType = 0;
2855a9c47b1SEric Moore pReq->MsgFlags = 0;
2865a9c47b1SEric Moore for (ii=0; ii < 8; ii++) {
2875a9c47b1SEric Moore pReq->Reserved2[ii] = 0;
2885a9c47b1SEric Moore }
2895a9c47b1SEric Moore
2905a9c47b1SEric Moore IOCPage4Ptr = ioc->spi_data.pIocPg4;
2915a9c47b1SEric Moore dataDma = ioc->spi_data.IocPg4_dma;
2925a9c47b1SEric Moore ii = IOCPage4Ptr->ActiveSEP++;
2935a9c47b1SEric Moore IOCPage4Ptr->SEP[ii].SEPTargetID = id;
2945a9c47b1SEric Moore IOCPage4Ptr->SEP[ii].SEPBus = channel;
2955a9c47b1SEric Moore pReq->Header = IOCPage4Ptr->Header;
2965a9c47b1SEric Moore pReq->PageAddress = cpu_to_le32(id | (channel << 8 ));
2975a9c47b1SEric Moore
2985a9c47b1SEric Moore /* Add a SGE to the config request.
2995a9c47b1SEric Moore */
3005a9c47b1SEric Moore flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
3015a9c47b1SEric Moore (IOCPage4Ptr->Header.PageLength + ii) * 4;
3025a9c47b1SEric Moore
30314d0f0b0SKashyap, Desai ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
3045a9c47b1SEric Moore
305d6ecdd63SPrakash, Sathya ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3065a9c47b1SEric Moore "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
3075a9c47b1SEric Moore ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel));
3085a9c47b1SEric Moore
3095a9c47b1SEric Moore mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
3105a9c47b1SEric Moore
3115a9c47b1SEric Moore return 0;
3125a9c47b1SEric Moore }
3135a9c47b1SEric Moore
3145a9c47b1SEric Moore /**
3155a9c47b1SEric Moore * mptspi_initTarget - Target, LUN alloc/free functionality.
3165a9c47b1SEric Moore * @hd: Pointer to MPT_SCSI_HOST structure
3175a9c47b1SEric Moore * @vtarget: per target private data
3185a9c47b1SEric Moore * @sdev: SCSI device
3195a9c47b1SEric Moore *
3205a9c47b1SEric Moore * NOTE: It's only SAFE to call this routine if data points to
3215a9c47b1SEric Moore * sane & valid STANDARD INQUIRY data!
3225a9c47b1SEric Moore *
3235a9c47b1SEric Moore * Allocate and initialize memory for this target.
3245a9c47b1SEric Moore * Save inquiry data.
3255a9c47b1SEric Moore *
3265a9c47b1SEric Moore **/
3275a9c47b1SEric Moore static void
mptspi_initTarget(MPT_SCSI_HOST * hd,VirtTarget * vtarget,struct scsi_device * sdev)3285a9c47b1SEric Moore mptspi_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget,
3295a9c47b1SEric Moore struct scsi_device *sdev)
3305a9c47b1SEric Moore {
3315a9c47b1SEric Moore
3325a9c47b1SEric Moore /* Is LUN supported? If so, upper 2 bits will be 0
3335a9c47b1SEric Moore * in first byte of inquiry data.
3345a9c47b1SEric Moore */
3355a9c47b1SEric Moore if (sdev->inq_periph_qual != 0)
3365a9c47b1SEric Moore return;
3375a9c47b1SEric Moore
3385a9c47b1SEric Moore if (vtarget == NULL)
3395a9c47b1SEric Moore return;
3405a9c47b1SEric Moore
3415a9c47b1SEric Moore vtarget->type = sdev->type;
3425a9c47b1SEric Moore
3435a9c47b1SEric Moore if ((sdev->type == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) {
3445a9c47b1SEric Moore /* Treat all Processors as SAF-TE if
3455a9c47b1SEric Moore * command line option is set */
3465a9c47b1SEric Moore vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
3475a9c47b1SEric Moore mptspi_writeIOCPage4(hd, vtarget->channel, vtarget->id);
3485a9c47b1SEric Moore }else if ((sdev->type == TYPE_PROCESSOR) &&
3495a9c47b1SEric Moore !(vtarget->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) {
3505a9c47b1SEric Moore if (sdev->inquiry_len > 49 ) {
3515a9c47b1SEric Moore if (sdev->inquiry[44] == 'S' &&
3525a9c47b1SEric Moore sdev->inquiry[45] == 'A' &&
3535a9c47b1SEric Moore sdev->inquiry[46] == 'F' &&
3545a9c47b1SEric Moore sdev->inquiry[47] == '-' &&
3555a9c47b1SEric Moore sdev->inquiry[48] == 'T' &&
3565a9c47b1SEric Moore sdev->inquiry[49] == 'E' ) {
3575a9c47b1SEric Moore vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
3585a9c47b1SEric Moore mptspi_writeIOCPage4(hd, vtarget->channel, vtarget->id);
3595a9c47b1SEric Moore }
3605a9c47b1SEric Moore }
3615a9c47b1SEric Moore }
3625a9c47b1SEric Moore mptspi_setTargetNegoParms(hd, vtarget, sdev);
3635a9c47b1SEric Moore }
364793955f5SEric Moore
365793955f5SEric Moore /**
366793955f5SEric Moore * mptspi_is_raid - Determines whether target is belonging to volume
367793955f5SEric Moore * @hd: Pointer to a SCSI HOST structure
368793955f5SEric Moore * @id: target device id
369793955f5SEric Moore *
370793955f5SEric Moore * Return:
371793955f5SEric Moore * non-zero = true
372793955f5SEric Moore * zero = false
373793955f5SEric Moore *
374793955f5SEric Moore */
375793955f5SEric Moore static int
mptspi_is_raid(struct _MPT_SCSI_HOST * hd,u32 id)376793955f5SEric Moore mptspi_is_raid(struct _MPT_SCSI_HOST *hd, u32 id)
377793955f5SEric Moore {
378793955f5SEric Moore int i, rc = 0;
379e80b002bSEric Moore MPT_ADAPTER *ioc = hd->ioc;
380793955f5SEric Moore
381e80b002bSEric Moore if (!ioc->raid_data.pIocPg2)
382793955f5SEric Moore goto out;
383793955f5SEric Moore
384e80b002bSEric Moore if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
385793955f5SEric Moore goto out;
386e80b002bSEric Moore for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
387e80b002bSEric Moore if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) {
388793955f5SEric Moore rc = 1;
389793955f5SEric Moore goto out;
390793955f5SEric Moore }
391793955f5SEric Moore }
392793955f5SEric Moore
393793955f5SEric Moore out:
394793955f5SEric Moore return rc;
395793955f5SEric Moore }
396793955f5SEric Moore
mptspi_target_alloc(struct scsi_target * starget)397c92f222eSJames Bottomley static int mptspi_target_alloc(struct scsi_target *starget)
398c92f222eSJames Bottomley {
399c92f222eSJames Bottomley struct Scsi_Host *shost = dev_to_shost(&starget->dev);
400e7eae9f6SEric Moore struct _MPT_SCSI_HOST *hd = shost_priv(shost);
401793955f5SEric Moore VirtTarget *vtarget;
402e80b002bSEric Moore MPT_ADAPTER *ioc;
403c92f222eSJames Bottomley
404c92f222eSJames Bottomley if (hd == NULL)
405c92f222eSJames Bottomley return -ENODEV;
406c92f222eSJames Bottomley
407e80b002bSEric Moore ioc = hd->ioc;
408793955f5SEric Moore vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
409793955f5SEric Moore if (!vtarget)
410793955f5SEric Moore return -ENOMEM;
411c92f222eSJames Bottomley
412e80b002bSEric Moore vtarget->ioc_id = ioc->id;
413793955f5SEric Moore vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
414793955f5SEric Moore vtarget->id = (u8)starget->id;
415793955f5SEric Moore vtarget->channel = (u8)starget->channel;
416793955f5SEric Moore vtarget->starget = starget;
417793955f5SEric Moore starget->hostdata = vtarget;
418793955f5SEric Moore
419793955f5SEric Moore if (starget->channel == 1) {
420e80b002bSEric Moore if (mptscsih_is_phys_disk(ioc, 0, starget->id) == 0)
421c92f222eSJames Bottomley return 0;
422793955f5SEric Moore vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
423793955f5SEric Moore /* The real channel for this device is zero */
424793955f5SEric Moore vtarget->channel = 0;
425793955f5SEric Moore /* The actual physdisknum (for RAID passthrough) */
426e80b002bSEric Moore vtarget->id = mptscsih_raid_id_to_num(ioc, 0,
427793955f5SEric Moore starget->id);
428793955f5SEric Moore }
429793955f5SEric Moore
430793955f5SEric Moore if (starget->channel == 0 &&
431793955f5SEric Moore mptspi_is_raid(hd, starget->id)) {
432793955f5SEric Moore vtarget->raidVolume = 1;
433e80b002bSEric Moore ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
434e80b002bSEric Moore "RAID Volume @ channel=%d id=%d\n", ioc->name, starget->channel,
435793955f5SEric Moore starget->id));
436793955f5SEric Moore }
437c92f222eSJames Bottomley
438e80b002bSEric Moore if (ioc->spi_data.nvram &&
439e80b002bSEric Moore ioc->spi_data.nvram[starget->id] != MPT_HOST_NVRAM_INVALID) {
440e80b002bSEric Moore u32 nvram = ioc->spi_data.nvram[starget->id];
441c92f222eSJames Bottomley spi_min_period(starget) = (nvram & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
442c92f222eSJames Bottomley spi_max_width(starget) = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
443c92f222eSJames Bottomley } else {
444e80b002bSEric Moore spi_min_period(starget) = ioc->spi_data.minSyncFactor;
445e80b002bSEric Moore spi_max_width(starget) = ioc->spi_data.maxBusWidth;
446c92f222eSJames Bottomley }
447e80b002bSEric Moore spi_max_offset(starget) = ioc->spi_data.maxSyncOffset;
448c92f222eSJames Bottomley
449c92f222eSJames Bottomley spi_offset(starget) = 0;
450cc472449SPrakash, Sathya spi_period(starget) = 0xFF;
451c92f222eSJames Bottomley mptspi_write_width(starget, 0);
452c92f222eSJames Bottomley
453c92f222eSJames Bottomley return 0;
454c92f222eSJames Bottomley }
455c92f222eSJames Bottomley
456301b01aaSAdrian Bunk static void
mptspi_target_destroy(struct scsi_target * starget)457793955f5SEric Moore mptspi_target_destroy(struct scsi_target *starget)
458793955f5SEric Moore {
459793955f5SEric Moore kfree(starget->hostdata);
460793955f5SEric Moore starget->hostdata = NULL;
461793955f5SEric Moore }
462793955f5SEric Moore
463873c82edSEric Moore /**
464873c82edSEric Moore * mptspi_print_write_nego - negotiation parameters debug info that is being sent
465873c82edSEric Moore * @hd: Pointer to a SCSI HOST structure
466873c82edSEric Moore * @starget: SCSI target
467873c82edSEric Moore * @ii: negotiation parameters
468873c82edSEric Moore *
469873c82edSEric Moore */
470873c82edSEric Moore static void
mptspi_print_write_nego(struct _MPT_SCSI_HOST * hd,struct scsi_target * starget,u32 ii)471873c82edSEric Moore mptspi_print_write_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u32 ii)
472873c82edSEric Moore {
473d6ecdd63SPrakash, Sathya ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d Requested = 0x%08x"
474873c82edSEric Moore " ( %s factor = 0x%02x @ offset = 0x%02x %s%s%s%s%s%s%s%s)\n",
475873c82edSEric Moore hd->ioc->name, starget->id, ii,
476873c82edSEric Moore ii & MPI_SCSIDEVPAGE0_NP_WIDE ? "Wide ": "",
477873c82edSEric Moore ((ii >> 8) & 0xFF), ((ii >> 16) & 0xFF),
478873c82edSEric Moore ii & MPI_SCSIDEVPAGE0_NP_IU ? "IU ": "",
479873c82edSEric Moore ii & MPI_SCSIDEVPAGE0_NP_DT ? "DT ": "",
480873c82edSEric Moore ii & MPI_SCSIDEVPAGE0_NP_QAS ? "QAS ": "",
481873c82edSEric Moore ii & MPI_SCSIDEVPAGE0_NP_HOLD_MCS ? "HOLDMCS ": "",
482873c82edSEric Moore ii & MPI_SCSIDEVPAGE0_NP_WR_FLOW ? "WRFLOW ": "",
483873c82edSEric Moore ii & MPI_SCSIDEVPAGE0_NP_RD_STRM ? "RDSTRM ": "",
484873c82edSEric Moore ii & MPI_SCSIDEVPAGE0_NP_RTI ? "RTI ": "",
485873c82edSEric Moore ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": ""));
486873c82edSEric Moore }
487873c82edSEric Moore
488873c82edSEric Moore /**
489873c82edSEric Moore * mptspi_print_read_nego - negotiation parameters debug info that is being read
490873c82edSEric Moore * @hd: Pointer to a SCSI HOST structure
491873c82edSEric Moore * @starget: SCSI target
492873c82edSEric Moore * @ii: negotiation parameters
493873c82edSEric Moore *
494873c82edSEric Moore */
495873c82edSEric Moore static void
mptspi_print_read_nego(struct _MPT_SCSI_HOST * hd,struct scsi_target * starget,u32 ii)496873c82edSEric Moore mptspi_print_read_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u32 ii)
497873c82edSEric Moore {
498d6ecdd63SPrakash, Sathya ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d Read = 0x%08x"
499873c82edSEric Moore " ( %s factor = 0x%02x @ offset = 0x%02x %s%s%s%s%s%s%s%s)\n",
500873c82edSEric Moore hd->ioc->name, starget->id, ii,
501873c82edSEric Moore ii & MPI_SCSIDEVPAGE0_NP_WIDE ? "Wide ": "",
502873c82edSEric Moore ((ii >> 8) & 0xFF), ((ii >> 16) & 0xFF),
503873c82edSEric Moore ii & MPI_SCSIDEVPAGE0_NP_IU ? "IU ": "",
504873c82edSEric Moore ii & MPI_SCSIDEVPAGE0_NP_DT ? "DT ": "",
505873c82edSEric Moore ii & MPI_SCSIDEVPAGE0_NP_QAS ? "QAS ": "",
506873c82edSEric Moore ii & MPI_SCSIDEVPAGE0_NP_HOLD_MCS ? "HOLDMCS ": "",
507873c82edSEric Moore ii & MPI_SCSIDEVPAGE0_NP_WR_FLOW ? "WRFLOW ": "",
508873c82edSEric Moore ii & MPI_SCSIDEVPAGE0_NP_RD_STRM ? "RDSTRM ": "",
509873c82edSEric Moore ii & MPI_SCSIDEVPAGE0_NP_RTI ? "RTI ": "",
510873c82edSEric Moore ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": ""));
511873c82edSEric Moore }
512873c82edSEric Moore
mptspi_read_spi_device_pg0(struct scsi_target * starget,struct _CONFIG_PAGE_SCSI_DEVICE_0 * pass_pg0)513c92f222eSJames Bottomley static int mptspi_read_spi_device_pg0(struct scsi_target *starget,
514c92f222eSJames Bottomley struct _CONFIG_PAGE_SCSI_DEVICE_0 *pass_pg0)
515c92f222eSJames Bottomley {
516c92f222eSJames Bottomley struct Scsi_Host *shost = dev_to_shost(&starget->dev);
517e7eae9f6SEric Moore struct _MPT_SCSI_HOST *hd = shost_priv(shost);
518c92f222eSJames Bottomley struct _MPT_ADAPTER *ioc = hd->ioc;
519bc6e089aSEric Moore struct _CONFIG_PAGE_SCSI_DEVICE_0 *spi_dev_pg0;
520bc6e089aSEric Moore dma_addr_t spi_dev_pg0_dma;
521c92f222eSJames Bottomley int size;
522c92f222eSJames Bottomley struct _x_config_parms cfg;
523c92f222eSJames Bottomley struct _CONFIG_PAGE_HEADER hdr;
524c92f222eSJames Bottomley int err = -EBUSY;
525c92f222eSJames Bottomley
526c92f222eSJames Bottomley /* No SPI parameters for RAID devices */
527c92f222eSJames Bottomley if (starget->channel == 0 &&
528793955f5SEric Moore mptspi_is_raid(hd, starget->id))
529c92f222eSJames Bottomley return -1;
530c92f222eSJames Bottomley
531c92f222eSJames Bottomley size = ioc->spi_data.sdp0length * 4;
532c92f222eSJames Bottomley /*
533c92f222eSJames Bottomley if (ioc->spi_data.sdp0length & 1)
534c92f222eSJames Bottomley size += size + 4;
535c92f222eSJames Bottomley size += 2048;
536c92f222eSJames Bottomley */
537c92f222eSJames Bottomley
538bc6e089aSEric Moore spi_dev_pg0 = dma_alloc_coherent(&ioc->pcidev->dev, size, &spi_dev_pg0_dma, GFP_KERNEL);
539bc6e089aSEric Moore if (spi_dev_pg0 == NULL) {
540c51d0beaSEric Moore starget_printk(KERN_ERR, starget, MYIOC_s_FMT
54129dd3609SEric Moore "dma_alloc_coherent for parameters failed\n", ioc->name);
542c92f222eSJames Bottomley return -EINVAL;
543c92f222eSJames Bottomley }
544c92f222eSJames Bottomley
545c92f222eSJames Bottomley memset(&hdr, 0, sizeof(hdr));
546c92f222eSJames Bottomley
547c92f222eSJames Bottomley hdr.PageVersion = ioc->spi_data.sdp0version;
548c92f222eSJames Bottomley hdr.PageLength = ioc->spi_data.sdp0length;
549c92f222eSJames Bottomley hdr.PageNumber = 0;
550c92f222eSJames Bottomley hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
551c92f222eSJames Bottomley
552c92f222eSJames Bottomley memset(&cfg, 0, sizeof(cfg));
553c92f222eSJames Bottomley
554c92f222eSJames Bottomley cfg.cfghdr.hdr = &hdr;
555bc6e089aSEric Moore cfg.physAddr = spi_dev_pg0_dma;
556c92f222eSJames Bottomley cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
557c92f222eSJames Bottomley cfg.dir = 0;
558c92f222eSJames Bottomley cfg.pageAddr = starget->id;
559f8c23bdeSKashyap, Desai cfg.timeout = 60;
560c92f222eSJames Bottomley
561c92f222eSJames Bottomley if (mpt_config(ioc, &cfg)) {
562c51d0beaSEric Moore starget_printk(KERN_ERR, starget, MYIOC_s_FMT "mpt_config failed\n", ioc->name);
563c92f222eSJames Bottomley goto out_free;
564c92f222eSJames Bottomley }
565c92f222eSJames Bottomley err = 0;
566bc6e089aSEric Moore memcpy(pass_pg0, spi_dev_pg0, size);
567c92f222eSJames Bottomley
568bc6e089aSEric Moore mptspi_print_read_nego(hd, starget, le32_to_cpu(spi_dev_pg0->NegotiatedParameters));
569873c82edSEric Moore
570c92f222eSJames Bottomley out_free:
571bc6e089aSEric Moore dma_free_coherent(&ioc->pcidev->dev, size, spi_dev_pg0, spi_dev_pg0_dma);
572c92f222eSJames Bottomley return err;
573c92f222eSJames Bottomley }
574c92f222eSJames Bottomley
mptspi_getRP(struct scsi_target * starget)575c92f222eSJames Bottomley static u32 mptspi_getRP(struct scsi_target *starget)
576c92f222eSJames Bottomley {
577c92f222eSJames Bottomley u32 nego = 0;
578c92f222eSJames Bottomley
579c92f222eSJames Bottomley nego |= spi_iu(starget) ? MPI_SCSIDEVPAGE1_RP_IU : 0;
580c92f222eSJames Bottomley nego |= spi_dt(starget) ? MPI_SCSIDEVPAGE1_RP_DT : 0;
581c92f222eSJames Bottomley nego |= spi_qas(starget) ? MPI_SCSIDEVPAGE1_RP_QAS : 0;
582c92f222eSJames Bottomley nego |= spi_hold_mcs(starget) ? MPI_SCSIDEVPAGE1_RP_HOLD_MCS : 0;
583c92f222eSJames Bottomley nego |= spi_wr_flow(starget) ? MPI_SCSIDEVPAGE1_RP_WR_FLOW : 0;
584c92f222eSJames Bottomley nego |= spi_rd_strm(starget) ? MPI_SCSIDEVPAGE1_RP_RD_STRM : 0;
585c92f222eSJames Bottomley nego |= spi_rti(starget) ? MPI_SCSIDEVPAGE1_RP_RTI : 0;
586c92f222eSJames Bottomley nego |= spi_pcomp_en(starget) ? MPI_SCSIDEVPAGE1_RP_PCOMP_EN : 0;
587c92f222eSJames Bottomley
588c92f222eSJames Bottomley nego |= (spi_period(starget) << MPI_SCSIDEVPAGE1_RP_SHIFT_MIN_SYNC_PERIOD) & MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK;
589c92f222eSJames Bottomley nego |= (spi_offset(starget) << MPI_SCSIDEVPAGE1_RP_SHIFT_MAX_SYNC_OFFSET) & MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK;
590c92f222eSJames Bottomley nego |= spi_width(starget) ? MPI_SCSIDEVPAGE1_RP_WIDE : 0;
591c92f222eSJames Bottomley
592c92f222eSJames Bottomley return nego;
593c92f222eSJames Bottomley }
594c92f222eSJames Bottomley
mptspi_read_parameters(struct scsi_target * starget)595c92f222eSJames Bottomley static void mptspi_read_parameters(struct scsi_target *starget)
596c92f222eSJames Bottomley {
597c92f222eSJames Bottomley int nego;
598bc6e089aSEric Moore struct _CONFIG_PAGE_SCSI_DEVICE_0 spi_dev_pg0;
599c92f222eSJames Bottomley
600bc6e089aSEric Moore mptspi_read_spi_device_pg0(starget, &spi_dev_pg0);
601c92f222eSJames Bottomley
602bc6e089aSEric Moore nego = le32_to_cpu(spi_dev_pg0.NegotiatedParameters);
603c92f222eSJames Bottomley
604c92f222eSJames Bottomley spi_iu(starget) = (nego & MPI_SCSIDEVPAGE0_NP_IU) ? 1 : 0;
605c92f222eSJames Bottomley spi_dt(starget) = (nego & MPI_SCSIDEVPAGE0_NP_DT) ? 1 : 0;
606c92f222eSJames Bottomley spi_qas(starget) = (nego & MPI_SCSIDEVPAGE0_NP_QAS) ? 1 : 0;
607c92f222eSJames Bottomley spi_wr_flow(starget) = (nego & MPI_SCSIDEVPAGE0_NP_WR_FLOW) ? 1 : 0;
608c92f222eSJames Bottomley spi_rd_strm(starget) = (nego & MPI_SCSIDEVPAGE0_NP_RD_STRM) ? 1 : 0;
609c92f222eSJames Bottomley spi_rti(starget) = (nego & MPI_SCSIDEVPAGE0_NP_RTI) ? 1 : 0;
610c92f222eSJames Bottomley spi_pcomp_en(starget) = (nego & MPI_SCSIDEVPAGE0_NP_PCOMP_EN) ? 1 : 0;
611c92f222eSJames Bottomley spi_hold_mcs(starget) = (nego & MPI_SCSIDEVPAGE0_NP_HOLD_MCS) ? 1 : 0;
612c92f222eSJames Bottomley spi_period(starget) = (nego & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> MPI_SCSIDEVPAGE0_NP_SHIFT_SYNC_PERIOD;
613c92f222eSJames Bottomley spi_offset(starget) = (nego & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) >> MPI_SCSIDEVPAGE0_NP_SHIFT_SYNC_OFFSET;
614c92f222eSJames Bottomley spi_width(starget) = (nego & MPI_SCSIDEVPAGE0_NP_WIDE) ? 1 : 0;
615c92f222eSJames Bottomley }
616c92f222eSJames Bottomley
6175767d25fSJoe Lawrence static int
mptscsih_quiesce_raid(MPT_SCSI_HOST * hd,int quiesce,u8 channel,u8 id)618793955f5SEric Moore mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id)
619c92f222eSJames Bottomley {
62037c60f37SKashyap, Desai MPT_ADAPTER *ioc = hd->ioc;
621c92f222eSJames Bottomley MpiRaidActionRequest_t *pReq;
622c92f222eSJames Bottomley MPT_FRAME_HDR *mf;
62337c60f37SKashyap, Desai int ret;
62437c60f37SKashyap, Desai unsigned long timeleft;
62537c60f37SKashyap, Desai
62637c60f37SKashyap, Desai mutex_lock(&ioc->internal_cmds.mutex);
627c92f222eSJames Bottomley
628c92f222eSJames Bottomley /* Get and Populate a free Frame
629c92f222eSJames Bottomley */
630e80b002bSEric Moore if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
63137c60f37SKashyap, Desai dfailprintk(hd->ioc, printk(MYIOC_s_WARN_FMT
63237c60f37SKashyap, Desai "%s: no msg frames!\n", ioc->name, __func__));
63337c60f37SKashyap, Desai ret = -EAGAIN;
63437c60f37SKashyap, Desai goto out;
635c92f222eSJames Bottomley }
636c92f222eSJames Bottomley pReq = (MpiRaidActionRequest_t *)mf;
637c92f222eSJames Bottomley if (quiesce)
638c92f222eSJames Bottomley pReq->Action = MPI_RAID_ACTION_QUIESCE_PHYS_IO;
639c92f222eSJames Bottomley else
640c92f222eSJames Bottomley pReq->Action = MPI_RAID_ACTION_ENABLE_PHYS_IO;
641c92f222eSJames Bottomley pReq->Reserved1 = 0;
642c92f222eSJames Bottomley pReq->ChainOffset = 0;
643c92f222eSJames Bottomley pReq->Function = MPI_FUNCTION_RAID_ACTION;
644793955f5SEric Moore pReq->VolumeID = id;
645793955f5SEric Moore pReq->VolumeBus = channel;
646c92f222eSJames Bottomley pReq->PhysDiskNum = 0;
647c92f222eSJames Bottomley pReq->MsgFlags = 0;
648c92f222eSJames Bottomley pReq->Reserved2 = 0;
649c92f222eSJames Bottomley pReq->ActionDataWord = 0; /* Reserved for this action */
650c92f222eSJames Bottomley
65114d0f0b0SKashyap, Desai ioc->add_sge((char *)&pReq->ActionDataSGE,
652c92f222eSJames Bottomley MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
653c92f222eSJames Bottomley
654e80b002bSEric Moore ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n",
655e80b002bSEric Moore ioc->name, pReq->Action, channel, id));
656c92f222eSJames Bottomley
65737c60f37SKashyap, Desai INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
658e80b002bSEric Moore mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
65937c60f37SKashyap, Desai timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done, 10*HZ);
66037c60f37SKashyap, Desai if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
66137c60f37SKashyap, Desai ret = -ETIME;
66237c60f37SKashyap, Desai dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: TIMED OUT!\n",
66337c60f37SKashyap, Desai ioc->name, __func__));
66437c60f37SKashyap, Desai if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
66537c60f37SKashyap, Desai goto out;
66637c60f37SKashyap, Desai if (!timeleft) {
66737c60f37SKashyap, Desai printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
66837c60f37SKashyap, Desai ioc->name, __func__);
66937c60f37SKashyap, Desai mpt_HardResetHandler(ioc, CAN_SLEEP);
67037c60f37SKashyap, Desai mpt_free_msg_frame(ioc, mf);
67137c60f37SKashyap, Desai }
67237c60f37SKashyap, Desai goto out;
67337c60f37SKashyap, Desai }
674c92f222eSJames Bottomley
67537c60f37SKashyap, Desai ret = ioc->internal_cmds.completion_code;
676c92f222eSJames Bottomley
67737c60f37SKashyap, Desai out:
67837c60f37SKashyap, Desai CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
67937c60f37SKashyap, Desai mutex_unlock(&ioc->internal_cmds.mutex);
68037c60f37SKashyap, Desai return ret;
681c92f222eSJames Bottomley }
682c92f222eSJames Bottomley
mptspi_dv_device(struct _MPT_SCSI_HOST * hd,struct scsi_device * sdev)683c92f222eSJames Bottomley static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
684c92f222eSJames Bottomley struct scsi_device *sdev)
685c92f222eSJames Bottomley {
686c92f222eSJames Bottomley VirtTarget *vtarget = scsi_target(sdev)->hostdata;
687e80b002bSEric Moore MPT_ADAPTER *ioc = hd->ioc;
688c92f222eSJames Bottomley
689c92f222eSJames Bottomley /* no DV on RAID devices */
690c92f222eSJames Bottomley if (sdev->channel == 0 &&
691793955f5SEric Moore mptspi_is_raid(hd, sdev->id))
692c92f222eSJames Bottomley return;
693c92f222eSJames Bottomley
694c92f222eSJames Bottomley /* If this is a piece of a RAID, then quiesce first */
695c92f222eSJames Bottomley if (sdev->channel == 1 &&
696793955f5SEric Moore mptscsih_quiesce_raid(hd, 1, vtarget->channel, vtarget->id) < 0) {
697c51d0beaSEric Moore starget_printk(KERN_ERR, scsi_target(sdev), MYIOC_s_FMT
698e80b002bSEric Moore "Integrated RAID quiesce failed\n", ioc->name);
699c92f222eSJames Bottomley return;
700c92f222eSJames Bottomley }
701c92f222eSJames Bottomley
70272978245SEric Moore hd->spi_pending |= (1 << sdev->id);
703c92f222eSJames Bottomley spi_dv_device(sdev);
70472978245SEric Moore hd->spi_pending &= ~(1 << sdev->id);
705c92f222eSJames Bottomley
706c92f222eSJames Bottomley if (sdev->channel == 1 &&
707793955f5SEric Moore mptscsih_quiesce_raid(hd, 0, vtarget->channel, vtarget->id) < 0)
708c51d0beaSEric Moore starget_printk(KERN_ERR, scsi_target(sdev), MYIOC_s_FMT
709e80b002bSEric Moore "Integrated RAID resume failed\n", ioc->name);
710c92f222eSJames Bottomley
711c92f222eSJames Bottomley mptspi_read_parameters(sdev->sdev_target);
712c92f222eSJames Bottomley spi_display_xfer_agreement(sdev->sdev_target);
713c92f222eSJames Bottomley mptspi_read_parameters(sdev->sdev_target);
714c92f222eSJames Bottomley }
715c92f222eSJames Bottomley
mptspi_slave_alloc(struct scsi_device * sdev)716c92f222eSJames Bottomley static int mptspi_slave_alloc(struct scsi_device *sdev)
717c92f222eSJames Bottomley {
718e7eae9f6SEric Moore MPT_SCSI_HOST *hd = shost_priv(sdev->host);
719793955f5SEric Moore VirtTarget *vtarget;
720a69de507SEric Moore VirtDevice *vdevice;
721793955f5SEric Moore struct scsi_target *starget;
722e80b002bSEric Moore MPT_ADAPTER *ioc = hd->ioc;
723c92f222eSJames Bottomley
724793955f5SEric Moore if (sdev->channel == 1 &&
725e80b002bSEric Moore mptscsih_is_phys_disk(ioc, 0, sdev->id) == 0)
726793955f5SEric Moore return -ENXIO;
727c92f222eSJames Bottomley
728a69de507SEric Moore vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
729a69de507SEric Moore if (!vdevice) {
730793955f5SEric Moore printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
731e80b002bSEric Moore ioc->name, sizeof(VirtDevice));
732793955f5SEric Moore return -ENOMEM;
733c92f222eSJames Bottomley }
734c92f222eSJames Bottomley
735a69de507SEric Moore vdevice->lun = sdev->lun;
736a69de507SEric Moore sdev->hostdata = vdevice;
737c92f222eSJames Bottomley
738793955f5SEric Moore starget = scsi_target(sdev);
739793955f5SEric Moore vtarget = starget->hostdata;
740a69de507SEric Moore vdevice->vtarget = vtarget;
741793955f5SEric Moore vtarget->num_luns++;
742c92f222eSJames Bottomley
743793955f5SEric Moore if (sdev->channel == 1)
744c92f222eSJames Bottomley sdev->no_uld_attach = 1;
745c92f222eSJames Bottomley
746c92f222eSJames Bottomley return 0;
747c92f222eSJames Bottomley }
748c92f222eSJames Bottomley
mptspi_slave_configure(struct scsi_device * sdev)749c92f222eSJames Bottomley static int mptspi_slave_configure(struct scsi_device *sdev)
750c92f222eSJames Bottomley {
751e7eae9f6SEric Moore struct _MPT_SCSI_HOST *hd = shost_priv(sdev->host);
7525a9c47b1SEric Moore VirtTarget *vtarget = scsi_target(sdev)->hostdata;
75329982e9aSDoug Chapman int ret;
75429982e9aSDoug Chapman
75529982e9aSDoug Chapman mptspi_initTarget(hd, vtarget, sdev);
75629982e9aSDoug Chapman
75729982e9aSDoug Chapman ret = mptscsih_slave_configure(sdev);
758c92f222eSJames Bottomley
759c92f222eSJames Bottomley if (ret)
760c92f222eSJames Bottomley return ret;
761c92f222eSJames Bottomley
762d6ecdd63SPrakash, Sathya ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d min_period=0x%02x"
763873c82edSEric Moore " max_offset=0x%02x max_width=%d\n", hd->ioc->name,
764873c82edSEric Moore sdev->id, spi_min_period(scsi_target(sdev)),
765873c82edSEric Moore spi_max_offset(scsi_target(sdev)),
766873c82edSEric Moore spi_max_width(scsi_target(sdev))));
767873c82edSEric Moore
768c92f222eSJames Bottomley if ((sdev->channel == 1 ||
769793955f5SEric Moore !(mptspi_is_raid(hd, sdev->id))) &&
770c92f222eSJames Bottomley !spi_initial_dv(sdev->sdev_target))
771c92f222eSJames Bottomley mptspi_dv_device(hd, sdev);
772c92f222eSJames Bottomley
773c92f222eSJames Bottomley return 0;
774c92f222eSJames Bottomley }
775c92f222eSJames Bottomley
776793955f5SEric Moore static int
mptspi_qcmd(struct Scsi_Host * shost,struct scsi_cmnd * SCpnt)777a48ac9e5SMatthew Wilcox mptspi_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt)
778793955f5SEric Moore {
779a48ac9e5SMatthew Wilcox struct _MPT_SCSI_HOST *hd = shost_priv(shost);
780a69de507SEric Moore VirtDevice *vdevice = SCpnt->device->hostdata;
781e80b002bSEric Moore MPT_ADAPTER *ioc = hd->ioc;
782793955f5SEric Moore
783a69de507SEric Moore if (!vdevice || !vdevice->vtarget) {
784793955f5SEric Moore SCpnt->result = DID_NO_CONNECT << 16;
7851ae6d167SBart Van Assche scsi_done(SCpnt);
786793955f5SEric Moore return 0;
787793955f5SEric Moore }
788793955f5SEric Moore
789793955f5SEric Moore if (SCpnt->device->channel == 1 &&
790e80b002bSEric Moore mptscsih_is_phys_disk(ioc, 0, SCpnt->device->id) == 0) {
791793955f5SEric Moore SCpnt->result = DID_NO_CONNECT << 16;
7921ae6d167SBart Van Assche scsi_done(SCpnt);
793793955f5SEric Moore return 0;
794793955f5SEric Moore }
795793955f5SEric Moore
796873c82edSEric Moore if (spi_dv_pending(scsi_target(SCpnt->device)))
797e80b002bSEric Moore ddvprintk(ioc, scsi_print_command(SCpnt));
798873c82edSEric Moore
799a48ac9e5SMatthew Wilcox return mptscsih_qcmd(SCpnt);
800793955f5SEric Moore }
801793955f5SEric Moore
mptspi_slave_destroy(struct scsi_device * sdev)802c92f222eSJames Bottomley static void mptspi_slave_destroy(struct scsi_device *sdev)
803c92f222eSJames Bottomley {
804c92f222eSJames Bottomley struct scsi_target *starget = scsi_target(sdev);
805c92f222eSJames Bottomley VirtTarget *vtarget = starget->hostdata;
806c92f222eSJames Bottomley VirtDevice *vdevice = sdev->hostdata;
807c92f222eSJames Bottomley
808c92f222eSJames Bottomley /* Will this be the last lun on a non-raid device? */
809c92f222eSJames Bottomley if (vtarget->num_luns == 1 && vdevice->configured_lun) {
810c92f222eSJames Bottomley struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
811c92f222eSJames Bottomley
812c92f222eSJames Bottomley /* Async Narrow */
813c92f222eSJames Bottomley pg1.RequestedParameters = 0;
814c92f222eSJames Bottomley pg1.Reserved = 0;
815c92f222eSJames Bottomley pg1.Configuration = 0;
816c92f222eSJames Bottomley
817c92f222eSJames Bottomley mptspi_write_spi_device_pg1(starget, &pg1);
818c92f222eSJames Bottomley }
819c92f222eSJames Bottomley
820c92f222eSJames Bottomley mptscsih_slave_destroy(sdev);
821c92f222eSJames Bottomley }
822c92f222eSJames Bottomley
823*95a24cf1SBart Van Assche static const struct scsi_host_template mptspi_driver_template = {
824f78496daSMoore, Eric Dean .module = THIS_MODULE,
825243eabcfSMoore, Eric Dean .proc_name = "mptspi",
826cac19703SAl Viro .show_info = mptscsih_show_info,
827243eabcfSMoore, Eric Dean .name = "MPT SPI Host",
828243eabcfSMoore, Eric Dean .info = mptscsih_info,
829793955f5SEric Moore .queuecommand = mptspi_qcmd,
830c92f222eSJames Bottomley .target_alloc = mptspi_target_alloc,
831c92f222eSJames Bottomley .slave_alloc = mptspi_slave_alloc,
832c92f222eSJames Bottomley .slave_configure = mptspi_slave_configure,
833793955f5SEric Moore .target_destroy = mptspi_target_destroy,
834c92f222eSJames Bottomley .slave_destroy = mptspi_slave_destroy,
8356e3815baSMoore, Eric Dean .change_queue_depth = mptscsih_change_queue_depth,
836243eabcfSMoore, Eric Dean .eh_abort_handler = mptscsih_abort,
837243eabcfSMoore, Eric Dean .eh_device_reset_handler = mptscsih_dev_reset,
838243eabcfSMoore, Eric Dean .eh_bus_reset_handler = mptscsih_bus_reset,
839243eabcfSMoore, Eric Dean .eh_host_reset_handler = mptscsih_host_reset,
840243eabcfSMoore, Eric Dean .bios_param = mptscsih_bios_param,
841243eabcfSMoore, Eric Dean .can_queue = MPT_SCSI_CAN_QUEUE,
842243eabcfSMoore, Eric Dean .this_id = -1,
843243eabcfSMoore, Eric Dean .sg_tablesize = MPT_SCSI_SG_DEPTH,
844243eabcfSMoore, Eric Dean .max_sectors = 8192,
845243eabcfSMoore, Eric Dean .cmd_per_lun = 7,
8462899836fSBart Van Assche .shost_groups = mptscsih_host_attr_groups,
847243eabcfSMoore, Eric Dean };
848243eabcfSMoore, Eric Dean
mptspi_write_spi_device_pg1(struct scsi_target * starget,struct _CONFIG_PAGE_SCSI_DEVICE_1 * pass_pg1)849c92f222eSJames Bottomley static int mptspi_write_spi_device_pg1(struct scsi_target *starget,
850c92f222eSJames Bottomley struct _CONFIG_PAGE_SCSI_DEVICE_1 *pass_pg1)
851c92f222eSJames Bottomley {
852c92f222eSJames Bottomley struct Scsi_Host *shost = dev_to_shost(&starget->dev);
853e7eae9f6SEric Moore struct _MPT_SCSI_HOST *hd = shost_priv(shost);
854c92f222eSJames Bottomley struct _MPT_ADAPTER *ioc = hd->ioc;
855c92f222eSJames Bottomley struct _CONFIG_PAGE_SCSI_DEVICE_1 *pg1;
856c92f222eSJames Bottomley dma_addr_t pg1_dma;
857c92f222eSJames Bottomley int size;
858c92f222eSJames Bottomley struct _x_config_parms cfg;
859c92f222eSJames Bottomley struct _CONFIG_PAGE_HEADER hdr;
860c92f222eSJames Bottomley int err = -EBUSY;
86119fff154SKashyap, Desai u32 nego_parms;
86219fff154SKashyap, Desai u32 period;
86319fff154SKashyap, Desai struct scsi_device *sdev;
86419fff154SKashyap, Desai int i;
865c92f222eSJames Bottomley
866c92f222eSJames Bottomley /* don't allow updating nego parameters on RAID devices */
867c92f222eSJames Bottomley if (starget->channel == 0 &&
868793955f5SEric Moore mptspi_is_raid(hd, starget->id))
869c92f222eSJames Bottomley return -1;
870c92f222eSJames Bottomley
871c92f222eSJames Bottomley size = ioc->spi_data.sdp1length * 4;
872c92f222eSJames Bottomley
873c92f222eSJames Bottomley pg1 = dma_alloc_coherent(&ioc->pcidev->dev, size, &pg1_dma, GFP_KERNEL);
874c92f222eSJames Bottomley if (pg1 == NULL) {
875c51d0beaSEric Moore starget_printk(KERN_ERR, starget, MYIOC_s_FMT
87629dd3609SEric Moore "dma_alloc_coherent for parameters failed\n", ioc->name);
877c92f222eSJames Bottomley return -EINVAL;
878c92f222eSJames Bottomley }
879c92f222eSJames Bottomley
880c92f222eSJames Bottomley memset(&hdr, 0, sizeof(hdr));
881c92f222eSJames Bottomley
882c92f222eSJames Bottomley hdr.PageVersion = ioc->spi_data.sdp1version;
883c92f222eSJames Bottomley hdr.PageLength = ioc->spi_data.sdp1length;
884c92f222eSJames Bottomley hdr.PageNumber = 1;
885c92f222eSJames Bottomley hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
886c92f222eSJames Bottomley
887c92f222eSJames Bottomley memset(&cfg, 0, sizeof(cfg));
888c92f222eSJames Bottomley
889c92f222eSJames Bottomley cfg.cfghdr.hdr = &hdr;
890c92f222eSJames Bottomley cfg.physAddr = pg1_dma;
891c92f222eSJames Bottomley cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
892c92f222eSJames Bottomley cfg.dir = 1;
893c92f222eSJames Bottomley cfg.pageAddr = starget->id;
894c92f222eSJames Bottomley
895c92f222eSJames Bottomley memcpy(pg1, pass_pg1, size);
896c92f222eSJames Bottomley
897c92f222eSJames Bottomley pg1->Header.PageVersion = hdr.PageVersion;
898c92f222eSJames Bottomley pg1->Header.PageLength = hdr.PageLength;
899c92f222eSJames Bottomley pg1->Header.PageNumber = hdr.PageNumber;
900c92f222eSJames Bottomley pg1->Header.PageType = hdr.PageType;
901c92f222eSJames Bottomley
90219fff154SKashyap, Desai nego_parms = le32_to_cpu(pg1->RequestedParameters);
90319fff154SKashyap, Desai period = (nego_parms & MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK) >>
90419fff154SKashyap, Desai MPI_SCSIDEVPAGE1_RP_SHIFT_MIN_SYNC_PERIOD;
90519fff154SKashyap, Desai if (period == 8) {
90619fff154SKashyap, Desai /* Turn on inline data padding for TAPE when running U320 */
90719fff154SKashyap, Desai for (i = 0 ; i < 16; i++) {
90819fff154SKashyap, Desai sdev = scsi_device_lookup_by_target(starget, i);
90919fff154SKashyap, Desai if (sdev && sdev->type == TYPE_TAPE) {
91019fff154SKashyap, Desai sdev_printk(KERN_DEBUG, sdev, MYIOC_s_FMT
91119fff154SKashyap, Desai "IDP:ON\n", ioc->name);
91219fff154SKashyap, Desai nego_parms |= MPI_SCSIDEVPAGE1_RP_IDP;
91319fff154SKashyap, Desai pg1->RequestedParameters =
91419fff154SKashyap, Desai cpu_to_le32(nego_parms);
91519fff154SKashyap, Desai break;
91619fff154SKashyap, Desai }
91719fff154SKashyap, Desai }
91819fff154SKashyap, Desai }
91919fff154SKashyap, Desai
920873c82edSEric Moore mptspi_print_write_nego(hd, starget, le32_to_cpu(pg1->RequestedParameters));
921873c82edSEric Moore
922c92f222eSJames Bottomley if (mpt_config(ioc, &cfg)) {
923c51d0beaSEric Moore starget_printk(KERN_ERR, starget, MYIOC_s_FMT
92429dd3609SEric Moore "mpt_config failed\n", ioc->name);
925c92f222eSJames Bottomley goto out_free;
926c92f222eSJames Bottomley }
927c92f222eSJames Bottomley err = 0;
928c92f222eSJames Bottomley
929c92f222eSJames Bottomley out_free:
930c92f222eSJames Bottomley dma_free_coherent(&ioc->pcidev->dev, size, pg1, pg1_dma);
931c92f222eSJames Bottomley return err;
932c92f222eSJames Bottomley }
933c92f222eSJames Bottomley
mptspi_write_offset(struct scsi_target * starget,int offset)934c92f222eSJames Bottomley static void mptspi_write_offset(struct scsi_target *starget, int offset)
935c92f222eSJames Bottomley {
936c92f222eSJames Bottomley struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
937c92f222eSJames Bottomley u32 nego;
938c92f222eSJames Bottomley
939c92f222eSJames Bottomley if (offset < 0)
940c92f222eSJames Bottomley offset = 0;
941c92f222eSJames Bottomley
942c92f222eSJames Bottomley if (offset > 255)
943c92f222eSJames Bottomley offset = 255;
944c92f222eSJames Bottomley
945c92f222eSJames Bottomley if (spi_offset(starget) == -1)
946c92f222eSJames Bottomley mptspi_read_parameters(starget);
947c92f222eSJames Bottomley
948c92f222eSJames Bottomley spi_offset(starget) = offset;
949c92f222eSJames Bottomley
950c92f222eSJames Bottomley nego = mptspi_getRP(starget);
951c92f222eSJames Bottomley
952c92f222eSJames Bottomley pg1.RequestedParameters = cpu_to_le32(nego);
953c92f222eSJames Bottomley pg1.Reserved = 0;
954c92f222eSJames Bottomley pg1.Configuration = 0;
955c92f222eSJames Bottomley
956c92f222eSJames Bottomley mptspi_write_spi_device_pg1(starget, &pg1);
957c92f222eSJames Bottomley }
958c92f222eSJames Bottomley
mptspi_write_period(struct scsi_target * starget,int period)959c92f222eSJames Bottomley static void mptspi_write_period(struct scsi_target *starget, int period)
960c92f222eSJames Bottomley {
961c92f222eSJames Bottomley struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
962c92f222eSJames Bottomley u32 nego;
963c92f222eSJames Bottomley
964c92f222eSJames Bottomley if (period < 8)
965c92f222eSJames Bottomley period = 8;
966c92f222eSJames Bottomley
967c92f222eSJames Bottomley if (period > 255)
968c92f222eSJames Bottomley period = 255;
969c92f222eSJames Bottomley
970c92f222eSJames Bottomley if (spi_period(starget) == -1)
971c92f222eSJames Bottomley mptspi_read_parameters(starget);
972c92f222eSJames Bottomley
973c92f222eSJames Bottomley if (period == 8) {
974c92f222eSJames Bottomley spi_iu(starget) = 1;
975c92f222eSJames Bottomley spi_dt(starget) = 1;
976c92f222eSJames Bottomley } else if (period == 9) {
977c92f222eSJames Bottomley spi_dt(starget) = 1;
978c92f222eSJames Bottomley }
979c92f222eSJames Bottomley
980c92f222eSJames Bottomley spi_period(starget) = period;
981c92f222eSJames Bottomley
982c92f222eSJames Bottomley nego = mptspi_getRP(starget);
983c92f222eSJames Bottomley
984c92f222eSJames Bottomley pg1.RequestedParameters = cpu_to_le32(nego);
985c92f222eSJames Bottomley pg1.Reserved = 0;
986c92f222eSJames Bottomley pg1.Configuration = 0;
987c92f222eSJames Bottomley
988c92f222eSJames Bottomley mptspi_write_spi_device_pg1(starget, &pg1);
989c92f222eSJames Bottomley }
990c92f222eSJames Bottomley
mptspi_write_dt(struct scsi_target * starget,int dt)991c92f222eSJames Bottomley static void mptspi_write_dt(struct scsi_target *starget, int dt)
992c92f222eSJames Bottomley {
993c92f222eSJames Bottomley struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
994c92f222eSJames Bottomley u32 nego;
995c92f222eSJames Bottomley
996c92f222eSJames Bottomley if (spi_period(starget) == -1)
997c92f222eSJames Bottomley mptspi_read_parameters(starget);
998c92f222eSJames Bottomley
999c92f222eSJames Bottomley if (!dt && spi_period(starget) < 10)
1000c92f222eSJames Bottomley spi_period(starget) = 10;
1001c92f222eSJames Bottomley
1002c92f222eSJames Bottomley spi_dt(starget) = dt;
1003c92f222eSJames Bottomley
1004c92f222eSJames Bottomley nego = mptspi_getRP(starget);
1005c92f222eSJames Bottomley
1006c92f222eSJames Bottomley
1007c92f222eSJames Bottomley pg1.RequestedParameters = cpu_to_le32(nego);
1008c92f222eSJames Bottomley pg1.Reserved = 0;
1009c92f222eSJames Bottomley pg1.Configuration = 0;
1010c92f222eSJames Bottomley
1011c92f222eSJames Bottomley mptspi_write_spi_device_pg1(starget, &pg1);
1012c92f222eSJames Bottomley }
1013c92f222eSJames Bottomley
mptspi_write_iu(struct scsi_target * starget,int iu)1014c92f222eSJames Bottomley static void mptspi_write_iu(struct scsi_target *starget, int iu)
1015c92f222eSJames Bottomley {
1016c92f222eSJames Bottomley struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
1017c92f222eSJames Bottomley u32 nego;
1018c92f222eSJames Bottomley
1019c92f222eSJames Bottomley if (spi_period(starget) == -1)
1020c92f222eSJames Bottomley mptspi_read_parameters(starget);
1021c92f222eSJames Bottomley
1022c92f222eSJames Bottomley if (!iu && spi_period(starget) < 9)
1023c92f222eSJames Bottomley spi_period(starget) = 9;
1024c92f222eSJames Bottomley
1025c92f222eSJames Bottomley spi_iu(starget) = iu;
1026c92f222eSJames Bottomley
1027c92f222eSJames Bottomley nego = mptspi_getRP(starget);
1028c92f222eSJames Bottomley
1029c92f222eSJames Bottomley pg1.RequestedParameters = cpu_to_le32(nego);
1030c92f222eSJames Bottomley pg1.Reserved = 0;
1031c92f222eSJames Bottomley pg1.Configuration = 0;
1032c92f222eSJames Bottomley
1033c92f222eSJames Bottomley mptspi_write_spi_device_pg1(starget, &pg1);
1034c92f222eSJames Bottomley }
1035c92f222eSJames Bottomley
1036c92f222eSJames Bottomley #define MPTSPI_SIMPLE_TRANSPORT_PARM(parm) \
1037c92f222eSJames Bottomley static void mptspi_write_##parm(struct scsi_target *starget, int parm)\
1038c92f222eSJames Bottomley { \
1039c92f222eSJames Bottomley struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; \
1040c92f222eSJames Bottomley u32 nego; \
1041c92f222eSJames Bottomley \
1042c92f222eSJames Bottomley spi_##parm(starget) = parm; \
1043c92f222eSJames Bottomley \
1044c92f222eSJames Bottomley nego = mptspi_getRP(starget); \
1045c92f222eSJames Bottomley \
1046c92f222eSJames Bottomley pg1.RequestedParameters = cpu_to_le32(nego); \
1047c92f222eSJames Bottomley pg1.Reserved = 0; \
1048c92f222eSJames Bottomley pg1.Configuration = 0; \
1049c92f222eSJames Bottomley \
1050c92f222eSJames Bottomley mptspi_write_spi_device_pg1(starget, &pg1); \
1051c92f222eSJames Bottomley }
1052c92f222eSJames Bottomley
1053c92f222eSJames Bottomley MPTSPI_SIMPLE_TRANSPORT_PARM(rd_strm)
MPTSPI_SIMPLE_TRANSPORT_PARM(wr_flow)1054c92f222eSJames Bottomley MPTSPI_SIMPLE_TRANSPORT_PARM(wr_flow)
1055c92f222eSJames Bottomley MPTSPI_SIMPLE_TRANSPORT_PARM(rti)
1056c92f222eSJames Bottomley MPTSPI_SIMPLE_TRANSPORT_PARM(hold_mcs)
1057c92f222eSJames Bottomley MPTSPI_SIMPLE_TRANSPORT_PARM(pcomp_en)
1058c92f222eSJames Bottomley
1059c92f222eSJames Bottomley static void mptspi_write_qas(struct scsi_target *starget, int qas)
1060c92f222eSJames Bottomley {
1061c92f222eSJames Bottomley struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
1062c92f222eSJames Bottomley struct Scsi_Host *shost = dev_to_shost(&starget->dev);
1063e7eae9f6SEric Moore struct _MPT_SCSI_HOST *hd = shost_priv(shost);
1064c92f222eSJames Bottomley VirtTarget *vtarget = starget->hostdata;
1065c92f222eSJames Bottomley u32 nego;
1066c92f222eSJames Bottomley
1067c92f222eSJames Bottomley if ((vtarget->negoFlags & MPT_TARGET_NO_NEGO_QAS) ||
1068c92f222eSJames Bottomley hd->ioc->spi_data.noQas)
1069c92f222eSJames Bottomley spi_qas(starget) = 0;
1070c92f222eSJames Bottomley else
1071c92f222eSJames Bottomley spi_qas(starget) = qas;
1072c92f222eSJames Bottomley
1073c92f222eSJames Bottomley nego = mptspi_getRP(starget);
1074c92f222eSJames Bottomley
1075c92f222eSJames Bottomley pg1.RequestedParameters = cpu_to_le32(nego);
1076c92f222eSJames Bottomley pg1.Reserved = 0;
1077c92f222eSJames Bottomley pg1.Configuration = 0;
1078c92f222eSJames Bottomley
1079c92f222eSJames Bottomley mptspi_write_spi_device_pg1(starget, &pg1);
1080c92f222eSJames Bottomley }
1081c92f222eSJames Bottomley
mptspi_write_width(struct scsi_target * starget,int width)1082c92f222eSJames Bottomley static void mptspi_write_width(struct scsi_target *starget, int width)
1083c92f222eSJames Bottomley {
1084c92f222eSJames Bottomley struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
1085c92f222eSJames Bottomley u32 nego;
1086c92f222eSJames Bottomley
1087c92f222eSJames Bottomley if (!width) {
1088c92f222eSJames Bottomley spi_dt(starget) = 0;
1089c92f222eSJames Bottomley if (spi_period(starget) < 10)
1090c92f222eSJames Bottomley spi_period(starget) = 10;
1091c92f222eSJames Bottomley }
1092c92f222eSJames Bottomley
1093c92f222eSJames Bottomley spi_width(starget) = width;
1094c92f222eSJames Bottomley
1095c92f222eSJames Bottomley nego = mptspi_getRP(starget);
1096c92f222eSJames Bottomley
1097c92f222eSJames Bottomley pg1.RequestedParameters = cpu_to_le32(nego);
1098c92f222eSJames Bottomley pg1.Reserved = 0;
1099c92f222eSJames Bottomley pg1.Configuration = 0;
1100c92f222eSJames Bottomley
1101c92f222eSJames Bottomley mptspi_write_spi_device_pg1(starget, &pg1);
1102c92f222eSJames Bottomley }
1103c92f222eSJames Bottomley
1104c92f222eSJames Bottomley struct work_queue_wrapper {
1105c92f222eSJames Bottomley struct work_struct work;
1106c92f222eSJames Bottomley struct _MPT_SCSI_HOST *hd;
1107c92f222eSJames Bottomley int disk;
1108c92f222eSJames Bottomley };
1109c92f222eSJames Bottomley
mpt_work_wrapper(struct work_struct * work)1110c4028958SDavid Howells static void mpt_work_wrapper(struct work_struct *work)
1111c92f222eSJames Bottomley {
1112c4028958SDavid Howells struct work_queue_wrapper *wqw =
1113c4028958SDavid Howells container_of(work, struct work_queue_wrapper, work);
1114c92f222eSJames Bottomley struct _MPT_SCSI_HOST *hd = wqw->hd;
1115e80b002bSEric Moore MPT_ADAPTER *ioc = hd->ioc;
1116e80b002bSEric Moore struct Scsi_Host *shost = ioc->sh;
1117c92f222eSJames Bottomley struct scsi_device *sdev;
1118c92f222eSJames Bottomley int disk = wqw->disk;
1119c92f222eSJames Bottomley struct _CONFIG_PAGE_IOC_3 *pg3;
1120c92f222eSJames Bottomley
1121c92f222eSJames Bottomley kfree(wqw);
1122c92f222eSJames Bottomley
1123e80b002bSEric Moore mpt_findImVolumes(ioc);
1124e80b002bSEric Moore pg3 = ioc->raid_data.pIocPg3;
1125c92f222eSJames Bottomley if (!pg3)
1126c92f222eSJames Bottomley return;
1127c92f222eSJames Bottomley
1128c92f222eSJames Bottomley shost_for_each_device(sdev,shost) {
1129c92f222eSJames Bottomley struct scsi_target *starget = scsi_target(sdev);
1130c92f222eSJames Bottomley VirtTarget *vtarget = starget->hostdata;
1131c92f222eSJames Bottomley
1132c92f222eSJames Bottomley /* only want to search RAID components */
1133c92f222eSJames Bottomley if (sdev->channel != 1)
1134c92f222eSJames Bottomley continue;
1135c92f222eSJames Bottomley
1136793955f5SEric Moore /* The id is the raid PhysDiskNum, even if
1137c92f222eSJames Bottomley * starget->id is the actual target address */
1138793955f5SEric Moore if(vtarget->id != disk)
1139c92f222eSJames Bottomley continue;
1140c92f222eSJames Bottomley
1141c51d0beaSEric Moore starget_printk(KERN_INFO, vtarget->starget, MYIOC_s_FMT
1142e80b002bSEric Moore "Integrated RAID requests DV of new device\n", ioc->name);
1143c92f222eSJames Bottomley mptspi_dv_device(hd, sdev);
1144c92f222eSJames Bottomley }
1145c51d0beaSEric Moore shost_printk(KERN_INFO, shost, MYIOC_s_FMT
1146e80b002bSEric Moore "Integrated RAID detects new device %d\n", ioc->name, disk);
11471d645088SHannes Reinecke scsi_scan_target(&ioc->sh->shost_gendev, 1, disk, 0, SCSI_SCAN_RESCAN);
1148c92f222eSJames Bottomley }
1149c92f222eSJames Bottomley
1150c92f222eSJames Bottomley
mpt_dv_raid(struct _MPT_SCSI_HOST * hd,int disk)1151c92f222eSJames Bottomley static void mpt_dv_raid(struct _MPT_SCSI_HOST *hd, int disk)
1152c92f222eSJames Bottomley {
1153c92f222eSJames Bottomley struct work_queue_wrapper *wqw = kmalloc(sizeof(*wqw), GFP_ATOMIC);
1154e80b002bSEric Moore MPT_ADAPTER *ioc = hd->ioc;
1155c92f222eSJames Bottomley
1156c92f222eSJames Bottomley if (!wqw) {
1157c51d0beaSEric Moore shost_printk(KERN_ERR, ioc->sh, MYIOC_s_FMT
1158c92f222eSJames Bottomley "Failed to act on RAID event for physical disk %d\n",
1159e80b002bSEric Moore ioc->name, disk);
1160c92f222eSJames Bottomley return;
1161c92f222eSJames Bottomley }
1162c4028958SDavid Howells INIT_WORK(&wqw->work, mpt_work_wrapper);
1163c92f222eSJames Bottomley wqw->hd = hd;
1164c92f222eSJames Bottomley wqw->disk = disk;
1165c92f222eSJames Bottomley
1166c92f222eSJames Bottomley schedule_work(&wqw->work);
1167c92f222eSJames Bottomley }
1168c92f222eSJames Bottomley
1169c92f222eSJames Bottomley static int
mptspi_event_process(MPT_ADAPTER * ioc,EventNotificationReply_t * pEvReply)1170c92f222eSJames Bottomley mptspi_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
1171c92f222eSJames Bottomley {
1172c92f222eSJames Bottomley u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
1173e7eae9f6SEric Moore struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
1174c92f222eSJames Bottomley
1175ffb7fef3SKashyap, Desai if (ioc->bus_type != SPI)
1176ffb7fef3SKashyap, Desai return 0;
1177ffb7fef3SKashyap, Desai
1178c92f222eSJames Bottomley if (hd && event == MPI_EVENT_INTEGRATED_RAID) {
1179c92f222eSJames Bottomley int reason
1180c92f222eSJames Bottomley = (le32_to_cpu(pEvReply->Data[0]) & 0x00FF0000) >> 16;
1181c92f222eSJames Bottomley
1182c92f222eSJames Bottomley if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
1183c92f222eSJames Bottomley int disk = (le32_to_cpu(pEvReply->Data[0]) & 0xFF000000) >> 24;
1184c92f222eSJames Bottomley mpt_dv_raid(hd, disk);
1185c92f222eSJames Bottomley }
1186c92f222eSJames Bottomley }
1187c92f222eSJames Bottomley return mptscsih_event_process(ioc, pEvReply);
1188c92f222eSJames Bottomley }
1189c92f222eSJames Bottomley
1190c92f222eSJames Bottomley static int
mptspi_deny_binding(struct scsi_target * starget)1191c92f222eSJames Bottomley mptspi_deny_binding(struct scsi_target *starget)
1192c92f222eSJames Bottomley {
1193c92f222eSJames Bottomley struct _MPT_SCSI_HOST *hd =
1194c92f222eSJames Bottomley (struct _MPT_SCSI_HOST *)dev_to_shost(starget->dev.parent)->hostdata;
1195793955f5SEric Moore return ((mptspi_is_raid(hd, starget->id)) &&
1196c92f222eSJames Bottomley starget->channel == 0) ? 1 : 0;
1197c92f222eSJames Bottomley }
1198c92f222eSJames Bottomley
1199c92f222eSJames Bottomley static struct spi_function_template mptspi_transport_functions = {
1200c92f222eSJames Bottomley .get_offset = mptspi_read_parameters,
1201c92f222eSJames Bottomley .set_offset = mptspi_write_offset,
1202c92f222eSJames Bottomley .show_offset = 1,
1203c92f222eSJames Bottomley .get_period = mptspi_read_parameters,
1204c92f222eSJames Bottomley .set_period = mptspi_write_period,
1205c92f222eSJames Bottomley .show_period = 1,
1206c92f222eSJames Bottomley .get_width = mptspi_read_parameters,
1207c92f222eSJames Bottomley .set_width = mptspi_write_width,
1208c92f222eSJames Bottomley .show_width = 1,
1209c92f222eSJames Bottomley .get_iu = mptspi_read_parameters,
1210c92f222eSJames Bottomley .set_iu = mptspi_write_iu,
1211c92f222eSJames Bottomley .show_iu = 1,
1212c92f222eSJames Bottomley .get_dt = mptspi_read_parameters,
1213c92f222eSJames Bottomley .set_dt = mptspi_write_dt,
1214c92f222eSJames Bottomley .show_dt = 1,
1215c92f222eSJames Bottomley .get_qas = mptspi_read_parameters,
1216c92f222eSJames Bottomley .set_qas = mptspi_write_qas,
1217c92f222eSJames Bottomley .show_qas = 1,
1218c92f222eSJames Bottomley .get_wr_flow = mptspi_read_parameters,
1219c92f222eSJames Bottomley .set_wr_flow = mptspi_write_wr_flow,
1220c92f222eSJames Bottomley .show_wr_flow = 1,
1221c92f222eSJames Bottomley .get_rd_strm = mptspi_read_parameters,
1222c92f222eSJames Bottomley .set_rd_strm = mptspi_write_rd_strm,
1223c92f222eSJames Bottomley .show_rd_strm = 1,
1224c92f222eSJames Bottomley .get_rti = mptspi_read_parameters,
1225c92f222eSJames Bottomley .set_rti = mptspi_write_rti,
1226c92f222eSJames Bottomley .show_rti = 1,
1227c92f222eSJames Bottomley .get_pcomp_en = mptspi_read_parameters,
1228c92f222eSJames Bottomley .set_pcomp_en = mptspi_write_pcomp_en,
1229c92f222eSJames Bottomley .show_pcomp_en = 1,
1230c92f222eSJames Bottomley .get_hold_mcs = mptspi_read_parameters,
1231c92f222eSJames Bottomley .set_hold_mcs = mptspi_write_hold_mcs,
1232c92f222eSJames Bottomley .show_hold_mcs = 1,
1233c92f222eSJames Bottomley .deny_binding = mptspi_deny_binding,
1234c92f222eSJames Bottomley };
1235243eabcfSMoore, Eric Dean
1236243eabcfSMoore, Eric Dean /****************************************************************************
1237243eabcfSMoore, Eric Dean * Supported hardware
1238243eabcfSMoore, Eric Dean */
1239243eabcfSMoore, Eric Dean
1240243eabcfSMoore, Eric Dean static struct pci_device_id mptspi_pci_table[] = {
124187cf8986SEric Moore { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1030,
1242243eabcfSMoore, Eric Dean PCI_ANY_ID, PCI_ANY_ID },
1243232f08fcSEric Moore { PCI_VENDOR_ID_ATTO, MPI_MANUFACTPAGE_DEVID_53C1030,
1244232f08fcSEric Moore PCI_ANY_ID, PCI_ANY_ID },
124587cf8986SEric Moore { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1035,
1246243eabcfSMoore, Eric Dean PCI_ANY_ID, PCI_ANY_ID },
1247243eabcfSMoore, Eric Dean {0} /* Terminating entry */
1248243eabcfSMoore, Eric Dean };
1249243eabcfSMoore, Eric Dean MODULE_DEVICE_TABLE(pci, mptspi_pci_table);
1250243eabcfSMoore, Eric Dean
12516e1cad02SEric Moore
12526e1cad02SEric Moore /*
12536e1cad02SEric Moore * renegotiate for a given target
12546e1cad02SEric Moore */
12556e1cad02SEric Moore static void
mptspi_dv_renegotiate_work(struct work_struct * work)1256c4028958SDavid Howells mptspi_dv_renegotiate_work(struct work_struct *work)
12576e1cad02SEric Moore {
1258c4028958SDavid Howells struct work_queue_wrapper *wqw =
1259c4028958SDavid Howells container_of(work, struct work_queue_wrapper, work);
12606e1cad02SEric Moore struct _MPT_SCSI_HOST *hd = wqw->hd;
12616e1cad02SEric Moore struct scsi_device *sdev;
126272978245SEric Moore struct scsi_target *starget;
126372978245SEric Moore struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
126472978245SEric Moore u32 nego;
1265e80b002bSEric Moore MPT_ADAPTER *ioc = hd->ioc;
12666e1cad02SEric Moore
12676e1cad02SEric Moore kfree(wqw);
12686e1cad02SEric Moore
126972978245SEric Moore if (hd->spi_pending) {
1270e80b002bSEric Moore shost_for_each_device(sdev, ioc->sh) {
127172978245SEric Moore if (hd->spi_pending & (1 << sdev->id))
127272978245SEric Moore continue;
127372978245SEric Moore starget = scsi_target(sdev);
127472978245SEric Moore nego = mptspi_getRP(starget);
127572978245SEric Moore pg1.RequestedParameters = cpu_to_le32(nego);
127672978245SEric Moore pg1.Reserved = 0;
127772978245SEric Moore pg1.Configuration = 0;
127872978245SEric Moore mptspi_write_spi_device_pg1(starget, &pg1);
127972978245SEric Moore }
128072978245SEric Moore } else {
1281e80b002bSEric Moore shost_for_each_device(sdev, ioc->sh)
12826e1cad02SEric Moore mptspi_dv_device(hd, sdev);
12836e1cad02SEric Moore }
128472978245SEric Moore }
12856e1cad02SEric Moore
12866e1cad02SEric Moore static void
mptspi_dv_renegotiate(struct _MPT_SCSI_HOST * hd)12876e1cad02SEric Moore mptspi_dv_renegotiate(struct _MPT_SCSI_HOST *hd)
12886e1cad02SEric Moore {
12896e1cad02SEric Moore struct work_queue_wrapper *wqw = kmalloc(sizeof(*wqw), GFP_ATOMIC);
12906e1cad02SEric Moore
12916e1cad02SEric Moore if (!wqw)
12926e1cad02SEric Moore return;
12936e1cad02SEric Moore
1294c4028958SDavid Howells INIT_WORK(&wqw->work, mptspi_dv_renegotiate_work);
12956e1cad02SEric Moore wqw->hd = hd;
12966e1cad02SEric Moore
12976e1cad02SEric Moore schedule_work(&wqw->work);
12986e1cad02SEric Moore }
12996e1cad02SEric Moore
13006e1cad02SEric Moore /*
13016e1cad02SEric Moore * spi module reset handler
13026e1cad02SEric Moore */
13036e1cad02SEric Moore static int
mptspi_ioc_reset(MPT_ADAPTER * ioc,int reset_phase)13046e1cad02SEric Moore mptspi_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
13056e1cad02SEric Moore {
13066e1cad02SEric Moore int rc;
13076e1cad02SEric Moore
13086e1cad02SEric Moore rc = mptscsih_ioc_reset(ioc, reset_phase);
1309ffb7fef3SKashyap, Desai if ((ioc->bus_type != SPI) || (!rc))
1310ffb7fef3SKashyap, Desai return rc;
13116e1cad02SEric Moore
1312081a5bcbSJames Bottomley /* only try to do a renegotiation if we're properly set up
1313081a5bcbSJames Bottomley * if we get an ioc fault on bringup, ioc->sh will be NULL */
1314081a5bcbSJames Bottomley if (reset_phase == MPT_IOC_POST_RESET &&
1315081a5bcbSJames Bottomley ioc->sh) {
1316081a5bcbSJames Bottomley struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
1317081a5bcbSJames Bottomley
13186e1cad02SEric Moore mptspi_dv_renegotiate(hd);
1319081a5bcbSJames Bottomley }
13206e1cad02SEric Moore
13216e1cad02SEric Moore return rc;
13226e1cad02SEric Moore }
13236e1cad02SEric Moore
1324c29ca9d1STom "spot" Callaway #ifdef CONFIG_PM
13256e1cad02SEric Moore /*
13266e1cad02SEric Moore * spi module resume handler
13276e1cad02SEric Moore */
13286e1cad02SEric Moore static int
mptspi_resume(struct pci_dev * pdev)13296e1cad02SEric Moore mptspi_resume(struct pci_dev *pdev)
13306e1cad02SEric Moore {
13316e1cad02SEric Moore MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1332e7eae9f6SEric Moore struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
13336e1cad02SEric Moore int rc;
13346e1cad02SEric Moore
13356e1cad02SEric Moore rc = mptscsih_resume(pdev);
13366e1cad02SEric Moore mptspi_dv_renegotiate(hd);
13376e1cad02SEric Moore
13386e1cad02SEric Moore return rc;
13396e1cad02SEric Moore }
1340c29ca9d1STom "spot" Callaway #endif
13416e1cad02SEric Moore
1342243eabcfSMoore, Eric Dean /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1343243eabcfSMoore, Eric Dean /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1344243eabcfSMoore, Eric Dean /*
1345243eabcfSMoore, Eric Dean * mptspi_probe - Installs scsi devices per bus.
1346243eabcfSMoore, Eric Dean * @pdev: Pointer to pci_dev structure
1347243eabcfSMoore, Eric Dean *
1348243eabcfSMoore, Eric Dean * Returns 0 for success, non-zero for failure.
1349243eabcfSMoore, Eric Dean *
1350243eabcfSMoore, Eric Dean */
1351243eabcfSMoore, Eric Dean static int
mptspi_probe(struct pci_dev * pdev,const struct pci_device_id * id)1352243eabcfSMoore, Eric Dean mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
1353243eabcfSMoore, Eric Dean {
1354243eabcfSMoore, Eric Dean struct Scsi_Host *sh;
1355243eabcfSMoore, Eric Dean MPT_SCSI_HOST *hd;
1356243eabcfSMoore, Eric Dean MPT_ADAPTER *ioc;
1357243eabcfSMoore, Eric Dean unsigned long flags;
13581ca00bb7SChristoph Hellwig int ii;
1359243eabcfSMoore, Eric Dean int numSGE = 0;
1360243eabcfSMoore, Eric Dean int scale;
1361243eabcfSMoore, Eric Dean int ioc_cap;
1362243eabcfSMoore, Eric Dean int error=0;
1363243eabcfSMoore, Eric Dean int r;
1364243eabcfSMoore, Eric Dean
1365243eabcfSMoore, Eric Dean if ((r = mpt_attach(pdev,id)) != 0)
1366243eabcfSMoore, Eric Dean return r;
1367243eabcfSMoore, Eric Dean
1368243eabcfSMoore, Eric Dean ioc = pci_get_drvdata(pdev);
1369d335cc38SMoore, Eric Dean ioc->DoneCtx = mptspiDoneCtx;
1370d335cc38SMoore, Eric Dean ioc->TaskCtx = mptspiTaskCtx;
1371d335cc38SMoore, Eric Dean ioc->InternalCtx = mptspiInternalCtx;
1372243eabcfSMoore, Eric Dean
1373243eabcfSMoore, Eric Dean /* Added sanity check on readiness of the MPT adapter.
1374243eabcfSMoore, Eric Dean */
1375243eabcfSMoore, Eric Dean if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
1376243eabcfSMoore, Eric Dean printk(MYIOC_s_WARN_FMT
1377243eabcfSMoore, Eric Dean "Skipping because it's not operational!\n",
1378243eabcfSMoore, Eric Dean ioc->name);
13797acec1e7SMoore, Eric Dean error = -ENODEV;
13807acec1e7SMoore, Eric Dean goto out_mptspi_probe;
1381243eabcfSMoore, Eric Dean }
1382243eabcfSMoore, Eric Dean
1383243eabcfSMoore, Eric Dean if (!ioc->active) {
1384243eabcfSMoore, Eric Dean printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
1385243eabcfSMoore, Eric Dean ioc->name);
13867acec1e7SMoore, Eric Dean error = -ENODEV;
13877acec1e7SMoore, Eric Dean goto out_mptspi_probe;
1388243eabcfSMoore, Eric Dean }
1389243eabcfSMoore, Eric Dean
1390243eabcfSMoore, Eric Dean /* Sanity check - ensure at least 1 port is INITIATOR capable
1391243eabcfSMoore, Eric Dean */
1392243eabcfSMoore, Eric Dean ioc_cap = 0;
1393243eabcfSMoore, Eric Dean for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
1394243eabcfSMoore, Eric Dean if (ioc->pfacts[ii].ProtocolFlags &
1395243eabcfSMoore, Eric Dean MPI_PORTFACTS_PROTOCOL_INITIATOR)
1396243eabcfSMoore, Eric Dean ioc_cap ++;
1397243eabcfSMoore, Eric Dean }
1398243eabcfSMoore, Eric Dean
1399243eabcfSMoore, Eric Dean if (!ioc_cap) {
1400243eabcfSMoore, Eric Dean printk(MYIOC_s_WARN_FMT
1401243eabcfSMoore, Eric Dean "Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",
1402243eabcfSMoore, Eric Dean ioc->name, ioc);
1403466544d8SMoore, Eric Dean return 0;
1404243eabcfSMoore, Eric Dean }
1405243eabcfSMoore, Eric Dean
1406243eabcfSMoore, Eric Dean sh = scsi_host_alloc(&mptspi_driver_template, sizeof(MPT_SCSI_HOST));
1407243eabcfSMoore, Eric Dean
1408243eabcfSMoore, Eric Dean if (!sh) {
1409243eabcfSMoore, Eric Dean printk(MYIOC_s_WARN_FMT
1410243eabcfSMoore, Eric Dean "Unable to register controller with SCSI subsystem\n",
1411243eabcfSMoore, Eric Dean ioc->name);
14127acec1e7SMoore, Eric Dean error = -1;
14137acec1e7SMoore, Eric Dean goto out_mptspi_probe;
1414243eabcfSMoore, Eric Dean }
1415243eabcfSMoore, Eric Dean
14164089b71cSChris J Arges /* VMWare emulation doesn't properly implement WRITE_SAME
14174089b71cSChris J Arges */
14184089b71cSChris J Arges if (pdev->subsystem_vendor == 0x15AD)
14194089b71cSChris J Arges sh->no_write_same = 1;
14204089b71cSChris J Arges
1421243eabcfSMoore, Eric Dean spin_lock_irqsave(&ioc->FreeQlock, flags);
1422243eabcfSMoore, Eric Dean
1423243eabcfSMoore, Eric Dean /* Attach the SCSI Host to the IOC structure
1424243eabcfSMoore, Eric Dean */
1425243eabcfSMoore, Eric Dean ioc->sh = sh;
1426243eabcfSMoore, Eric Dean
1427243eabcfSMoore, Eric Dean sh->io_port = 0;
1428243eabcfSMoore, Eric Dean sh->n_io_port = 0;
1429243eabcfSMoore, Eric Dean sh->irq = 0;
1430243eabcfSMoore, Eric Dean
1431243eabcfSMoore, Eric Dean /* set 16 byte cdb's */
1432243eabcfSMoore, Eric Dean sh->max_cmd_len = 16;
1433243eabcfSMoore, Eric Dean
1434243eabcfSMoore, Eric Dean /* Yikes! This is important!
1435243eabcfSMoore, Eric Dean * Otherwise, by default, linux
1436243eabcfSMoore, Eric Dean * only scans target IDs 0-7!
1437243eabcfSMoore, Eric Dean * pfactsN->MaxDevices unreliable
1438243eabcfSMoore, Eric Dean * (not supported in early
1439243eabcfSMoore, Eric Dean * versions of the FW).
1440243eabcfSMoore, Eric Dean * max_id = 1 + actual max id,
1441243eabcfSMoore, Eric Dean * max_lun = 1 + actual last lun,
1442243eabcfSMoore, Eric Dean * see hosts.h :o(
1443243eabcfSMoore, Eric Dean */
1444793955f5SEric Moore sh->max_id = ioc->devices_per_bus;
1445243eabcfSMoore, Eric Dean
1446243eabcfSMoore, Eric Dean sh->max_lun = MPT_LAST_LUN + 1;
1447c92f222eSJames Bottomley /*
1448c92f222eSJames Bottomley * If RAID Firmware Detected, setup virtual channel
1449c92f222eSJames Bottomley */
1450b506ade9SEric Moore if (ioc->ir_firmware)
1451c92f222eSJames Bottomley sh->max_channel = 1;
1452c92f222eSJames Bottomley else
1453243eabcfSMoore, Eric Dean sh->max_channel = 0;
1454243eabcfSMoore, Eric Dean sh->this_id = ioc->pfacts[0].PortSCSIID;
1455243eabcfSMoore, Eric Dean
1456243eabcfSMoore, Eric Dean /* Required entry.
1457243eabcfSMoore, Eric Dean */
1458243eabcfSMoore, Eric Dean sh->unique_id = ioc->id;
1459243eabcfSMoore, Eric Dean
1460243eabcfSMoore, Eric Dean /* Verify that we won't exceed the maximum
1461243eabcfSMoore, Eric Dean * number of chain buffers
1462243eabcfSMoore, Eric Dean * We can optimize: ZZ = req_sz/sizeof(SGE)
1463243eabcfSMoore, Eric Dean * For 32bit SGE's:
1464243eabcfSMoore, Eric Dean * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
1465243eabcfSMoore, Eric Dean * + (req_sz - 64)/sizeof(SGE)
1466243eabcfSMoore, Eric Dean * A slightly different algorithm is required for
1467243eabcfSMoore, Eric Dean * 64bit SGEs.
1468243eabcfSMoore, Eric Dean */
146914d0f0b0SKashyap, Desai scale = ioc->req_sz/ioc->SGE_size;
147014d0f0b0SKashyap, Desai if (ioc->sg_addr_size == sizeof(u64)) {
1471243eabcfSMoore, Eric Dean numSGE = (scale - 1) *
1472243eabcfSMoore, Eric Dean (ioc->facts.MaxChainDepth-1) + scale +
147314d0f0b0SKashyap, Desai (ioc->req_sz - 60) / ioc->SGE_size;
1474243eabcfSMoore, Eric Dean } else {
1475243eabcfSMoore, Eric Dean numSGE = 1 + (scale - 1) *
1476243eabcfSMoore, Eric Dean (ioc->facts.MaxChainDepth-1) + scale +
147714d0f0b0SKashyap, Desai (ioc->req_sz - 64) / ioc->SGE_size;
1478243eabcfSMoore, Eric Dean }
1479243eabcfSMoore, Eric Dean
1480243eabcfSMoore, Eric Dean if (numSGE < sh->sg_tablesize) {
1481243eabcfSMoore, Eric Dean /* Reset this value */
148229dd3609SEric Moore dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1483243eabcfSMoore, Eric Dean "Resetting sg_tablesize to %d from %d\n",
1484243eabcfSMoore, Eric Dean ioc->name, numSGE, sh->sg_tablesize));
1485243eabcfSMoore, Eric Dean sh->sg_tablesize = numSGE;
1486243eabcfSMoore, Eric Dean }
1487243eabcfSMoore, Eric Dean
1488243eabcfSMoore, Eric Dean spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1489243eabcfSMoore, Eric Dean
1490e7eae9f6SEric Moore hd = shost_priv(sh);
1491243eabcfSMoore, Eric Dean hd->ioc = ioc;
1492243eabcfSMoore, Eric Dean
1493243eabcfSMoore, Eric Dean /* SCSI needs scsi_cmnd lookup table!
1494243eabcfSMoore, Eric Dean * (with size equal to req_depth*PtrSz!)
1495243eabcfSMoore, Eric Dean */
1496f69b0791SJulia Lawall ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_KERNEL);
1497e8206381SEric Moore if (!ioc->ScsiLookup) {
1498243eabcfSMoore, Eric Dean error = -ENOMEM;
14997acec1e7SMoore, Eric Dean goto out_mptspi_probe;
1500243eabcfSMoore, Eric Dean }
1501e8206381SEric Moore spin_lock_init(&ioc->scsi_lookup_lock);
1502243eabcfSMoore, Eric Dean
1503d6ecdd63SPrakash, Sathya dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
1504e8206381SEric Moore ioc->name, ioc->ScsiLookup));
1505243eabcfSMoore, Eric Dean
1506243eabcfSMoore, Eric Dean ioc->spi_data.Saf_Te = mpt_saf_te;
1507d6ecdd63SPrakash, Sathya ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1508ba856d32SEric Moore "saf_te %x\n",
1509243eabcfSMoore, Eric Dean ioc->name,
1510ba856d32SEric Moore mpt_saf_te));
1511243eabcfSMoore, Eric Dean ioc->spi_data.noQas = 0;
1512243eabcfSMoore, Eric Dean
1513243eabcfSMoore, Eric Dean hd->last_queue_full = 0;
151472978245SEric Moore hd->spi_pending = 0;
1515243eabcfSMoore, Eric Dean
1516c92f222eSJames Bottomley /* Some versions of the firmware don't support page 0; without
1517c92f222eSJames Bottomley * that we can't get the parameters */
1518e80b002bSEric Moore if (ioc->spi_data.sdp0length != 0)
1519c92f222eSJames Bottomley sh->transportt = mptspi_transport_template;
1520c92f222eSJames Bottomley
1521243eabcfSMoore, Eric Dean error = scsi_add_host (sh, &ioc->pcidev->dev);
1522243eabcfSMoore, Eric Dean if(error) {
152329dd3609SEric Moore dprintk(ioc, printk(MYIOC_s_ERR_FMT
152429dd3609SEric Moore "scsi_add_host failed\n", ioc->name));
15257acec1e7SMoore, Eric Dean goto out_mptspi_probe;
1526243eabcfSMoore, Eric Dean }
1527243eabcfSMoore, Eric Dean
1528d8e925dcSMoore, Eric /*
1529d8e925dcSMoore, Eric * issue internal bus reset
1530d8e925dcSMoore, Eric */
1531d8e925dcSMoore, Eric if (ioc->spi_data.bus_reset)
15321ba9ab2eSKashyap, Desai mptscsih_IssueTaskMgmt(hd,
1533d8e925dcSMoore, Eric MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
1534d8e925dcSMoore, Eric 0, 0, 0, 0, 5);
1535d8e925dcSMoore, Eric
1536243eabcfSMoore, Eric Dean scsi_scan_host(sh);
1537243eabcfSMoore, Eric Dean return 0;
1538243eabcfSMoore, Eric Dean
15397acec1e7SMoore, Eric Dean out_mptspi_probe:
1540243eabcfSMoore, Eric Dean
1541243eabcfSMoore, Eric Dean mptscsih_remove(pdev);
1542243eabcfSMoore, Eric Dean return error;
1543243eabcfSMoore, Eric Dean }
1544243eabcfSMoore, Eric Dean
mptspi_remove(struct pci_dev * pdev)1545cfd2aff7SHannes Reinecke static void mptspi_remove(struct pci_dev *pdev)
1546cfd2aff7SHannes Reinecke {
1547cfd2aff7SHannes Reinecke MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1548cfd2aff7SHannes Reinecke
1549cfd2aff7SHannes Reinecke scsi_remove_host(ioc->sh);
1550cfd2aff7SHannes Reinecke mptscsih_remove(pdev);
1551cfd2aff7SHannes Reinecke }
1552cfd2aff7SHannes Reinecke
1553243eabcfSMoore, Eric Dean static struct pci_driver mptspi_driver = {
1554243eabcfSMoore, Eric Dean .name = "mptspi",
1555243eabcfSMoore, Eric Dean .id_table = mptspi_pci_table,
1556243eabcfSMoore, Eric Dean .probe = mptspi_probe,
1557cfd2aff7SHannes Reinecke .remove = mptspi_remove,
1558243eabcfSMoore, Eric Dean .shutdown = mptscsih_shutdown,
1559243eabcfSMoore, Eric Dean #ifdef CONFIG_PM
1560243eabcfSMoore, Eric Dean .suspend = mptscsih_suspend,
15616e1cad02SEric Moore .resume = mptspi_resume,
1562243eabcfSMoore, Eric Dean #endif
1563243eabcfSMoore, Eric Dean };
1564243eabcfSMoore, Eric Dean
1565243eabcfSMoore, Eric Dean /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1566243eabcfSMoore, Eric Dean /**
1567d9489fb6SRandy Dunlap * mptspi_init - Register MPT adapter(s) as SCSI host(s) with SCSI mid-layer.
1568243eabcfSMoore, Eric Dean *
1569243eabcfSMoore, Eric Dean * Returns 0 for success, non-zero for failure.
1570243eabcfSMoore, Eric Dean */
1571243eabcfSMoore, Eric Dean static int __init
mptspi_init(void)1572243eabcfSMoore, Eric Dean mptspi_init(void)
1573243eabcfSMoore, Eric Dean {
157457ce21bfSPrakash, Sathya int error;
157557ce21bfSPrakash, Sathya
1576243eabcfSMoore, Eric Dean show_mptmod_ver(my_NAME, my_VERSION);
1577243eabcfSMoore, Eric Dean
1578c92f222eSJames Bottomley mptspi_transport_template = spi_attach_transport(&mptspi_transport_functions);
1579c92f222eSJames Bottomley if (!mptspi_transport_template)
1580c92f222eSJames Bottomley return -ENODEV;
1581c92f222eSJames Bottomley
1582213aaca3SKashyap, Desai mptspiDoneCtx = mpt_register(mptscsih_io_done, MPTSPI_DRIVER,
1583213aaca3SKashyap, Desai "mptscsih_io_done");
1584213aaca3SKashyap, Desai mptspiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSPI_DRIVER,
1585213aaca3SKashyap, Desai "mptscsih_taskmgmt_complete");
1586213aaca3SKashyap, Desai mptspiInternalCtx = mpt_register(mptscsih_scandv_complete,
1587213aaca3SKashyap, Desai MPTSPI_DRIVER, "mptscsih_scandv_complete");
1588243eabcfSMoore, Eric Dean
1589d6ecdd63SPrakash, Sathya mpt_event_register(mptspiDoneCtx, mptspi_event_process);
1590d6ecdd63SPrakash, Sathya mpt_reset_register(mptspiDoneCtx, mptspi_ioc_reset);
1591243eabcfSMoore, Eric Dean
159257ce21bfSPrakash, Sathya error = pci_register_driver(&mptspi_driver);
159357ce21bfSPrakash, Sathya if (error)
159457ce21bfSPrakash, Sathya spi_release_transport(mptspi_transport_template);
159557ce21bfSPrakash, Sathya
159657ce21bfSPrakash, Sathya return error;
1597243eabcfSMoore, Eric Dean }
1598243eabcfSMoore, Eric Dean
1599243eabcfSMoore, Eric Dean /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1600243eabcfSMoore, Eric Dean /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1601243eabcfSMoore, Eric Dean /**
1602243eabcfSMoore, Eric Dean * mptspi_exit - Unregisters MPT adapter(s)
1603243eabcfSMoore, Eric Dean */
1604243eabcfSMoore, Eric Dean static void __exit
mptspi_exit(void)1605243eabcfSMoore, Eric Dean mptspi_exit(void)
1606243eabcfSMoore, Eric Dean {
1607243eabcfSMoore, Eric Dean pci_unregister_driver(&mptspi_driver);
1608243eabcfSMoore, Eric Dean
1609243eabcfSMoore, Eric Dean mpt_reset_deregister(mptspiDoneCtx);
1610243eabcfSMoore, Eric Dean mpt_event_deregister(mptspiDoneCtx);
1611243eabcfSMoore, Eric Dean
1612243eabcfSMoore, Eric Dean mpt_deregister(mptspiInternalCtx);
1613243eabcfSMoore, Eric Dean mpt_deregister(mptspiTaskCtx);
1614243eabcfSMoore, Eric Dean mpt_deregister(mptspiDoneCtx);
1615c92f222eSJames Bottomley spi_release_transport(mptspi_transport_template);
1616243eabcfSMoore, Eric Dean }
1617243eabcfSMoore, Eric Dean
1618243eabcfSMoore, Eric Dean module_init(mptspi_init);
1619243eabcfSMoore, Eric Dean module_exit(mptspi_exit);
1620