1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * linux/drivers/message/fusion/mptspi.c
3*4882a593Smuzhiyun * For use with LSI PCI chip/adapter(s)
4*4882a593Smuzhiyun * running LSI Fusion MPT (Message Passing Technology) firmware.
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Copyright (c) 1999-2008 LSI Corporation
7*4882a593Smuzhiyun * (mailto:DL-MPTFusionLinux@lsi.com)
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun */
10*4882a593Smuzhiyun /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11*4882a593Smuzhiyun /*
12*4882a593Smuzhiyun This program is free software; you can redistribute it and/or modify
13*4882a593Smuzhiyun it under the terms of the GNU General Public License as published by
14*4882a593Smuzhiyun the Free Software Foundation; version 2 of the License.
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun This program is distributed in the hope that it will be useful,
17*4882a593Smuzhiyun but WITHOUT ANY WARRANTY; without even the implied warranty of
18*4882a593Smuzhiyun MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19*4882a593Smuzhiyun GNU General Public License for more details.
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun NO WARRANTY
22*4882a593Smuzhiyun THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
23*4882a593Smuzhiyun CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
24*4882a593Smuzhiyun LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
25*4882a593Smuzhiyun MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
26*4882a593Smuzhiyun solely responsible for determining the appropriateness of using and
27*4882a593Smuzhiyun distributing the Program and assumes all risks associated with its
28*4882a593Smuzhiyun exercise of rights under this Agreement, including but not limited to
29*4882a593Smuzhiyun the risks and costs of program errors, damage to or loss of data,
30*4882a593Smuzhiyun programs or equipment, and unavailability or interruption of operations.
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun DISCLAIMER OF LIABILITY
33*4882a593Smuzhiyun NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
34*4882a593Smuzhiyun DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35*4882a593Smuzhiyun DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
36*4882a593Smuzhiyun ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
37*4882a593Smuzhiyun TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
38*4882a593Smuzhiyun USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
39*4882a593Smuzhiyun HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun You should have received a copy of the GNU General Public License
42*4882a593Smuzhiyun along with this program; if not, write to the Free Software
43*4882a593Smuzhiyun Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
44*4882a593Smuzhiyun */
45*4882a593Smuzhiyun /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun #include <linux/module.h>
48*4882a593Smuzhiyun #include <linux/kernel.h>
49*4882a593Smuzhiyun #include <linux/slab.h>
50*4882a593Smuzhiyun #include <linux/init.h>
51*4882a593Smuzhiyun #include <linux/errno.h>
52*4882a593Smuzhiyun #include <linux/kdev_t.h>
53*4882a593Smuzhiyun #include <linux/blkdev.h>
54*4882a593Smuzhiyun #include <linux/delay.h> /* for mdelay */
55*4882a593Smuzhiyun #include <linux/interrupt.h> /* needed for in_interrupt() proto */
56*4882a593Smuzhiyun #include <linux/reboot.h> /* notifier code */
57*4882a593Smuzhiyun #include <linux/workqueue.h>
58*4882a593Smuzhiyun #include <linux/raid_class.h>
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun #include <scsi/scsi.h>
61*4882a593Smuzhiyun #include <scsi/scsi_cmnd.h>
62*4882a593Smuzhiyun #include <scsi/scsi_device.h>
63*4882a593Smuzhiyun #include <scsi/scsi_host.h>
64*4882a593Smuzhiyun #include <scsi/scsi_tcq.h>
65*4882a593Smuzhiyun #include <scsi/scsi_transport.h>
66*4882a593Smuzhiyun #include <scsi/scsi_transport_spi.h>
67*4882a593Smuzhiyun #include <scsi/scsi_dbg.h>
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun #include "mptbase.h"
70*4882a593Smuzhiyun #include "mptscsih.h"
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
73*4882a593Smuzhiyun #define my_NAME "Fusion MPT SPI Host driver"
74*4882a593Smuzhiyun #define my_VERSION MPT_LINUX_VERSION_COMMON
75*4882a593Smuzhiyun #define MYNAM "mptspi"
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun MODULE_AUTHOR(MODULEAUTHOR);
78*4882a593Smuzhiyun MODULE_DESCRIPTION(my_NAME);
79*4882a593Smuzhiyun MODULE_LICENSE("GPL");
80*4882a593Smuzhiyun MODULE_VERSION(my_VERSION);
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun /* Command line args */
83*4882a593Smuzhiyun static int mpt_saf_te = MPTSCSIH_SAF_TE;
84*4882a593Smuzhiyun module_param(mpt_saf_te, int, 0);
85*4882a593Smuzhiyun MODULE_PARM_DESC(mpt_saf_te, " Force enabling SEP Processor: enable=1 (default=MPTSCSIH_SAF_TE=0)");
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun static void mptspi_write_offset(struct scsi_target *, int);
88*4882a593Smuzhiyun static void mptspi_write_width(struct scsi_target *, int);
89*4882a593Smuzhiyun static int mptspi_write_spi_device_pg1(struct scsi_target *,
90*4882a593Smuzhiyun struct _CONFIG_PAGE_SCSI_DEVICE_1 *);
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun static struct scsi_transport_template *mptspi_transport_template = NULL;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun static u8 mptspiDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
95*4882a593Smuzhiyun static u8 mptspiTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
96*4882a593Smuzhiyun static u8 mptspiInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun /**
99*4882a593Smuzhiyun * mptspi_setTargetNegoParms - Update the target negotiation parameters
100*4882a593Smuzhiyun * @hd: Pointer to a SCSI Host Structure
101*4882a593Smuzhiyun * @target: per target private data
102*4882a593Smuzhiyun * @sdev: SCSI device
103*4882a593Smuzhiyun *
104*4882a593Smuzhiyun * Update the target negotiation parameters based on the the Inquiry
105*4882a593Smuzhiyun * data, adapter capabilities, and NVRAM settings.
106*4882a593Smuzhiyun **/
107*4882a593Smuzhiyun static void
mptspi_setTargetNegoParms(MPT_SCSI_HOST * hd,VirtTarget * target,struct scsi_device * sdev)108*4882a593Smuzhiyun mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
109*4882a593Smuzhiyun struct scsi_device *sdev)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun MPT_ADAPTER *ioc = hd->ioc;
112*4882a593Smuzhiyun SpiCfgData *pspi_data = &ioc->spi_data;
113*4882a593Smuzhiyun int id = (int) target->id;
114*4882a593Smuzhiyun int nvram;
115*4882a593Smuzhiyun u8 width = MPT_NARROW;
116*4882a593Smuzhiyun u8 factor = MPT_ASYNC;
117*4882a593Smuzhiyun u8 offset = 0;
118*4882a593Smuzhiyun u8 nfactor;
119*4882a593Smuzhiyun u8 noQas = 1;
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun target->negoFlags = pspi_data->noQas;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun if (sdev->scsi_level < SCSI_2) {
124*4882a593Smuzhiyun width = 0;
125*4882a593Smuzhiyun factor = MPT_ULTRA2;
126*4882a593Smuzhiyun offset = pspi_data->maxSyncOffset;
127*4882a593Smuzhiyun target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
128*4882a593Smuzhiyun } else {
129*4882a593Smuzhiyun if (scsi_device_wide(sdev))
130*4882a593Smuzhiyun width = 1;
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun if (scsi_device_sync(sdev)) {
133*4882a593Smuzhiyun factor = pspi_data->minSyncFactor;
134*4882a593Smuzhiyun if (!scsi_device_dt(sdev))
135*4882a593Smuzhiyun factor = MPT_ULTRA2;
136*4882a593Smuzhiyun else {
137*4882a593Smuzhiyun if (!scsi_device_ius(sdev) &&
138*4882a593Smuzhiyun !scsi_device_qas(sdev))
139*4882a593Smuzhiyun factor = MPT_ULTRA160;
140*4882a593Smuzhiyun else {
141*4882a593Smuzhiyun factor = MPT_ULTRA320;
142*4882a593Smuzhiyun if (scsi_device_qas(sdev)) {
143*4882a593Smuzhiyun ddvprintk(ioc,
144*4882a593Smuzhiyun printk(MYIOC_s_DEBUG_FMT "Enabling QAS due to "
145*4882a593Smuzhiyun "byte56=%02x on id=%d!\n", ioc->name,
146*4882a593Smuzhiyun scsi_device_qas(sdev), id));
147*4882a593Smuzhiyun noQas = 0;
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun if (sdev->type == TYPE_TAPE &&
150*4882a593Smuzhiyun scsi_device_ius(sdev))
151*4882a593Smuzhiyun target->negoFlags |= MPT_TAPE_NEGO_IDP;
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun offset = pspi_data->maxSyncOffset;
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun /* If RAID, never disable QAS
157*4882a593Smuzhiyun * else if non RAID, do not disable
158*4882a593Smuzhiyun * QAS if bit 1 is set
159*4882a593Smuzhiyun * bit 1 QAS support, non-raid only
160*4882a593Smuzhiyun * bit 0 IU support
161*4882a593Smuzhiyun */
162*4882a593Smuzhiyun if (target->raidVolume == 1)
163*4882a593Smuzhiyun noQas = 0;
164*4882a593Smuzhiyun } else {
165*4882a593Smuzhiyun factor = MPT_ASYNC;
166*4882a593Smuzhiyun offset = 0;
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun if (!sdev->tagged_supported)
171*4882a593Smuzhiyun target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun /* Update tflags based on NVRAM settings. (SCSI only)
174*4882a593Smuzhiyun */
175*4882a593Smuzhiyun if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
176*4882a593Smuzhiyun nvram = pspi_data->nvram[id];
177*4882a593Smuzhiyun nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun if (width)
180*4882a593Smuzhiyun width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun if (offset > 0) {
183*4882a593Smuzhiyun /* Ensure factor is set to the
184*4882a593Smuzhiyun * maximum of: adapter, nvram, inquiry
185*4882a593Smuzhiyun */
186*4882a593Smuzhiyun if (nfactor) {
187*4882a593Smuzhiyun if (nfactor < pspi_data->minSyncFactor )
188*4882a593Smuzhiyun nfactor = pspi_data->minSyncFactor;
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun factor = max(factor, nfactor);
191*4882a593Smuzhiyun if (factor == MPT_ASYNC)
192*4882a593Smuzhiyun offset = 0;
193*4882a593Smuzhiyun } else {
194*4882a593Smuzhiyun offset = 0;
195*4882a593Smuzhiyun factor = MPT_ASYNC;
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun } else {
198*4882a593Smuzhiyun factor = MPT_ASYNC;
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun /* Make sure data is consistent
203*4882a593Smuzhiyun */
204*4882a593Smuzhiyun if ((!width) && (factor < MPT_ULTRA2))
205*4882a593Smuzhiyun factor = MPT_ULTRA2;
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun /* Save the data to the target structure.
208*4882a593Smuzhiyun */
209*4882a593Smuzhiyun target->minSyncFactor = factor;
210*4882a593Smuzhiyun target->maxOffset = offset;
211*4882a593Smuzhiyun target->maxWidth = width;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun spi_min_period(scsi_target(sdev)) = factor;
214*4882a593Smuzhiyun spi_max_offset(scsi_target(sdev)) = offset;
215*4882a593Smuzhiyun spi_max_width(scsi_target(sdev)) = width;
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun /* Disable unused features.
220*4882a593Smuzhiyun */
221*4882a593Smuzhiyun if (!width)
222*4882a593Smuzhiyun target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun if (!offset)
225*4882a593Smuzhiyun target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun if ( factor > MPT_ULTRA320 )
228*4882a593Smuzhiyun noQas = 0;
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun if (noQas && (pspi_data->noQas == 0)) {
231*4882a593Smuzhiyun pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS;
232*4882a593Smuzhiyun target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun /* Disable QAS in a mixed configuration case
235*4882a593Smuzhiyun */
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
238*4882a593Smuzhiyun "Disabling QAS due to noQas=%02x on id=%d!\n", ioc->name, noQas, id));
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun /**
243*4882a593Smuzhiyun * mptspi_writeIOCPage4 - write IOC Page 4
244*4882a593Smuzhiyun * @hd: Pointer to a SCSI Host Structure
245*4882a593Smuzhiyun * @channel: channel number
246*4882a593Smuzhiyun * @id: write IOC Page4 for this ID & Bus
247*4882a593Smuzhiyun *
248*4882a593Smuzhiyun * Return: -EAGAIN if unable to obtain a Message Frame
249*4882a593Smuzhiyun * or 0 if success.
250*4882a593Smuzhiyun *
251*4882a593Smuzhiyun * Remark: We do not wait for a return, write pages sequentially.
252*4882a593Smuzhiyun **/
253*4882a593Smuzhiyun static int
mptspi_writeIOCPage4(MPT_SCSI_HOST * hd,u8 channel,u8 id)254*4882a593Smuzhiyun mptspi_writeIOCPage4(MPT_SCSI_HOST *hd, u8 channel , u8 id)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun MPT_ADAPTER *ioc = hd->ioc;
257*4882a593Smuzhiyun Config_t *pReq;
258*4882a593Smuzhiyun IOCPage4_t *IOCPage4Ptr;
259*4882a593Smuzhiyun MPT_FRAME_HDR *mf;
260*4882a593Smuzhiyun dma_addr_t dataDma;
261*4882a593Smuzhiyun u32 flagsLength;
262*4882a593Smuzhiyun int ii;
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun /* Get a MF for this command.
265*4882a593Smuzhiyun */
266*4882a593Smuzhiyun if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
267*4882a593Smuzhiyun dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
268*4882a593Smuzhiyun "writeIOCPage4 : no msg frames!\n",ioc->name));
269*4882a593Smuzhiyun return -EAGAIN;
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun /* Set the request and the data pointers.
273*4882a593Smuzhiyun * Place data at end of MF.
274*4882a593Smuzhiyun */
275*4882a593Smuzhiyun pReq = (Config_t *)mf;
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun /* Complete the request frame (same for all requests).
278*4882a593Smuzhiyun */
279*4882a593Smuzhiyun pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
280*4882a593Smuzhiyun pReq->Reserved = 0;
281*4882a593Smuzhiyun pReq->ChainOffset = 0;
282*4882a593Smuzhiyun pReq->Function = MPI_FUNCTION_CONFIG;
283*4882a593Smuzhiyun pReq->ExtPageLength = 0;
284*4882a593Smuzhiyun pReq->ExtPageType = 0;
285*4882a593Smuzhiyun pReq->MsgFlags = 0;
286*4882a593Smuzhiyun for (ii=0; ii < 8; ii++) {
287*4882a593Smuzhiyun pReq->Reserved2[ii] = 0;
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun IOCPage4Ptr = ioc->spi_data.pIocPg4;
291*4882a593Smuzhiyun dataDma = ioc->spi_data.IocPg4_dma;
292*4882a593Smuzhiyun ii = IOCPage4Ptr->ActiveSEP++;
293*4882a593Smuzhiyun IOCPage4Ptr->SEP[ii].SEPTargetID = id;
294*4882a593Smuzhiyun IOCPage4Ptr->SEP[ii].SEPBus = channel;
295*4882a593Smuzhiyun pReq->Header = IOCPage4Ptr->Header;
296*4882a593Smuzhiyun pReq->PageAddress = cpu_to_le32(id | (channel << 8 ));
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun /* Add a SGE to the config request.
299*4882a593Smuzhiyun */
300*4882a593Smuzhiyun flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
301*4882a593Smuzhiyun (IOCPage4Ptr->Header.PageLength + ii) * 4;
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
306*4882a593Smuzhiyun "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
307*4882a593Smuzhiyun ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel));
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun return 0;
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun /**
315*4882a593Smuzhiyun * mptspi_initTarget - Target, LUN alloc/free functionality.
316*4882a593Smuzhiyun * @hd: Pointer to MPT_SCSI_HOST structure
317*4882a593Smuzhiyun * @vtarget: per target private data
318*4882a593Smuzhiyun * @sdev: SCSI device
319*4882a593Smuzhiyun *
320*4882a593Smuzhiyun * NOTE: It's only SAFE to call this routine if data points to
321*4882a593Smuzhiyun * sane & valid STANDARD INQUIRY data!
322*4882a593Smuzhiyun *
323*4882a593Smuzhiyun * Allocate and initialize memory for this target.
324*4882a593Smuzhiyun * Save inquiry data.
325*4882a593Smuzhiyun *
326*4882a593Smuzhiyun **/
327*4882a593Smuzhiyun static void
mptspi_initTarget(MPT_SCSI_HOST * hd,VirtTarget * vtarget,struct scsi_device * sdev)328*4882a593Smuzhiyun mptspi_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget,
329*4882a593Smuzhiyun struct scsi_device *sdev)
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun /* Is LUN supported? If so, upper 2 bits will be 0
333*4882a593Smuzhiyun * in first byte of inquiry data.
334*4882a593Smuzhiyun */
335*4882a593Smuzhiyun if (sdev->inq_periph_qual != 0)
336*4882a593Smuzhiyun return;
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun if (vtarget == NULL)
339*4882a593Smuzhiyun return;
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun vtarget->type = sdev->type;
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun if ((sdev->type == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) {
344*4882a593Smuzhiyun /* Treat all Processors as SAF-TE if
345*4882a593Smuzhiyun * command line option is set */
346*4882a593Smuzhiyun vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
347*4882a593Smuzhiyun mptspi_writeIOCPage4(hd, vtarget->channel, vtarget->id);
348*4882a593Smuzhiyun }else if ((sdev->type == TYPE_PROCESSOR) &&
349*4882a593Smuzhiyun !(vtarget->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) {
350*4882a593Smuzhiyun if (sdev->inquiry_len > 49 ) {
351*4882a593Smuzhiyun if (sdev->inquiry[44] == 'S' &&
352*4882a593Smuzhiyun sdev->inquiry[45] == 'A' &&
353*4882a593Smuzhiyun sdev->inquiry[46] == 'F' &&
354*4882a593Smuzhiyun sdev->inquiry[47] == '-' &&
355*4882a593Smuzhiyun sdev->inquiry[48] == 'T' &&
356*4882a593Smuzhiyun sdev->inquiry[49] == 'E' ) {
357*4882a593Smuzhiyun vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
358*4882a593Smuzhiyun mptspi_writeIOCPage4(hd, vtarget->channel, vtarget->id);
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun mptspi_setTargetNegoParms(hd, vtarget, sdev);
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun /**
366*4882a593Smuzhiyun * mptspi_is_raid - Determines whether target is belonging to volume
367*4882a593Smuzhiyun * @hd: Pointer to a SCSI HOST structure
368*4882a593Smuzhiyun * @id: target device id
369*4882a593Smuzhiyun *
370*4882a593Smuzhiyun * Return:
371*4882a593Smuzhiyun * non-zero = true
372*4882a593Smuzhiyun * zero = false
373*4882a593Smuzhiyun *
374*4882a593Smuzhiyun */
375*4882a593Smuzhiyun static int
mptspi_is_raid(struct _MPT_SCSI_HOST * hd,u32 id)376*4882a593Smuzhiyun mptspi_is_raid(struct _MPT_SCSI_HOST *hd, u32 id)
377*4882a593Smuzhiyun {
378*4882a593Smuzhiyun int i, rc = 0;
379*4882a593Smuzhiyun MPT_ADAPTER *ioc = hd->ioc;
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun if (!ioc->raid_data.pIocPg2)
382*4882a593Smuzhiyun goto out;
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
385*4882a593Smuzhiyun goto out;
386*4882a593Smuzhiyun for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
387*4882a593Smuzhiyun if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) {
388*4882a593Smuzhiyun rc = 1;
389*4882a593Smuzhiyun goto out;
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun }
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun out:
394*4882a593Smuzhiyun return rc;
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun
mptspi_target_alloc(struct scsi_target * starget)397*4882a593Smuzhiyun static int mptspi_target_alloc(struct scsi_target *starget)
398*4882a593Smuzhiyun {
399*4882a593Smuzhiyun struct Scsi_Host *shost = dev_to_shost(&starget->dev);
400*4882a593Smuzhiyun struct _MPT_SCSI_HOST *hd = shost_priv(shost);
401*4882a593Smuzhiyun VirtTarget *vtarget;
402*4882a593Smuzhiyun MPT_ADAPTER *ioc;
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun if (hd == NULL)
405*4882a593Smuzhiyun return -ENODEV;
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun ioc = hd->ioc;
408*4882a593Smuzhiyun vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
409*4882a593Smuzhiyun if (!vtarget)
410*4882a593Smuzhiyun return -ENOMEM;
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun vtarget->ioc_id = ioc->id;
413*4882a593Smuzhiyun vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
414*4882a593Smuzhiyun vtarget->id = (u8)starget->id;
415*4882a593Smuzhiyun vtarget->channel = (u8)starget->channel;
416*4882a593Smuzhiyun vtarget->starget = starget;
417*4882a593Smuzhiyun starget->hostdata = vtarget;
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun if (starget->channel == 1) {
420*4882a593Smuzhiyun if (mptscsih_is_phys_disk(ioc, 0, starget->id) == 0)
421*4882a593Smuzhiyun return 0;
422*4882a593Smuzhiyun vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
423*4882a593Smuzhiyun /* The real channel for this device is zero */
424*4882a593Smuzhiyun vtarget->channel = 0;
425*4882a593Smuzhiyun /* The actual physdisknum (for RAID passthrough) */
426*4882a593Smuzhiyun vtarget->id = mptscsih_raid_id_to_num(ioc, 0,
427*4882a593Smuzhiyun starget->id);
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun if (starget->channel == 0 &&
431*4882a593Smuzhiyun mptspi_is_raid(hd, starget->id)) {
432*4882a593Smuzhiyun vtarget->raidVolume = 1;
433*4882a593Smuzhiyun ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
434*4882a593Smuzhiyun "RAID Volume @ channel=%d id=%d\n", ioc->name, starget->channel,
435*4882a593Smuzhiyun starget->id));
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun if (ioc->spi_data.nvram &&
439*4882a593Smuzhiyun ioc->spi_data.nvram[starget->id] != MPT_HOST_NVRAM_INVALID) {
440*4882a593Smuzhiyun u32 nvram = ioc->spi_data.nvram[starget->id];
441*4882a593Smuzhiyun spi_min_period(starget) = (nvram & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
442*4882a593Smuzhiyun spi_max_width(starget) = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
443*4882a593Smuzhiyun } else {
444*4882a593Smuzhiyun spi_min_period(starget) = ioc->spi_data.minSyncFactor;
445*4882a593Smuzhiyun spi_max_width(starget) = ioc->spi_data.maxBusWidth;
446*4882a593Smuzhiyun }
447*4882a593Smuzhiyun spi_max_offset(starget) = ioc->spi_data.maxSyncOffset;
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun spi_offset(starget) = 0;
450*4882a593Smuzhiyun spi_period(starget) = 0xFF;
451*4882a593Smuzhiyun mptspi_write_width(starget, 0);
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun return 0;
454*4882a593Smuzhiyun }
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun static void
mptspi_target_destroy(struct scsi_target * starget)457*4882a593Smuzhiyun mptspi_target_destroy(struct scsi_target *starget)
458*4882a593Smuzhiyun {
459*4882a593Smuzhiyun kfree(starget->hostdata);
460*4882a593Smuzhiyun starget->hostdata = NULL;
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun /**
464*4882a593Smuzhiyun * mptspi_print_write_nego - negotiation parameters debug info that is being sent
465*4882a593Smuzhiyun * @hd: Pointer to a SCSI HOST structure
466*4882a593Smuzhiyun * @starget: SCSI target
467*4882a593Smuzhiyun * @ii: negotiation parameters
468*4882a593Smuzhiyun *
469*4882a593Smuzhiyun */
470*4882a593Smuzhiyun static void
mptspi_print_write_nego(struct _MPT_SCSI_HOST * hd,struct scsi_target * starget,u32 ii)471*4882a593Smuzhiyun mptspi_print_write_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u32 ii)
472*4882a593Smuzhiyun {
473*4882a593Smuzhiyun ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d Requested = 0x%08x"
474*4882a593Smuzhiyun " ( %s factor = 0x%02x @ offset = 0x%02x %s%s%s%s%s%s%s%s)\n",
475*4882a593Smuzhiyun hd->ioc->name, starget->id, ii,
476*4882a593Smuzhiyun ii & MPI_SCSIDEVPAGE0_NP_WIDE ? "Wide ": "",
477*4882a593Smuzhiyun ((ii >> 8) & 0xFF), ((ii >> 16) & 0xFF),
478*4882a593Smuzhiyun ii & MPI_SCSIDEVPAGE0_NP_IU ? "IU ": "",
479*4882a593Smuzhiyun ii & MPI_SCSIDEVPAGE0_NP_DT ? "DT ": "",
480*4882a593Smuzhiyun ii & MPI_SCSIDEVPAGE0_NP_QAS ? "QAS ": "",
481*4882a593Smuzhiyun ii & MPI_SCSIDEVPAGE0_NP_HOLD_MCS ? "HOLDMCS ": "",
482*4882a593Smuzhiyun ii & MPI_SCSIDEVPAGE0_NP_WR_FLOW ? "WRFLOW ": "",
483*4882a593Smuzhiyun ii & MPI_SCSIDEVPAGE0_NP_RD_STRM ? "RDSTRM ": "",
484*4882a593Smuzhiyun ii & MPI_SCSIDEVPAGE0_NP_RTI ? "RTI ": "",
485*4882a593Smuzhiyun ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": ""));
486*4882a593Smuzhiyun }
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun /**
489*4882a593Smuzhiyun * mptspi_print_read_nego - negotiation parameters debug info that is being read
490*4882a593Smuzhiyun * @hd: Pointer to a SCSI HOST structure
491*4882a593Smuzhiyun * @starget: SCSI target
492*4882a593Smuzhiyun * @ii: negotiation parameters
493*4882a593Smuzhiyun *
494*4882a593Smuzhiyun */
495*4882a593Smuzhiyun static void
mptspi_print_read_nego(struct _MPT_SCSI_HOST * hd,struct scsi_target * starget,u32 ii)496*4882a593Smuzhiyun mptspi_print_read_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u32 ii)
497*4882a593Smuzhiyun {
498*4882a593Smuzhiyun ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d Read = 0x%08x"
499*4882a593Smuzhiyun " ( %s factor = 0x%02x @ offset = 0x%02x %s%s%s%s%s%s%s%s)\n",
500*4882a593Smuzhiyun hd->ioc->name, starget->id, ii,
501*4882a593Smuzhiyun ii & MPI_SCSIDEVPAGE0_NP_WIDE ? "Wide ": "",
502*4882a593Smuzhiyun ((ii >> 8) & 0xFF), ((ii >> 16) & 0xFF),
503*4882a593Smuzhiyun ii & MPI_SCSIDEVPAGE0_NP_IU ? "IU ": "",
504*4882a593Smuzhiyun ii & MPI_SCSIDEVPAGE0_NP_DT ? "DT ": "",
505*4882a593Smuzhiyun ii & MPI_SCSIDEVPAGE0_NP_QAS ? "QAS ": "",
506*4882a593Smuzhiyun ii & MPI_SCSIDEVPAGE0_NP_HOLD_MCS ? "HOLDMCS ": "",
507*4882a593Smuzhiyun ii & MPI_SCSIDEVPAGE0_NP_WR_FLOW ? "WRFLOW ": "",
508*4882a593Smuzhiyun ii & MPI_SCSIDEVPAGE0_NP_RD_STRM ? "RDSTRM ": "",
509*4882a593Smuzhiyun ii & MPI_SCSIDEVPAGE0_NP_RTI ? "RTI ": "",
510*4882a593Smuzhiyun ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": ""));
511*4882a593Smuzhiyun }
512*4882a593Smuzhiyun
mptspi_read_spi_device_pg0(struct scsi_target * starget,struct _CONFIG_PAGE_SCSI_DEVICE_0 * pass_pg0)513*4882a593Smuzhiyun static int mptspi_read_spi_device_pg0(struct scsi_target *starget,
514*4882a593Smuzhiyun struct _CONFIG_PAGE_SCSI_DEVICE_0 *pass_pg0)
515*4882a593Smuzhiyun {
516*4882a593Smuzhiyun struct Scsi_Host *shost = dev_to_shost(&starget->dev);
517*4882a593Smuzhiyun struct _MPT_SCSI_HOST *hd = shost_priv(shost);
518*4882a593Smuzhiyun struct _MPT_ADAPTER *ioc = hd->ioc;
519*4882a593Smuzhiyun struct _CONFIG_PAGE_SCSI_DEVICE_0 *spi_dev_pg0;
520*4882a593Smuzhiyun dma_addr_t spi_dev_pg0_dma;
521*4882a593Smuzhiyun int size;
522*4882a593Smuzhiyun struct _x_config_parms cfg;
523*4882a593Smuzhiyun struct _CONFIG_PAGE_HEADER hdr;
524*4882a593Smuzhiyun int err = -EBUSY;
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun /* No SPI parameters for RAID devices */
527*4882a593Smuzhiyun if (starget->channel == 0 &&
528*4882a593Smuzhiyun mptspi_is_raid(hd, starget->id))
529*4882a593Smuzhiyun return -1;
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun size = ioc->spi_data.sdp0length * 4;
532*4882a593Smuzhiyun /*
533*4882a593Smuzhiyun if (ioc->spi_data.sdp0length & 1)
534*4882a593Smuzhiyun size += size + 4;
535*4882a593Smuzhiyun size += 2048;
536*4882a593Smuzhiyun */
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun spi_dev_pg0 = dma_alloc_coherent(&ioc->pcidev->dev, size, &spi_dev_pg0_dma, GFP_KERNEL);
539*4882a593Smuzhiyun if (spi_dev_pg0 == NULL) {
540*4882a593Smuzhiyun starget_printk(KERN_ERR, starget, MYIOC_s_FMT
541*4882a593Smuzhiyun "dma_alloc_coherent for parameters failed\n", ioc->name);
542*4882a593Smuzhiyun return -EINVAL;
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun memset(&hdr, 0, sizeof(hdr));
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun hdr.PageVersion = ioc->spi_data.sdp0version;
548*4882a593Smuzhiyun hdr.PageLength = ioc->spi_data.sdp0length;
549*4882a593Smuzhiyun hdr.PageNumber = 0;
550*4882a593Smuzhiyun hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun memset(&cfg, 0, sizeof(cfg));
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun cfg.cfghdr.hdr = &hdr;
555*4882a593Smuzhiyun cfg.physAddr = spi_dev_pg0_dma;
556*4882a593Smuzhiyun cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
557*4882a593Smuzhiyun cfg.dir = 0;
558*4882a593Smuzhiyun cfg.pageAddr = starget->id;
559*4882a593Smuzhiyun cfg.timeout = 60;
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun if (mpt_config(ioc, &cfg)) {
562*4882a593Smuzhiyun starget_printk(KERN_ERR, starget, MYIOC_s_FMT "mpt_config failed\n", ioc->name);
563*4882a593Smuzhiyun goto out_free;
564*4882a593Smuzhiyun }
565*4882a593Smuzhiyun err = 0;
566*4882a593Smuzhiyun memcpy(pass_pg0, spi_dev_pg0, size);
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun mptspi_print_read_nego(hd, starget, le32_to_cpu(spi_dev_pg0->NegotiatedParameters));
569*4882a593Smuzhiyun
570*4882a593Smuzhiyun out_free:
571*4882a593Smuzhiyun dma_free_coherent(&ioc->pcidev->dev, size, spi_dev_pg0, spi_dev_pg0_dma);
572*4882a593Smuzhiyun return err;
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun
mptspi_getRP(struct scsi_target * starget)575*4882a593Smuzhiyun static u32 mptspi_getRP(struct scsi_target *starget)
576*4882a593Smuzhiyun {
577*4882a593Smuzhiyun u32 nego = 0;
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun nego |= spi_iu(starget) ? MPI_SCSIDEVPAGE1_RP_IU : 0;
580*4882a593Smuzhiyun nego |= spi_dt(starget) ? MPI_SCSIDEVPAGE1_RP_DT : 0;
581*4882a593Smuzhiyun nego |= spi_qas(starget) ? MPI_SCSIDEVPAGE1_RP_QAS : 0;
582*4882a593Smuzhiyun nego |= spi_hold_mcs(starget) ? MPI_SCSIDEVPAGE1_RP_HOLD_MCS : 0;
583*4882a593Smuzhiyun nego |= spi_wr_flow(starget) ? MPI_SCSIDEVPAGE1_RP_WR_FLOW : 0;
584*4882a593Smuzhiyun nego |= spi_rd_strm(starget) ? MPI_SCSIDEVPAGE1_RP_RD_STRM : 0;
585*4882a593Smuzhiyun nego |= spi_rti(starget) ? MPI_SCSIDEVPAGE1_RP_RTI : 0;
586*4882a593Smuzhiyun nego |= spi_pcomp_en(starget) ? MPI_SCSIDEVPAGE1_RP_PCOMP_EN : 0;
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun nego |= (spi_period(starget) << MPI_SCSIDEVPAGE1_RP_SHIFT_MIN_SYNC_PERIOD) & MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK;
589*4882a593Smuzhiyun nego |= (spi_offset(starget) << MPI_SCSIDEVPAGE1_RP_SHIFT_MAX_SYNC_OFFSET) & MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK;
590*4882a593Smuzhiyun nego |= spi_width(starget) ? MPI_SCSIDEVPAGE1_RP_WIDE : 0;
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun return nego;
593*4882a593Smuzhiyun }
594*4882a593Smuzhiyun
mptspi_read_parameters(struct scsi_target * starget)595*4882a593Smuzhiyun static void mptspi_read_parameters(struct scsi_target *starget)
596*4882a593Smuzhiyun {
597*4882a593Smuzhiyun int nego;
598*4882a593Smuzhiyun struct _CONFIG_PAGE_SCSI_DEVICE_0 spi_dev_pg0;
599*4882a593Smuzhiyun
600*4882a593Smuzhiyun mptspi_read_spi_device_pg0(starget, &spi_dev_pg0);
601*4882a593Smuzhiyun
602*4882a593Smuzhiyun nego = le32_to_cpu(spi_dev_pg0.NegotiatedParameters);
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun spi_iu(starget) = (nego & MPI_SCSIDEVPAGE0_NP_IU) ? 1 : 0;
605*4882a593Smuzhiyun spi_dt(starget) = (nego & MPI_SCSIDEVPAGE0_NP_DT) ? 1 : 0;
606*4882a593Smuzhiyun spi_qas(starget) = (nego & MPI_SCSIDEVPAGE0_NP_QAS) ? 1 : 0;
607*4882a593Smuzhiyun spi_wr_flow(starget) = (nego & MPI_SCSIDEVPAGE0_NP_WR_FLOW) ? 1 : 0;
608*4882a593Smuzhiyun spi_rd_strm(starget) = (nego & MPI_SCSIDEVPAGE0_NP_RD_STRM) ? 1 : 0;
609*4882a593Smuzhiyun spi_rti(starget) = (nego & MPI_SCSIDEVPAGE0_NP_RTI) ? 1 : 0;
610*4882a593Smuzhiyun spi_pcomp_en(starget) = (nego & MPI_SCSIDEVPAGE0_NP_PCOMP_EN) ? 1 : 0;
611*4882a593Smuzhiyun spi_hold_mcs(starget) = (nego & MPI_SCSIDEVPAGE0_NP_HOLD_MCS) ? 1 : 0;
612*4882a593Smuzhiyun spi_period(starget) = (nego & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> MPI_SCSIDEVPAGE0_NP_SHIFT_SYNC_PERIOD;
613*4882a593Smuzhiyun spi_offset(starget) = (nego & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) >> MPI_SCSIDEVPAGE0_NP_SHIFT_SYNC_OFFSET;
614*4882a593Smuzhiyun spi_width(starget) = (nego & MPI_SCSIDEVPAGE0_NP_WIDE) ? 1 : 0;
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun static int
mptscsih_quiesce_raid(MPT_SCSI_HOST * hd,int quiesce,u8 channel,u8 id)618*4882a593Smuzhiyun mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id)
619*4882a593Smuzhiyun {
620*4882a593Smuzhiyun MPT_ADAPTER *ioc = hd->ioc;
621*4882a593Smuzhiyun MpiRaidActionRequest_t *pReq;
622*4882a593Smuzhiyun MPT_FRAME_HDR *mf;
623*4882a593Smuzhiyun int ret;
624*4882a593Smuzhiyun unsigned long timeleft;
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun mutex_lock(&ioc->internal_cmds.mutex);
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun /* Get and Populate a free Frame
629*4882a593Smuzhiyun */
630*4882a593Smuzhiyun if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
631*4882a593Smuzhiyun dfailprintk(hd->ioc, printk(MYIOC_s_WARN_FMT
632*4882a593Smuzhiyun "%s: no msg frames!\n", ioc->name, __func__));
633*4882a593Smuzhiyun ret = -EAGAIN;
634*4882a593Smuzhiyun goto out;
635*4882a593Smuzhiyun }
636*4882a593Smuzhiyun pReq = (MpiRaidActionRequest_t *)mf;
637*4882a593Smuzhiyun if (quiesce)
638*4882a593Smuzhiyun pReq->Action = MPI_RAID_ACTION_QUIESCE_PHYS_IO;
639*4882a593Smuzhiyun else
640*4882a593Smuzhiyun pReq->Action = MPI_RAID_ACTION_ENABLE_PHYS_IO;
641*4882a593Smuzhiyun pReq->Reserved1 = 0;
642*4882a593Smuzhiyun pReq->ChainOffset = 0;
643*4882a593Smuzhiyun pReq->Function = MPI_FUNCTION_RAID_ACTION;
644*4882a593Smuzhiyun pReq->VolumeID = id;
645*4882a593Smuzhiyun pReq->VolumeBus = channel;
646*4882a593Smuzhiyun pReq->PhysDiskNum = 0;
647*4882a593Smuzhiyun pReq->MsgFlags = 0;
648*4882a593Smuzhiyun pReq->Reserved2 = 0;
649*4882a593Smuzhiyun pReq->ActionDataWord = 0; /* Reserved for this action */
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun ioc->add_sge((char *)&pReq->ActionDataSGE,
652*4882a593Smuzhiyun MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
653*4882a593Smuzhiyun
654*4882a593Smuzhiyun ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n",
655*4882a593Smuzhiyun ioc->name, pReq->Action, channel, id));
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
658*4882a593Smuzhiyun mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
659*4882a593Smuzhiyun timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done, 10*HZ);
660*4882a593Smuzhiyun if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
661*4882a593Smuzhiyun ret = -ETIME;
662*4882a593Smuzhiyun dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: TIMED OUT!\n",
663*4882a593Smuzhiyun ioc->name, __func__));
664*4882a593Smuzhiyun if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
665*4882a593Smuzhiyun goto out;
666*4882a593Smuzhiyun if (!timeleft) {
667*4882a593Smuzhiyun printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
668*4882a593Smuzhiyun ioc->name, __func__);
669*4882a593Smuzhiyun mpt_HardResetHandler(ioc, CAN_SLEEP);
670*4882a593Smuzhiyun mpt_free_msg_frame(ioc, mf);
671*4882a593Smuzhiyun }
672*4882a593Smuzhiyun goto out;
673*4882a593Smuzhiyun }
674*4882a593Smuzhiyun
675*4882a593Smuzhiyun ret = ioc->internal_cmds.completion_code;
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun out:
678*4882a593Smuzhiyun CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
679*4882a593Smuzhiyun mutex_unlock(&ioc->internal_cmds.mutex);
680*4882a593Smuzhiyun return ret;
681*4882a593Smuzhiyun }
682*4882a593Smuzhiyun
mptspi_dv_device(struct _MPT_SCSI_HOST * hd,struct scsi_device * sdev)683*4882a593Smuzhiyun static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
684*4882a593Smuzhiyun struct scsi_device *sdev)
685*4882a593Smuzhiyun {
686*4882a593Smuzhiyun VirtTarget *vtarget = scsi_target(sdev)->hostdata;
687*4882a593Smuzhiyun MPT_ADAPTER *ioc = hd->ioc;
688*4882a593Smuzhiyun
689*4882a593Smuzhiyun /* no DV on RAID devices */
690*4882a593Smuzhiyun if (sdev->channel == 0 &&
691*4882a593Smuzhiyun mptspi_is_raid(hd, sdev->id))
692*4882a593Smuzhiyun return;
693*4882a593Smuzhiyun
694*4882a593Smuzhiyun /* If this is a piece of a RAID, then quiesce first */
695*4882a593Smuzhiyun if (sdev->channel == 1 &&
696*4882a593Smuzhiyun mptscsih_quiesce_raid(hd, 1, vtarget->channel, vtarget->id) < 0) {
697*4882a593Smuzhiyun starget_printk(KERN_ERR, scsi_target(sdev), MYIOC_s_FMT
698*4882a593Smuzhiyun "Integrated RAID quiesce failed\n", ioc->name);
699*4882a593Smuzhiyun return;
700*4882a593Smuzhiyun }
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun hd->spi_pending |= (1 << sdev->id);
703*4882a593Smuzhiyun spi_dv_device(sdev);
704*4882a593Smuzhiyun hd->spi_pending &= ~(1 << sdev->id);
705*4882a593Smuzhiyun
706*4882a593Smuzhiyun if (sdev->channel == 1 &&
707*4882a593Smuzhiyun mptscsih_quiesce_raid(hd, 0, vtarget->channel, vtarget->id) < 0)
708*4882a593Smuzhiyun starget_printk(KERN_ERR, scsi_target(sdev), MYIOC_s_FMT
709*4882a593Smuzhiyun "Integrated RAID resume failed\n", ioc->name);
710*4882a593Smuzhiyun
711*4882a593Smuzhiyun mptspi_read_parameters(sdev->sdev_target);
712*4882a593Smuzhiyun spi_display_xfer_agreement(sdev->sdev_target);
713*4882a593Smuzhiyun mptspi_read_parameters(sdev->sdev_target);
714*4882a593Smuzhiyun }
715*4882a593Smuzhiyun
mptspi_slave_alloc(struct scsi_device * sdev)716*4882a593Smuzhiyun static int mptspi_slave_alloc(struct scsi_device *sdev)
717*4882a593Smuzhiyun {
718*4882a593Smuzhiyun MPT_SCSI_HOST *hd = shost_priv(sdev->host);
719*4882a593Smuzhiyun VirtTarget *vtarget;
720*4882a593Smuzhiyun VirtDevice *vdevice;
721*4882a593Smuzhiyun struct scsi_target *starget;
722*4882a593Smuzhiyun MPT_ADAPTER *ioc = hd->ioc;
723*4882a593Smuzhiyun
724*4882a593Smuzhiyun if (sdev->channel == 1 &&
725*4882a593Smuzhiyun mptscsih_is_phys_disk(ioc, 0, sdev->id) == 0)
726*4882a593Smuzhiyun return -ENXIO;
727*4882a593Smuzhiyun
728*4882a593Smuzhiyun vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
729*4882a593Smuzhiyun if (!vdevice) {
730*4882a593Smuzhiyun printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
731*4882a593Smuzhiyun ioc->name, sizeof(VirtDevice));
732*4882a593Smuzhiyun return -ENOMEM;
733*4882a593Smuzhiyun }
734*4882a593Smuzhiyun
735*4882a593Smuzhiyun vdevice->lun = sdev->lun;
736*4882a593Smuzhiyun sdev->hostdata = vdevice;
737*4882a593Smuzhiyun
738*4882a593Smuzhiyun starget = scsi_target(sdev);
739*4882a593Smuzhiyun vtarget = starget->hostdata;
740*4882a593Smuzhiyun vdevice->vtarget = vtarget;
741*4882a593Smuzhiyun vtarget->num_luns++;
742*4882a593Smuzhiyun
743*4882a593Smuzhiyun if (sdev->channel == 1)
744*4882a593Smuzhiyun sdev->no_uld_attach = 1;
745*4882a593Smuzhiyun
746*4882a593Smuzhiyun return 0;
747*4882a593Smuzhiyun }
748*4882a593Smuzhiyun
mptspi_slave_configure(struct scsi_device * sdev)749*4882a593Smuzhiyun static int mptspi_slave_configure(struct scsi_device *sdev)
750*4882a593Smuzhiyun {
751*4882a593Smuzhiyun struct _MPT_SCSI_HOST *hd = shost_priv(sdev->host);
752*4882a593Smuzhiyun VirtTarget *vtarget = scsi_target(sdev)->hostdata;
753*4882a593Smuzhiyun int ret;
754*4882a593Smuzhiyun
755*4882a593Smuzhiyun mptspi_initTarget(hd, vtarget, sdev);
756*4882a593Smuzhiyun
757*4882a593Smuzhiyun ret = mptscsih_slave_configure(sdev);
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun if (ret)
760*4882a593Smuzhiyun return ret;
761*4882a593Smuzhiyun
762*4882a593Smuzhiyun ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d min_period=0x%02x"
763*4882a593Smuzhiyun " max_offset=0x%02x max_width=%d\n", hd->ioc->name,
764*4882a593Smuzhiyun sdev->id, spi_min_period(scsi_target(sdev)),
765*4882a593Smuzhiyun spi_max_offset(scsi_target(sdev)),
766*4882a593Smuzhiyun spi_max_width(scsi_target(sdev))));
767*4882a593Smuzhiyun
768*4882a593Smuzhiyun if ((sdev->channel == 1 ||
769*4882a593Smuzhiyun !(mptspi_is_raid(hd, sdev->id))) &&
770*4882a593Smuzhiyun !spi_initial_dv(sdev->sdev_target))
771*4882a593Smuzhiyun mptspi_dv_device(hd, sdev);
772*4882a593Smuzhiyun
773*4882a593Smuzhiyun return 0;
774*4882a593Smuzhiyun }
775*4882a593Smuzhiyun
776*4882a593Smuzhiyun static int
mptspi_qcmd(struct Scsi_Host * shost,struct scsi_cmnd * SCpnt)777*4882a593Smuzhiyun mptspi_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt)
778*4882a593Smuzhiyun {
779*4882a593Smuzhiyun struct _MPT_SCSI_HOST *hd = shost_priv(shost);
780*4882a593Smuzhiyun VirtDevice *vdevice = SCpnt->device->hostdata;
781*4882a593Smuzhiyun MPT_ADAPTER *ioc = hd->ioc;
782*4882a593Smuzhiyun
783*4882a593Smuzhiyun if (!vdevice || !vdevice->vtarget) {
784*4882a593Smuzhiyun SCpnt->result = DID_NO_CONNECT << 16;
785*4882a593Smuzhiyun SCpnt->scsi_done(SCpnt);
786*4882a593Smuzhiyun return 0;
787*4882a593Smuzhiyun }
788*4882a593Smuzhiyun
789*4882a593Smuzhiyun if (SCpnt->device->channel == 1 &&
790*4882a593Smuzhiyun mptscsih_is_phys_disk(ioc, 0, SCpnt->device->id) == 0) {
791*4882a593Smuzhiyun SCpnt->result = DID_NO_CONNECT << 16;
792*4882a593Smuzhiyun SCpnt->scsi_done(SCpnt);
793*4882a593Smuzhiyun return 0;
794*4882a593Smuzhiyun }
795*4882a593Smuzhiyun
796*4882a593Smuzhiyun if (spi_dv_pending(scsi_target(SCpnt->device)))
797*4882a593Smuzhiyun ddvprintk(ioc, scsi_print_command(SCpnt));
798*4882a593Smuzhiyun
799*4882a593Smuzhiyun return mptscsih_qcmd(SCpnt);
800*4882a593Smuzhiyun }
801*4882a593Smuzhiyun
mptspi_slave_destroy(struct scsi_device * sdev)802*4882a593Smuzhiyun static void mptspi_slave_destroy(struct scsi_device *sdev)
803*4882a593Smuzhiyun {
804*4882a593Smuzhiyun struct scsi_target *starget = scsi_target(sdev);
805*4882a593Smuzhiyun VirtTarget *vtarget = starget->hostdata;
806*4882a593Smuzhiyun VirtDevice *vdevice = sdev->hostdata;
807*4882a593Smuzhiyun
808*4882a593Smuzhiyun /* Will this be the last lun on a non-raid device? */
809*4882a593Smuzhiyun if (vtarget->num_luns == 1 && vdevice->configured_lun) {
810*4882a593Smuzhiyun struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
811*4882a593Smuzhiyun
812*4882a593Smuzhiyun /* Async Narrow */
813*4882a593Smuzhiyun pg1.RequestedParameters = 0;
814*4882a593Smuzhiyun pg1.Reserved = 0;
815*4882a593Smuzhiyun pg1.Configuration = 0;
816*4882a593Smuzhiyun
817*4882a593Smuzhiyun mptspi_write_spi_device_pg1(starget, &pg1);
818*4882a593Smuzhiyun }
819*4882a593Smuzhiyun
820*4882a593Smuzhiyun mptscsih_slave_destroy(sdev);
821*4882a593Smuzhiyun }
822*4882a593Smuzhiyun
823*4882a593Smuzhiyun static struct scsi_host_template mptspi_driver_template = {
824*4882a593Smuzhiyun .module = THIS_MODULE,
825*4882a593Smuzhiyun .proc_name = "mptspi",
826*4882a593Smuzhiyun .show_info = mptscsih_show_info,
827*4882a593Smuzhiyun .name = "MPT SPI Host",
828*4882a593Smuzhiyun .info = mptscsih_info,
829*4882a593Smuzhiyun .queuecommand = mptspi_qcmd,
830*4882a593Smuzhiyun .target_alloc = mptspi_target_alloc,
831*4882a593Smuzhiyun .slave_alloc = mptspi_slave_alloc,
832*4882a593Smuzhiyun .slave_configure = mptspi_slave_configure,
833*4882a593Smuzhiyun .target_destroy = mptspi_target_destroy,
834*4882a593Smuzhiyun .slave_destroy = mptspi_slave_destroy,
835*4882a593Smuzhiyun .change_queue_depth = mptscsih_change_queue_depth,
836*4882a593Smuzhiyun .eh_abort_handler = mptscsih_abort,
837*4882a593Smuzhiyun .eh_device_reset_handler = mptscsih_dev_reset,
838*4882a593Smuzhiyun .eh_bus_reset_handler = mptscsih_bus_reset,
839*4882a593Smuzhiyun .eh_host_reset_handler = mptscsih_host_reset,
840*4882a593Smuzhiyun .bios_param = mptscsih_bios_param,
841*4882a593Smuzhiyun .can_queue = MPT_SCSI_CAN_QUEUE,
842*4882a593Smuzhiyun .this_id = -1,
843*4882a593Smuzhiyun .sg_tablesize = MPT_SCSI_SG_DEPTH,
844*4882a593Smuzhiyun .max_sectors = 8192,
845*4882a593Smuzhiyun .cmd_per_lun = 7,
846*4882a593Smuzhiyun .shost_attrs = mptscsih_host_attrs,
847*4882a593Smuzhiyun };
848*4882a593Smuzhiyun
mptspi_write_spi_device_pg1(struct scsi_target * starget,struct _CONFIG_PAGE_SCSI_DEVICE_1 * pass_pg1)849*4882a593Smuzhiyun static int mptspi_write_spi_device_pg1(struct scsi_target *starget,
850*4882a593Smuzhiyun struct _CONFIG_PAGE_SCSI_DEVICE_1 *pass_pg1)
851*4882a593Smuzhiyun {
852*4882a593Smuzhiyun struct Scsi_Host *shost = dev_to_shost(&starget->dev);
853*4882a593Smuzhiyun struct _MPT_SCSI_HOST *hd = shost_priv(shost);
854*4882a593Smuzhiyun struct _MPT_ADAPTER *ioc = hd->ioc;
855*4882a593Smuzhiyun struct _CONFIG_PAGE_SCSI_DEVICE_1 *pg1;
856*4882a593Smuzhiyun dma_addr_t pg1_dma;
857*4882a593Smuzhiyun int size;
858*4882a593Smuzhiyun struct _x_config_parms cfg;
859*4882a593Smuzhiyun struct _CONFIG_PAGE_HEADER hdr;
860*4882a593Smuzhiyun int err = -EBUSY;
861*4882a593Smuzhiyun u32 nego_parms;
862*4882a593Smuzhiyun u32 period;
863*4882a593Smuzhiyun struct scsi_device *sdev;
864*4882a593Smuzhiyun int i;
865*4882a593Smuzhiyun
866*4882a593Smuzhiyun /* don't allow updating nego parameters on RAID devices */
867*4882a593Smuzhiyun if (starget->channel == 0 &&
868*4882a593Smuzhiyun mptspi_is_raid(hd, starget->id))
869*4882a593Smuzhiyun return -1;
870*4882a593Smuzhiyun
871*4882a593Smuzhiyun size = ioc->spi_data.sdp1length * 4;
872*4882a593Smuzhiyun
873*4882a593Smuzhiyun pg1 = dma_alloc_coherent(&ioc->pcidev->dev, size, &pg1_dma, GFP_KERNEL);
874*4882a593Smuzhiyun if (pg1 == NULL) {
875*4882a593Smuzhiyun starget_printk(KERN_ERR, starget, MYIOC_s_FMT
876*4882a593Smuzhiyun "dma_alloc_coherent for parameters failed\n", ioc->name);
877*4882a593Smuzhiyun return -EINVAL;
878*4882a593Smuzhiyun }
879*4882a593Smuzhiyun
880*4882a593Smuzhiyun memset(&hdr, 0, sizeof(hdr));
881*4882a593Smuzhiyun
882*4882a593Smuzhiyun hdr.PageVersion = ioc->spi_data.sdp1version;
883*4882a593Smuzhiyun hdr.PageLength = ioc->spi_data.sdp1length;
884*4882a593Smuzhiyun hdr.PageNumber = 1;
885*4882a593Smuzhiyun hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
886*4882a593Smuzhiyun
887*4882a593Smuzhiyun memset(&cfg, 0, sizeof(cfg));
888*4882a593Smuzhiyun
889*4882a593Smuzhiyun cfg.cfghdr.hdr = &hdr;
890*4882a593Smuzhiyun cfg.physAddr = pg1_dma;
891*4882a593Smuzhiyun cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
892*4882a593Smuzhiyun cfg.dir = 1;
893*4882a593Smuzhiyun cfg.pageAddr = starget->id;
894*4882a593Smuzhiyun
895*4882a593Smuzhiyun memcpy(pg1, pass_pg1, size);
896*4882a593Smuzhiyun
897*4882a593Smuzhiyun pg1->Header.PageVersion = hdr.PageVersion;
898*4882a593Smuzhiyun pg1->Header.PageLength = hdr.PageLength;
899*4882a593Smuzhiyun pg1->Header.PageNumber = hdr.PageNumber;
900*4882a593Smuzhiyun pg1->Header.PageType = hdr.PageType;
901*4882a593Smuzhiyun
902*4882a593Smuzhiyun nego_parms = le32_to_cpu(pg1->RequestedParameters);
903*4882a593Smuzhiyun period = (nego_parms & MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK) >>
904*4882a593Smuzhiyun MPI_SCSIDEVPAGE1_RP_SHIFT_MIN_SYNC_PERIOD;
905*4882a593Smuzhiyun if (period == 8) {
906*4882a593Smuzhiyun /* Turn on inline data padding for TAPE when running U320 */
907*4882a593Smuzhiyun for (i = 0 ; i < 16; i++) {
908*4882a593Smuzhiyun sdev = scsi_device_lookup_by_target(starget, i);
909*4882a593Smuzhiyun if (sdev && sdev->type == TYPE_TAPE) {
910*4882a593Smuzhiyun sdev_printk(KERN_DEBUG, sdev, MYIOC_s_FMT
911*4882a593Smuzhiyun "IDP:ON\n", ioc->name);
912*4882a593Smuzhiyun nego_parms |= MPI_SCSIDEVPAGE1_RP_IDP;
913*4882a593Smuzhiyun pg1->RequestedParameters =
914*4882a593Smuzhiyun cpu_to_le32(nego_parms);
915*4882a593Smuzhiyun break;
916*4882a593Smuzhiyun }
917*4882a593Smuzhiyun }
918*4882a593Smuzhiyun }
919*4882a593Smuzhiyun
920*4882a593Smuzhiyun mptspi_print_write_nego(hd, starget, le32_to_cpu(pg1->RequestedParameters));
921*4882a593Smuzhiyun
922*4882a593Smuzhiyun if (mpt_config(ioc, &cfg)) {
923*4882a593Smuzhiyun starget_printk(KERN_ERR, starget, MYIOC_s_FMT
924*4882a593Smuzhiyun "mpt_config failed\n", ioc->name);
925*4882a593Smuzhiyun goto out_free;
926*4882a593Smuzhiyun }
927*4882a593Smuzhiyun err = 0;
928*4882a593Smuzhiyun
929*4882a593Smuzhiyun out_free:
930*4882a593Smuzhiyun dma_free_coherent(&ioc->pcidev->dev, size, pg1, pg1_dma);
931*4882a593Smuzhiyun return err;
932*4882a593Smuzhiyun }
933*4882a593Smuzhiyun
mptspi_write_offset(struct scsi_target * starget,int offset)934*4882a593Smuzhiyun static void mptspi_write_offset(struct scsi_target *starget, int offset)
935*4882a593Smuzhiyun {
936*4882a593Smuzhiyun struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
937*4882a593Smuzhiyun u32 nego;
938*4882a593Smuzhiyun
939*4882a593Smuzhiyun if (offset < 0)
940*4882a593Smuzhiyun offset = 0;
941*4882a593Smuzhiyun
942*4882a593Smuzhiyun if (offset > 255)
943*4882a593Smuzhiyun offset = 255;
944*4882a593Smuzhiyun
945*4882a593Smuzhiyun if (spi_offset(starget) == -1)
946*4882a593Smuzhiyun mptspi_read_parameters(starget);
947*4882a593Smuzhiyun
948*4882a593Smuzhiyun spi_offset(starget) = offset;
949*4882a593Smuzhiyun
950*4882a593Smuzhiyun nego = mptspi_getRP(starget);
951*4882a593Smuzhiyun
952*4882a593Smuzhiyun pg1.RequestedParameters = cpu_to_le32(nego);
953*4882a593Smuzhiyun pg1.Reserved = 0;
954*4882a593Smuzhiyun pg1.Configuration = 0;
955*4882a593Smuzhiyun
956*4882a593Smuzhiyun mptspi_write_spi_device_pg1(starget, &pg1);
957*4882a593Smuzhiyun }
958*4882a593Smuzhiyun
mptspi_write_period(struct scsi_target * starget,int period)959*4882a593Smuzhiyun static void mptspi_write_period(struct scsi_target *starget, int period)
960*4882a593Smuzhiyun {
961*4882a593Smuzhiyun struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
962*4882a593Smuzhiyun u32 nego;
963*4882a593Smuzhiyun
964*4882a593Smuzhiyun if (period < 8)
965*4882a593Smuzhiyun period = 8;
966*4882a593Smuzhiyun
967*4882a593Smuzhiyun if (period > 255)
968*4882a593Smuzhiyun period = 255;
969*4882a593Smuzhiyun
970*4882a593Smuzhiyun if (spi_period(starget) == -1)
971*4882a593Smuzhiyun mptspi_read_parameters(starget);
972*4882a593Smuzhiyun
973*4882a593Smuzhiyun if (period == 8) {
974*4882a593Smuzhiyun spi_iu(starget) = 1;
975*4882a593Smuzhiyun spi_dt(starget) = 1;
976*4882a593Smuzhiyun } else if (period == 9) {
977*4882a593Smuzhiyun spi_dt(starget) = 1;
978*4882a593Smuzhiyun }
979*4882a593Smuzhiyun
980*4882a593Smuzhiyun spi_period(starget) = period;
981*4882a593Smuzhiyun
982*4882a593Smuzhiyun nego = mptspi_getRP(starget);
983*4882a593Smuzhiyun
984*4882a593Smuzhiyun pg1.RequestedParameters = cpu_to_le32(nego);
985*4882a593Smuzhiyun pg1.Reserved = 0;
986*4882a593Smuzhiyun pg1.Configuration = 0;
987*4882a593Smuzhiyun
988*4882a593Smuzhiyun mptspi_write_spi_device_pg1(starget, &pg1);
989*4882a593Smuzhiyun }
990*4882a593Smuzhiyun
mptspi_write_dt(struct scsi_target * starget,int dt)991*4882a593Smuzhiyun static void mptspi_write_dt(struct scsi_target *starget, int dt)
992*4882a593Smuzhiyun {
993*4882a593Smuzhiyun struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
994*4882a593Smuzhiyun u32 nego;
995*4882a593Smuzhiyun
996*4882a593Smuzhiyun if (spi_period(starget) == -1)
997*4882a593Smuzhiyun mptspi_read_parameters(starget);
998*4882a593Smuzhiyun
999*4882a593Smuzhiyun if (!dt && spi_period(starget) < 10)
1000*4882a593Smuzhiyun spi_period(starget) = 10;
1001*4882a593Smuzhiyun
1002*4882a593Smuzhiyun spi_dt(starget) = dt;
1003*4882a593Smuzhiyun
1004*4882a593Smuzhiyun nego = mptspi_getRP(starget);
1005*4882a593Smuzhiyun
1006*4882a593Smuzhiyun
1007*4882a593Smuzhiyun pg1.RequestedParameters = cpu_to_le32(nego);
1008*4882a593Smuzhiyun pg1.Reserved = 0;
1009*4882a593Smuzhiyun pg1.Configuration = 0;
1010*4882a593Smuzhiyun
1011*4882a593Smuzhiyun mptspi_write_spi_device_pg1(starget, &pg1);
1012*4882a593Smuzhiyun }
1013*4882a593Smuzhiyun
mptspi_write_iu(struct scsi_target * starget,int iu)1014*4882a593Smuzhiyun static void mptspi_write_iu(struct scsi_target *starget, int iu)
1015*4882a593Smuzhiyun {
1016*4882a593Smuzhiyun struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
1017*4882a593Smuzhiyun u32 nego;
1018*4882a593Smuzhiyun
1019*4882a593Smuzhiyun if (spi_period(starget) == -1)
1020*4882a593Smuzhiyun mptspi_read_parameters(starget);
1021*4882a593Smuzhiyun
1022*4882a593Smuzhiyun if (!iu && spi_period(starget) < 9)
1023*4882a593Smuzhiyun spi_period(starget) = 9;
1024*4882a593Smuzhiyun
1025*4882a593Smuzhiyun spi_iu(starget) = iu;
1026*4882a593Smuzhiyun
1027*4882a593Smuzhiyun nego = mptspi_getRP(starget);
1028*4882a593Smuzhiyun
1029*4882a593Smuzhiyun pg1.RequestedParameters = cpu_to_le32(nego);
1030*4882a593Smuzhiyun pg1.Reserved = 0;
1031*4882a593Smuzhiyun pg1.Configuration = 0;
1032*4882a593Smuzhiyun
1033*4882a593Smuzhiyun mptspi_write_spi_device_pg1(starget, &pg1);
1034*4882a593Smuzhiyun }
1035*4882a593Smuzhiyun
1036*4882a593Smuzhiyun #define MPTSPI_SIMPLE_TRANSPORT_PARM(parm) \
1037*4882a593Smuzhiyun static void mptspi_write_##parm(struct scsi_target *starget, int parm)\
1038*4882a593Smuzhiyun { \
1039*4882a593Smuzhiyun struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; \
1040*4882a593Smuzhiyun u32 nego; \
1041*4882a593Smuzhiyun \
1042*4882a593Smuzhiyun spi_##parm(starget) = parm; \
1043*4882a593Smuzhiyun \
1044*4882a593Smuzhiyun nego = mptspi_getRP(starget); \
1045*4882a593Smuzhiyun \
1046*4882a593Smuzhiyun pg1.RequestedParameters = cpu_to_le32(nego); \
1047*4882a593Smuzhiyun pg1.Reserved = 0; \
1048*4882a593Smuzhiyun pg1.Configuration = 0; \
1049*4882a593Smuzhiyun \
1050*4882a593Smuzhiyun mptspi_write_spi_device_pg1(starget, &pg1); \
1051*4882a593Smuzhiyun }
1052*4882a593Smuzhiyun
1053*4882a593Smuzhiyun MPTSPI_SIMPLE_TRANSPORT_PARM(rd_strm)
MPTSPI_SIMPLE_TRANSPORT_PARM(wr_flow)1054*4882a593Smuzhiyun MPTSPI_SIMPLE_TRANSPORT_PARM(wr_flow)
1055*4882a593Smuzhiyun MPTSPI_SIMPLE_TRANSPORT_PARM(rti)
1056*4882a593Smuzhiyun MPTSPI_SIMPLE_TRANSPORT_PARM(hold_mcs)
1057*4882a593Smuzhiyun MPTSPI_SIMPLE_TRANSPORT_PARM(pcomp_en)
1058*4882a593Smuzhiyun
1059*4882a593Smuzhiyun static void mptspi_write_qas(struct scsi_target *starget, int qas)
1060*4882a593Smuzhiyun {
1061*4882a593Smuzhiyun struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
1062*4882a593Smuzhiyun struct Scsi_Host *shost = dev_to_shost(&starget->dev);
1063*4882a593Smuzhiyun struct _MPT_SCSI_HOST *hd = shost_priv(shost);
1064*4882a593Smuzhiyun VirtTarget *vtarget = starget->hostdata;
1065*4882a593Smuzhiyun u32 nego;
1066*4882a593Smuzhiyun
1067*4882a593Smuzhiyun if ((vtarget->negoFlags & MPT_TARGET_NO_NEGO_QAS) ||
1068*4882a593Smuzhiyun hd->ioc->spi_data.noQas)
1069*4882a593Smuzhiyun spi_qas(starget) = 0;
1070*4882a593Smuzhiyun else
1071*4882a593Smuzhiyun spi_qas(starget) = qas;
1072*4882a593Smuzhiyun
1073*4882a593Smuzhiyun nego = mptspi_getRP(starget);
1074*4882a593Smuzhiyun
1075*4882a593Smuzhiyun pg1.RequestedParameters = cpu_to_le32(nego);
1076*4882a593Smuzhiyun pg1.Reserved = 0;
1077*4882a593Smuzhiyun pg1.Configuration = 0;
1078*4882a593Smuzhiyun
1079*4882a593Smuzhiyun mptspi_write_spi_device_pg1(starget, &pg1);
1080*4882a593Smuzhiyun }
1081*4882a593Smuzhiyun
mptspi_write_width(struct scsi_target * starget,int width)1082*4882a593Smuzhiyun static void mptspi_write_width(struct scsi_target *starget, int width)
1083*4882a593Smuzhiyun {
1084*4882a593Smuzhiyun struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
1085*4882a593Smuzhiyun u32 nego;
1086*4882a593Smuzhiyun
1087*4882a593Smuzhiyun if (!width) {
1088*4882a593Smuzhiyun spi_dt(starget) = 0;
1089*4882a593Smuzhiyun if (spi_period(starget) < 10)
1090*4882a593Smuzhiyun spi_period(starget) = 10;
1091*4882a593Smuzhiyun }
1092*4882a593Smuzhiyun
1093*4882a593Smuzhiyun spi_width(starget) = width;
1094*4882a593Smuzhiyun
1095*4882a593Smuzhiyun nego = mptspi_getRP(starget);
1096*4882a593Smuzhiyun
1097*4882a593Smuzhiyun pg1.RequestedParameters = cpu_to_le32(nego);
1098*4882a593Smuzhiyun pg1.Reserved = 0;
1099*4882a593Smuzhiyun pg1.Configuration = 0;
1100*4882a593Smuzhiyun
1101*4882a593Smuzhiyun mptspi_write_spi_device_pg1(starget, &pg1);
1102*4882a593Smuzhiyun }
1103*4882a593Smuzhiyun
1104*4882a593Smuzhiyun struct work_queue_wrapper {
1105*4882a593Smuzhiyun struct work_struct work;
1106*4882a593Smuzhiyun struct _MPT_SCSI_HOST *hd;
1107*4882a593Smuzhiyun int disk;
1108*4882a593Smuzhiyun };
1109*4882a593Smuzhiyun
mpt_work_wrapper(struct work_struct * work)1110*4882a593Smuzhiyun static void mpt_work_wrapper(struct work_struct *work)
1111*4882a593Smuzhiyun {
1112*4882a593Smuzhiyun struct work_queue_wrapper *wqw =
1113*4882a593Smuzhiyun container_of(work, struct work_queue_wrapper, work);
1114*4882a593Smuzhiyun struct _MPT_SCSI_HOST *hd = wqw->hd;
1115*4882a593Smuzhiyun MPT_ADAPTER *ioc = hd->ioc;
1116*4882a593Smuzhiyun struct Scsi_Host *shost = ioc->sh;
1117*4882a593Smuzhiyun struct scsi_device *sdev;
1118*4882a593Smuzhiyun int disk = wqw->disk;
1119*4882a593Smuzhiyun struct _CONFIG_PAGE_IOC_3 *pg3;
1120*4882a593Smuzhiyun
1121*4882a593Smuzhiyun kfree(wqw);
1122*4882a593Smuzhiyun
1123*4882a593Smuzhiyun mpt_findImVolumes(ioc);
1124*4882a593Smuzhiyun pg3 = ioc->raid_data.pIocPg3;
1125*4882a593Smuzhiyun if (!pg3)
1126*4882a593Smuzhiyun return;
1127*4882a593Smuzhiyun
1128*4882a593Smuzhiyun shost_for_each_device(sdev,shost) {
1129*4882a593Smuzhiyun struct scsi_target *starget = scsi_target(sdev);
1130*4882a593Smuzhiyun VirtTarget *vtarget = starget->hostdata;
1131*4882a593Smuzhiyun
1132*4882a593Smuzhiyun /* only want to search RAID components */
1133*4882a593Smuzhiyun if (sdev->channel != 1)
1134*4882a593Smuzhiyun continue;
1135*4882a593Smuzhiyun
1136*4882a593Smuzhiyun /* The id is the raid PhysDiskNum, even if
1137*4882a593Smuzhiyun * starget->id is the actual target address */
1138*4882a593Smuzhiyun if(vtarget->id != disk)
1139*4882a593Smuzhiyun continue;
1140*4882a593Smuzhiyun
1141*4882a593Smuzhiyun starget_printk(KERN_INFO, vtarget->starget, MYIOC_s_FMT
1142*4882a593Smuzhiyun "Integrated RAID requests DV of new device\n", ioc->name);
1143*4882a593Smuzhiyun mptspi_dv_device(hd, sdev);
1144*4882a593Smuzhiyun }
1145*4882a593Smuzhiyun shost_printk(KERN_INFO, shost, MYIOC_s_FMT
1146*4882a593Smuzhiyun "Integrated RAID detects new device %d\n", ioc->name, disk);
1147*4882a593Smuzhiyun scsi_scan_target(&ioc->sh->shost_gendev, 1, disk, 0, SCSI_SCAN_RESCAN);
1148*4882a593Smuzhiyun }
1149*4882a593Smuzhiyun
1150*4882a593Smuzhiyun
mpt_dv_raid(struct _MPT_SCSI_HOST * hd,int disk)1151*4882a593Smuzhiyun static void mpt_dv_raid(struct _MPT_SCSI_HOST *hd, int disk)
1152*4882a593Smuzhiyun {
1153*4882a593Smuzhiyun struct work_queue_wrapper *wqw = kmalloc(sizeof(*wqw), GFP_ATOMIC);
1154*4882a593Smuzhiyun MPT_ADAPTER *ioc = hd->ioc;
1155*4882a593Smuzhiyun
1156*4882a593Smuzhiyun if (!wqw) {
1157*4882a593Smuzhiyun shost_printk(KERN_ERR, ioc->sh, MYIOC_s_FMT
1158*4882a593Smuzhiyun "Failed to act on RAID event for physical disk %d\n",
1159*4882a593Smuzhiyun ioc->name, disk);
1160*4882a593Smuzhiyun return;
1161*4882a593Smuzhiyun }
1162*4882a593Smuzhiyun INIT_WORK(&wqw->work, mpt_work_wrapper);
1163*4882a593Smuzhiyun wqw->hd = hd;
1164*4882a593Smuzhiyun wqw->disk = disk;
1165*4882a593Smuzhiyun
1166*4882a593Smuzhiyun schedule_work(&wqw->work);
1167*4882a593Smuzhiyun }
1168*4882a593Smuzhiyun
1169*4882a593Smuzhiyun static int
mptspi_event_process(MPT_ADAPTER * ioc,EventNotificationReply_t * pEvReply)1170*4882a593Smuzhiyun mptspi_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
1171*4882a593Smuzhiyun {
1172*4882a593Smuzhiyun u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
1173*4882a593Smuzhiyun struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
1174*4882a593Smuzhiyun
1175*4882a593Smuzhiyun if (ioc->bus_type != SPI)
1176*4882a593Smuzhiyun return 0;
1177*4882a593Smuzhiyun
1178*4882a593Smuzhiyun if (hd && event == MPI_EVENT_INTEGRATED_RAID) {
1179*4882a593Smuzhiyun int reason
1180*4882a593Smuzhiyun = (le32_to_cpu(pEvReply->Data[0]) & 0x00FF0000) >> 16;
1181*4882a593Smuzhiyun
1182*4882a593Smuzhiyun if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
1183*4882a593Smuzhiyun int disk = (le32_to_cpu(pEvReply->Data[0]) & 0xFF000000) >> 24;
1184*4882a593Smuzhiyun mpt_dv_raid(hd, disk);
1185*4882a593Smuzhiyun }
1186*4882a593Smuzhiyun }
1187*4882a593Smuzhiyun return mptscsih_event_process(ioc, pEvReply);
1188*4882a593Smuzhiyun }
1189*4882a593Smuzhiyun
1190*4882a593Smuzhiyun static int
mptspi_deny_binding(struct scsi_target * starget)1191*4882a593Smuzhiyun mptspi_deny_binding(struct scsi_target *starget)
1192*4882a593Smuzhiyun {
1193*4882a593Smuzhiyun struct _MPT_SCSI_HOST *hd =
1194*4882a593Smuzhiyun (struct _MPT_SCSI_HOST *)dev_to_shost(starget->dev.parent)->hostdata;
1195*4882a593Smuzhiyun return ((mptspi_is_raid(hd, starget->id)) &&
1196*4882a593Smuzhiyun starget->channel == 0) ? 1 : 0;
1197*4882a593Smuzhiyun }
1198*4882a593Smuzhiyun
1199*4882a593Smuzhiyun static struct spi_function_template mptspi_transport_functions = {
1200*4882a593Smuzhiyun .get_offset = mptspi_read_parameters,
1201*4882a593Smuzhiyun .set_offset = mptspi_write_offset,
1202*4882a593Smuzhiyun .show_offset = 1,
1203*4882a593Smuzhiyun .get_period = mptspi_read_parameters,
1204*4882a593Smuzhiyun .set_period = mptspi_write_period,
1205*4882a593Smuzhiyun .show_period = 1,
1206*4882a593Smuzhiyun .get_width = mptspi_read_parameters,
1207*4882a593Smuzhiyun .set_width = mptspi_write_width,
1208*4882a593Smuzhiyun .show_width = 1,
1209*4882a593Smuzhiyun .get_iu = mptspi_read_parameters,
1210*4882a593Smuzhiyun .set_iu = mptspi_write_iu,
1211*4882a593Smuzhiyun .show_iu = 1,
1212*4882a593Smuzhiyun .get_dt = mptspi_read_parameters,
1213*4882a593Smuzhiyun .set_dt = mptspi_write_dt,
1214*4882a593Smuzhiyun .show_dt = 1,
1215*4882a593Smuzhiyun .get_qas = mptspi_read_parameters,
1216*4882a593Smuzhiyun .set_qas = mptspi_write_qas,
1217*4882a593Smuzhiyun .show_qas = 1,
1218*4882a593Smuzhiyun .get_wr_flow = mptspi_read_parameters,
1219*4882a593Smuzhiyun .set_wr_flow = mptspi_write_wr_flow,
1220*4882a593Smuzhiyun .show_wr_flow = 1,
1221*4882a593Smuzhiyun .get_rd_strm = mptspi_read_parameters,
1222*4882a593Smuzhiyun .set_rd_strm = mptspi_write_rd_strm,
1223*4882a593Smuzhiyun .show_rd_strm = 1,
1224*4882a593Smuzhiyun .get_rti = mptspi_read_parameters,
1225*4882a593Smuzhiyun .set_rti = mptspi_write_rti,
1226*4882a593Smuzhiyun .show_rti = 1,
1227*4882a593Smuzhiyun .get_pcomp_en = mptspi_read_parameters,
1228*4882a593Smuzhiyun .set_pcomp_en = mptspi_write_pcomp_en,
1229*4882a593Smuzhiyun .show_pcomp_en = 1,
1230*4882a593Smuzhiyun .get_hold_mcs = mptspi_read_parameters,
1231*4882a593Smuzhiyun .set_hold_mcs = mptspi_write_hold_mcs,
1232*4882a593Smuzhiyun .show_hold_mcs = 1,
1233*4882a593Smuzhiyun .deny_binding = mptspi_deny_binding,
1234*4882a593Smuzhiyun };
1235*4882a593Smuzhiyun
1236*4882a593Smuzhiyun /****************************************************************************
1237*4882a593Smuzhiyun * Supported hardware
1238*4882a593Smuzhiyun */
1239*4882a593Smuzhiyun
1240*4882a593Smuzhiyun static struct pci_device_id mptspi_pci_table[] = {
1241*4882a593Smuzhiyun { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1030,
1242*4882a593Smuzhiyun PCI_ANY_ID, PCI_ANY_ID },
1243*4882a593Smuzhiyun { PCI_VENDOR_ID_ATTO, MPI_MANUFACTPAGE_DEVID_53C1030,
1244*4882a593Smuzhiyun PCI_ANY_ID, PCI_ANY_ID },
1245*4882a593Smuzhiyun { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1035,
1246*4882a593Smuzhiyun PCI_ANY_ID, PCI_ANY_ID },
1247*4882a593Smuzhiyun {0} /* Terminating entry */
1248*4882a593Smuzhiyun };
1249*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pci, mptspi_pci_table);
1250*4882a593Smuzhiyun
1251*4882a593Smuzhiyun
1252*4882a593Smuzhiyun /*
1253*4882a593Smuzhiyun * renegotiate for a given target
1254*4882a593Smuzhiyun */
1255*4882a593Smuzhiyun static void
mptspi_dv_renegotiate_work(struct work_struct * work)1256*4882a593Smuzhiyun mptspi_dv_renegotiate_work(struct work_struct *work)
1257*4882a593Smuzhiyun {
1258*4882a593Smuzhiyun struct work_queue_wrapper *wqw =
1259*4882a593Smuzhiyun container_of(work, struct work_queue_wrapper, work);
1260*4882a593Smuzhiyun struct _MPT_SCSI_HOST *hd = wqw->hd;
1261*4882a593Smuzhiyun struct scsi_device *sdev;
1262*4882a593Smuzhiyun struct scsi_target *starget;
1263*4882a593Smuzhiyun struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
1264*4882a593Smuzhiyun u32 nego;
1265*4882a593Smuzhiyun MPT_ADAPTER *ioc = hd->ioc;
1266*4882a593Smuzhiyun
1267*4882a593Smuzhiyun kfree(wqw);
1268*4882a593Smuzhiyun
1269*4882a593Smuzhiyun if (hd->spi_pending) {
1270*4882a593Smuzhiyun shost_for_each_device(sdev, ioc->sh) {
1271*4882a593Smuzhiyun if (hd->spi_pending & (1 << sdev->id))
1272*4882a593Smuzhiyun continue;
1273*4882a593Smuzhiyun starget = scsi_target(sdev);
1274*4882a593Smuzhiyun nego = mptspi_getRP(starget);
1275*4882a593Smuzhiyun pg1.RequestedParameters = cpu_to_le32(nego);
1276*4882a593Smuzhiyun pg1.Reserved = 0;
1277*4882a593Smuzhiyun pg1.Configuration = 0;
1278*4882a593Smuzhiyun mptspi_write_spi_device_pg1(starget, &pg1);
1279*4882a593Smuzhiyun }
1280*4882a593Smuzhiyun } else {
1281*4882a593Smuzhiyun shost_for_each_device(sdev, ioc->sh)
1282*4882a593Smuzhiyun mptspi_dv_device(hd, sdev);
1283*4882a593Smuzhiyun }
1284*4882a593Smuzhiyun }
1285*4882a593Smuzhiyun
1286*4882a593Smuzhiyun static void
mptspi_dv_renegotiate(struct _MPT_SCSI_HOST * hd)1287*4882a593Smuzhiyun mptspi_dv_renegotiate(struct _MPT_SCSI_HOST *hd)
1288*4882a593Smuzhiyun {
1289*4882a593Smuzhiyun struct work_queue_wrapper *wqw = kmalloc(sizeof(*wqw), GFP_ATOMIC);
1290*4882a593Smuzhiyun
1291*4882a593Smuzhiyun if (!wqw)
1292*4882a593Smuzhiyun return;
1293*4882a593Smuzhiyun
1294*4882a593Smuzhiyun INIT_WORK(&wqw->work, mptspi_dv_renegotiate_work);
1295*4882a593Smuzhiyun wqw->hd = hd;
1296*4882a593Smuzhiyun
1297*4882a593Smuzhiyun schedule_work(&wqw->work);
1298*4882a593Smuzhiyun }
1299*4882a593Smuzhiyun
1300*4882a593Smuzhiyun /*
1301*4882a593Smuzhiyun * spi module reset handler
1302*4882a593Smuzhiyun */
1303*4882a593Smuzhiyun static int
mptspi_ioc_reset(MPT_ADAPTER * ioc,int reset_phase)1304*4882a593Smuzhiyun mptspi_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
1305*4882a593Smuzhiyun {
1306*4882a593Smuzhiyun int rc;
1307*4882a593Smuzhiyun
1308*4882a593Smuzhiyun rc = mptscsih_ioc_reset(ioc, reset_phase);
1309*4882a593Smuzhiyun if ((ioc->bus_type != SPI) || (!rc))
1310*4882a593Smuzhiyun return rc;
1311*4882a593Smuzhiyun
1312*4882a593Smuzhiyun /* only try to do a renegotiation if we're properly set up
1313*4882a593Smuzhiyun * if we get an ioc fault on bringup, ioc->sh will be NULL */
1314*4882a593Smuzhiyun if (reset_phase == MPT_IOC_POST_RESET &&
1315*4882a593Smuzhiyun ioc->sh) {
1316*4882a593Smuzhiyun struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
1317*4882a593Smuzhiyun
1318*4882a593Smuzhiyun mptspi_dv_renegotiate(hd);
1319*4882a593Smuzhiyun }
1320*4882a593Smuzhiyun
1321*4882a593Smuzhiyun return rc;
1322*4882a593Smuzhiyun }
1323*4882a593Smuzhiyun
1324*4882a593Smuzhiyun #ifdef CONFIG_PM
1325*4882a593Smuzhiyun /*
1326*4882a593Smuzhiyun * spi module resume handler
1327*4882a593Smuzhiyun */
1328*4882a593Smuzhiyun static int
mptspi_resume(struct pci_dev * pdev)1329*4882a593Smuzhiyun mptspi_resume(struct pci_dev *pdev)
1330*4882a593Smuzhiyun {
1331*4882a593Smuzhiyun MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1332*4882a593Smuzhiyun struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
1333*4882a593Smuzhiyun int rc;
1334*4882a593Smuzhiyun
1335*4882a593Smuzhiyun rc = mptscsih_resume(pdev);
1336*4882a593Smuzhiyun mptspi_dv_renegotiate(hd);
1337*4882a593Smuzhiyun
1338*4882a593Smuzhiyun return rc;
1339*4882a593Smuzhiyun }
1340*4882a593Smuzhiyun #endif
1341*4882a593Smuzhiyun
1342*4882a593Smuzhiyun /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1343*4882a593Smuzhiyun /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1344*4882a593Smuzhiyun /*
1345*4882a593Smuzhiyun * mptspi_probe - Installs scsi devices per bus.
1346*4882a593Smuzhiyun * @pdev: Pointer to pci_dev structure
1347*4882a593Smuzhiyun *
1348*4882a593Smuzhiyun * Returns 0 for success, non-zero for failure.
1349*4882a593Smuzhiyun *
1350*4882a593Smuzhiyun */
1351*4882a593Smuzhiyun static int
mptspi_probe(struct pci_dev * pdev,const struct pci_device_id * id)1352*4882a593Smuzhiyun mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
1353*4882a593Smuzhiyun {
1354*4882a593Smuzhiyun struct Scsi_Host *sh;
1355*4882a593Smuzhiyun MPT_SCSI_HOST *hd;
1356*4882a593Smuzhiyun MPT_ADAPTER *ioc;
1357*4882a593Smuzhiyun unsigned long flags;
1358*4882a593Smuzhiyun int ii;
1359*4882a593Smuzhiyun int numSGE = 0;
1360*4882a593Smuzhiyun int scale;
1361*4882a593Smuzhiyun int ioc_cap;
1362*4882a593Smuzhiyun int error=0;
1363*4882a593Smuzhiyun int r;
1364*4882a593Smuzhiyun
1365*4882a593Smuzhiyun if ((r = mpt_attach(pdev,id)) != 0)
1366*4882a593Smuzhiyun return r;
1367*4882a593Smuzhiyun
1368*4882a593Smuzhiyun ioc = pci_get_drvdata(pdev);
1369*4882a593Smuzhiyun ioc->DoneCtx = mptspiDoneCtx;
1370*4882a593Smuzhiyun ioc->TaskCtx = mptspiTaskCtx;
1371*4882a593Smuzhiyun ioc->InternalCtx = mptspiInternalCtx;
1372*4882a593Smuzhiyun
1373*4882a593Smuzhiyun /* Added sanity check on readiness of the MPT adapter.
1374*4882a593Smuzhiyun */
1375*4882a593Smuzhiyun if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
1376*4882a593Smuzhiyun printk(MYIOC_s_WARN_FMT
1377*4882a593Smuzhiyun "Skipping because it's not operational!\n",
1378*4882a593Smuzhiyun ioc->name);
1379*4882a593Smuzhiyun error = -ENODEV;
1380*4882a593Smuzhiyun goto out_mptspi_probe;
1381*4882a593Smuzhiyun }
1382*4882a593Smuzhiyun
1383*4882a593Smuzhiyun if (!ioc->active) {
1384*4882a593Smuzhiyun printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
1385*4882a593Smuzhiyun ioc->name);
1386*4882a593Smuzhiyun error = -ENODEV;
1387*4882a593Smuzhiyun goto out_mptspi_probe;
1388*4882a593Smuzhiyun }
1389*4882a593Smuzhiyun
1390*4882a593Smuzhiyun /* Sanity check - ensure at least 1 port is INITIATOR capable
1391*4882a593Smuzhiyun */
1392*4882a593Smuzhiyun ioc_cap = 0;
1393*4882a593Smuzhiyun for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
1394*4882a593Smuzhiyun if (ioc->pfacts[ii].ProtocolFlags &
1395*4882a593Smuzhiyun MPI_PORTFACTS_PROTOCOL_INITIATOR)
1396*4882a593Smuzhiyun ioc_cap ++;
1397*4882a593Smuzhiyun }
1398*4882a593Smuzhiyun
1399*4882a593Smuzhiyun if (!ioc_cap) {
1400*4882a593Smuzhiyun printk(MYIOC_s_WARN_FMT
1401*4882a593Smuzhiyun "Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",
1402*4882a593Smuzhiyun ioc->name, ioc);
1403*4882a593Smuzhiyun return 0;
1404*4882a593Smuzhiyun }
1405*4882a593Smuzhiyun
1406*4882a593Smuzhiyun sh = scsi_host_alloc(&mptspi_driver_template, sizeof(MPT_SCSI_HOST));
1407*4882a593Smuzhiyun
1408*4882a593Smuzhiyun if (!sh) {
1409*4882a593Smuzhiyun printk(MYIOC_s_WARN_FMT
1410*4882a593Smuzhiyun "Unable to register controller with SCSI subsystem\n",
1411*4882a593Smuzhiyun ioc->name);
1412*4882a593Smuzhiyun error = -1;
1413*4882a593Smuzhiyun goto out_mptspi_probe;
1414*4882a593Smuzhiyun }
1415*4882a593Smuzhiyun
1416*4882a593Smuzhiyun /* VMWare emulation doesn't properly implement WRITE_SAME
1417*4882a593Smuzhiyun */
1418*4882a593Smuzhiyun if (pdev->subsystem_vendor == 0x15AD)
1419*4882a593Smuzhiyun sh->no_write_same = 1;
1420*4882a593Smuzhiyun
1421*4882a593Smuzhiyun spin_lock_irqsave(&ioc->FreeQlock, flags);
1422*4882a593Smuzhiyun
1423*4882a593Smuzhiyun /* Attach the SCSI Host to the IOC structure
1424*4882a593Smuzhiyun */
1425*4882a593Smuzhiyun ioc->sh = sh;
1426*4882a593Smuzhiyun
1427*4882a593Smuzhiyun sh->io_port = 0;
1428*4882a593Smuzhiyun sh->n_io_port = 0;
1429*4882a593Smuzhiyun sh->irq = 0;
1430*4882a593Smuzhiyun
1431*4882a593Smuzhiyun /* set 16 byte cdb's */
1432*4882a593Smuzhiyun sh->max_cmd_len = 16;
1433*4882a593Smuzhiyun
1434*4882a593Smuzhiyun /* Yikes! This is important!
1435*4882a593Smuzhiyun * Otherwise, by default, linux
1436*4882a593Smuzhiyun * only scans target IDs 0-7!
1437*4882a593Smuzhiyun * pfactsN->MaxDevices unreliable
1438*4882a593Smuzhiyun * (not supported in early
1439*4882a593Smuzhiyun * versions of the FW).
1440*4882a593Smuzhiyun * max_id = 1 + actual max id,
1441*4882a593Smuzhiyun * max_lun = 1 + actual last lun,
1442*4882a593Smuzhiyun * see hosts.h :o(
1443*4882a593Smuzhiyun */
1444*4882a593Smuzhiyun sh->max_id = ioc->devices_per_bus;
1445*4882a593Smuzhiyun
1446*4882a593Smuzhiyun sh->max_lun = MPT_LAST_LUN + 1;
1447*4882a593Smuzhiyun /*
1448*4882a593Smuzhiyun * If RAID Firmware Detected, setup virtual channel
1449*4882a593Smuzhiyun */
1450*4882a593Smuzhiyun if (ioc->ir_firmware)
1451*4882a593Smuzhiyun sh->max_channel = 1;
1452*4882a593Smuzhiyun else
1453*4882a593Smuzhiyun sh->max_channel = 0;
1454*4882a593Smuzhiyun sh->this_id = ioc->pfacts[0].PortSCSIID;
1455*4882a593Smuzhiyun
1456*4882a593Smuzhiyun /* Required entry.
1457*4882a593Smuzhiyun */
1458*4882a593Smuzhiyun sh->unique_id = ioc->id;
1459*4882a593Smuzhiyun
1460*4882a593Smuzhiyun /* Verify that we won't exceed the maximum
1461*4882a593Smuzhiyun * number of chain buffers
1462*4882a593Smuzhiyun * We can optimize: ZZ = req_sz/sizeof(SGE)
1463*4882a593Smuzhiyun * For 32bit SGE's:
1464*4882a593Smuzhiyun * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
1465*4882a593Smuzhiyun * + (req_sz - 64)/sizeof(SGE)
1466*4882a593Smuzhiyun * A slightly different algorithm is required for
1467*4882a593Smuzhiyun * 64bit SGEs.
1468*4882a593Smuzhiyun */
1469*4882a593Smuzhiyun scale = ioc->req_sz/ioc->SGE_size;
1470*4882a593Smuzhiyun if (ioc->sg_addr_size == sizeof(u64)) {
1471*4882a593Smuzhiyun numSGE = (scale - 1) *
1472*4882a593Smuzhiyun (ioc->facts.MaxChainDepth-1) + scale +
1473*4882a593Smuzhiyun (ioc->req_sz - 60) / ioc->SGE_size;
1474*4882a593Smuzhiyun } else {
1475*4882a593Smuzhiyun numSGE = 1 + (scale - 1) *
1476*4882a593Smuzhiyun (ioc->facts.MaxChainDepth-1) + scale +
1477*4882a593Smuzhiyun (ioc->req_sz - 64) / ioc->SGE_size;
1478*4882a593Smuzhiyun }
1479*4882a593Smuzhiyun
1480*4882a593Smuzhiyun if (numSGE < sh->sg_tablesize) {
1481*4882a593Smuzhiyun /* Reset this value */
1482*4882a593Smuzhiyun dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1483*4882a593Smuzhiyun "Resetting sg_tablesize to %d from %d\n",
1484*4882a593Smuzhiyun ioc->name, numSGE, sh->sg_tablesize));
1485*4882a593Smuzhiyun sh->sg_tablesize = numSGE;
1486*4882a593Smuzhiyun }
1487*4882a593Smuzhiyun
1488*4882a593Smuzhiyun spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1489*4882a593Smuzhiyun
1490*4882a593Smuzhiyun hd = shost_priv(sh);
1491*4882a593Smuzhiyun hd->ioc = ioc;
1492*4882a593Smuzhiyun
1493*4882a593Smuzhiyun /* SCSI needs scsi_cmnd lookup table!
1494*4882a593Smuzhiyun * (with size equal to req_depth*PtrSz!)
1495*4882a593Smuzhiyun */
1496*4882a593Smuzhiyun ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
1497*4882a593Smuzhiyun if (!ioc->ScsiLookup) {
1498*4882a593Smuzhiyun error = -ENOMEM;
1499*4882a593Smuzhiyun goto out_mptspi_probe;
1500*4882a593Smuzhiyun }
1501*4882a593Smuzhiyun spin_lock_init(&ioc->scsi_lookup_lock);
1502*4882a593Smuzhiyun
1503*4882a593Smuzhiyun dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
1504*4882a593Smuzhiyun ioc->name, ioc->ScsiLookup));
1505*4882a593Smuzhiyun
1506*4882a593Smuzhiyun ioc->spi_data.Saf_Te = mpt_saf_te;
1507*4882a593Smuzhiyun ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1508*4882a593Smuzhiyun "saf_te %x\n",
1509*4882a593Smuzhiyun ioc->name,
1510*4882a593Smuzhiyun mpt_saf_te));
1511*4882a593Smuzhiyun ioc->spi_data.noQas = 0;
1512*4882a593Smuzhiyun
1513*4882a593Smuzhiyun hd->last_queue_full = 0;
1514*4882a593Smuzhiyun hd->spi_pending = 0;
1515*4882a593Smuzhiyun
1516*4882a593Smuzhiyun /* Some versions of the firmware don't support page 0; without
1517*4882a593Smuzhiyun * that we can't get the parameters */
1518*4882a593Smuzhiyun if (ioc->spi_data.sdp0length != 0)
1519*4882a593Smuzhiyun sh->transportt = mptspi_transport_template;
1520*4882a593Smuzhiyun
1521*4882a593Smuzhiyun error = scsi_add_host (sh, &ioc->pcidev->dev);
1522*4882a593Smuzhiyun if(error) {
1523*4882a593Smuzhiyun dprintk(ioc, printk(MYIOC_s_ERR_FMT
1524*4882a593Smuzhiyun "scsi_add_host failed\n", ioc->name));
1525*4882a593Smuzhiyun goto out_mptspi_probe;
1526*4882a593Smuzhiyun }
1527*4882a593Smuzhiyun
1528*4882a593Smuzhiyun /*
1529*4882a593Smuzhiyun * issue internal bus reset
1530*4882a593Smuzhiyun */
1531*4882a593Smuzhiyun if (ioc->spi_data.bus_reset)
1532*4882a593Smuzhiyun mptscsih_IssueTaskMgmt(hd,
1533*4882a593Smuzhiyun MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
1534*4882a593Smuzhiyun 0, 0, 0, 0, 5);
1535*4882a593Smuzhiyun
1536*4882a593Smuzhiyun scsi_scan_host(sh);
1537*4882a593Smuzhiyun return 0;
1538*4882a593Smuzhiyun
1539*4882a593Smuzhiyun out_mptspi_probe:
1540*4882a593Smuzhiyun
1541*4882a593Smuzhiyun mptscsih_remove(pdev);
1542*4882a593Smuzhiyun return error;
1543*4882a593Smuzhiyun }
1544*4882a593Smuzhiyun
mptspi_remove(struct pci_dev * pdev)1545*4882a593Smuzhiyun static void mptspi_remove(struct pci_dev *pdev)
1546*4882a593Smuzhiyun {
1547*4882a593Smuzhiyun MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1548*4882a593Smuzhiyun
1549*4882a593Smuzhiyun scsi_remove_host(ioc->sh);
1550*4882a593Smuzhiyun mptscsih_remove(pdev);
1551*4882a593Smuzhiyun }
1552*4882a593Smuzhiyun
1553*4882a593Smuzhiyun static struct pci_driver mptspi_driver = {
1554*4882a593Smuzhiyun .name = "mptspi",
1555*4882a593Smuzhiyun .id_table = mptspi_pci_table,
1556*4882a593Smuzhiyun .probe = mptspi_probe,
1557*4882a593Smuzhiyun .remove = mptspi_remove,
1558*4882a593Smuzhiyun .shutdown = mptscsih_shutdown,
1559*4882a593Smuzhiyun #ifdef CONFIG_PM
1560*4882a593Smuzhiyun .suspend = mptscsih_suspend,
1561*4882a593Smuzhiyun .resume = mptspi_resume,
1562*4882a593Smuzhiyun #endif
1563*4882a593Smuzhiyun };
1564*4882a593Smuzhiyun
1565*4882a593Smuzhiyun /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1566*4882a593Smuzhiyun /**
1567*4882a593Smuzhiyun * mptspi_init - Register MPT adapter(s) as SCSI host(s) with SCSI mid-layer.
1568*4882a593Smuzhiyun *
1569*4882a593Smuzhiyun * Returns 0 for success, non-zero for failure.
1570*4882a593Smuzhiyun */
1571*4882a593Smuzhiyun static int __init
mptspi_init(void)1572*4882a593Smuzhiyun mptspi_init(void)
1573*4882a593Smuzhiyun {
1574*4882a593Smuzhiyun int error;
1575*4882a593Smuzhiyun
1576*4882a593Smuzhiyun show_mptmod_ver(my_NAME, my_VERSION);
1577*4882a593Smuzhiyun
1578*4882a593Smuzhiyun mptspi_transport_template = spi_attach_transport(&mptspi_transport_functions);
1579*4882a593Smuzhiyun if (!mptspi_transport_template)
1580*4882a593Smuzhiyun return -ENODEV;
1581*4882a593Smuzhiyun
1582*4882a593Smuzhiyun mptspiDoneCtx = mpt_register(mptscsih_io_done, MPTSPI_DRIVER,
1583*4882a593Smuzhiyun "mptscsih_io_done");
1584*4882a593Smuzhiyun mptspiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSPI_DRIVER,
1585*4882a593Smuzhiyun "mptscsih_taskmgmt_complete");
1586*4882a593Smuzhiyun mptspiInternalCtx = mpt_register(mptscsih_scandv_complete,
1587*4882a593Smuzhiyun MPTSPI_DRIVER, "mptscsih_scandv_complete");
1588*4882a593Smuzhiyun
1589*4882a593Smuzhiyun mpt_event_register(mptspiDoneCtx, mptspi_event_process);
1590*4882a593Smuzhiyun mpt_reset_register(mptspiDoneCtx, mptspi_ioc_reset);
1591*4882a593Smuzhiyun
1592*4882a593Smuzhiyun error = pci_register_driver(&mptspi_driver);
1593*4882a593Smuzhiyun if (error)
1594*4882a593Smuzhiyun spi_release_transport(mptspi_transport_template);
1595*4882a593Smuzhiyun
1596*4882a593Smuzhiyun return error;
1597*4882a593Smuzhiyun }
1598*4882a593Smuzhiyun
1599*4882a593Smuzhiyun /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1600*4882a593Smuzhiyun /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1601*4882a593Smuzhiyun /**
1602*4882a593Smuzhiyun * mptspi_exit - Unregisters MPT adapter(s)
1603*4882a593Smuzhiyun */
1604*4882a593Smuzhiyun static void __exit
mptspi_exit(void)1605*4882a593Smuzhiyun mptspi_exit(void)
1606*4882a593Smuzhiyun {
1607*4882a593Smuzhiyun pci_unregister_driver(&mptspi_driver);
1608*4882a593Smuzhiyun
1609*4882a593Smuzhiyun mpt_reset_deregister(mptspiDoneCtx);
1610*4882a593Smuzhiyun mpt_event_deregister(mptspiDoneCtx);
1611*4882a593Smuzhiyun
1612*4882a593Smuzhiyun mpt_deregister(mptspiInternalCtx);
1613*4882a593Smuzhiyun mpt_deregister(mptspiTaskCtx);
1614*4882a593Smuzhiyun mpt_deregister(mptspiDoneCtx);
1615*4882a593Smuzhiyun spi_release_transport(mptspi_transport_template);
1616*4882a593Smuzhiyun }
1617*4882a593Smuzhiyun
1618*4882a593Smuzhiyun module_init(mptspi_init);
1619*4882a593Smuzhiyun module_exit(mptspi_exit);
1620