blob: 4896d7cc681acb97e87e3a4aadd65e7e6bcf010e [file] [log] [blame]
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001/*
2 * linux/drivers/message/fusion/mptspi.c
3 * For use with LSI Logic PCI chip/adapter(s)
4 * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
5 *
Eric Moore9f4203b2007-01-04 20:47:47 -07006 * Copyright (c) 1999-2007 LSI Logic Corporation
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04007 * (mailto:mpt_linux_developer@lsil.com)
8 *
9 */
10/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11/*
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; version 2 of the License.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 NO WARRANTY
22 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
23 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
24 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
25 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
26 solely responsible for determining the appropriateness of using and
27 distributing the Program and assumes all risks associated with its
28 exercise of rights under this Agreement, including but not limited to
29 the risks and costs of program errors, damage to or loss of data,
30 programs or equipment, and unavailability or interruption of operations.
31
32 DISCLAIMER OF LIABILITY
33 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
34 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
36 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
37 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
38 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
39 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
40
41 You should have received a copy of the GNU General Public License
42 along with this program; if not, write to the Free Software
43 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
44*/
45/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
46
47#include "linux_compat.h" /* linux-2.6 tweaks */
48#include <linux/module.h>
49#include <linux/kernel.h>
50#include <linux/init.h>
51#include <linux/errno.h>
52#include <linux/kdev_t.h>
53#include <linux/blkdev.h>
54#include <linux/delay.h> /* for mdelay */
55#include <linux/interrupt.h> /* needed for in_interrupt() proto */
56#include <linux/reboot.h> /* notifier code */
57#include <linux/sched.h>
58#include <linux/workqueue.h>
James Bottomleyc92f2222006-03-01 09:02:49 -060059#include <linux/raid_class.h>
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -040060
61#include <scsi/scsi.h>
62#include <scsi/scsi_cmnd.h>
63#include <scsi/scsi_device.h>
64#include <scsi/scsi_host.h>
65#include <scsi/scsi_tcq.h>
James Bottomleyc92f2222006-03-01 09:02:49 -060066#include <scsi/scsi_transport.h>
67#include <scsi/scsi_transport_spi.h>
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -040068
69#include "mptbase.h"
70#include "mptscsih.h"
71
72/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
73#define my_NAME "Fusion MPT SPI Host driver"
74#define my_VERSION MPT_LINUX_VERSION_COMMON
75#define MYNAM "mptspi"
76
77MODULE_AUTHOR(MODULEAUTHOR);
78MODULE_DESCRIPTION(my_NAME);
79MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070080MODULE_VERSION(my_VERSION);
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -040081
82/* Command line args */
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -040083static int mpt_saf_te = MPTSCSIH_SAF_TE;
84module_param(mpt_saf_te, int, 0);
85MODULE_PARM_DESC(mpt_saf_te, " Force enabling SEP Processor: enable=1 (default=MPTSCSIH_SAF_TE=0)");
86
James Bottomleyc92f2222006-03-01 09:02:49 -060087static void mptspi_write_offset(struct scsi_target *, int);
88static void mptspi_write_width(struct scsi_target *, int);
89static int mptspi_write_spi_device_pg1(struct scsi_target *,
90 struct _CONFIG_PAGE_SCSI_DEVICE_1 *);
91
92static struct scsi_transport_template *mptspi_transport_template = NULL;
93
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -040094static int mptspiDoneCtx = -1;
95static int mptspiTaskCtx = -1;
96static int mptspiInternalCtx = -1; /* Used only for internal commands */
97
Eric Moore5a9c47b2007-01-29 09:43:17 -070098/**
99 * mptspi_setTargetNegoParms - Update the target negotiation
100 * parameters based on the the Inquiry data, adapter capabilities,
101 * and NVRAM settings
102 *
103 * @hd: Pointer to a SCSI Host Structure
104 * @vtarget: per target private data
105 * @sdev: SCSI device
106 *
107 **/
108static void
109mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
110 struct scsi_device *sdev)
111{
112 SpiCfgData *pspi_data = &hd->ioc->spi_data;
113 int id = (int) target->id;
114 int nvram;
115 u8 width = MPT_NARROW;
116 u8 factor = MPT_ASYNC;
117 u8 offset = 0;
118 u8 nfactor;
119 u8 noQas = 1;
120
121 target->negoFlags = pspi_data->noQas;
122
123 if (sdev->scsi_level < SCSI_2) {
124 width = 0;
125 factor = MPT_ULTRA2;
126 offset = pspi_data->maxSyncOffset;
127 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
128 } else {
129 if (scsi_device_wide(sdev))
130 width = 1;
131
132 if (scsi_device_sync(sdev)) {
133 factor = pspi_data->minSyncFactor;
134 if (!scsi_device_dt(sdev))
135 factor = MPT_ULTRA2;
136 else {
137 if (!scsi_device_ius(sdev) &&
138 !scsi_device_qas(sdev))
139 factor = MPT_ULTRA160;
140 else {
141 factor = MPT_ULTRA320;
142 if (scsi_device_qas(sdev)) {
143 ddvprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", scsi_device_qas(sdev), id));
144 noQas = 0;
145 }
146 if (sdev->type == TYPE_TAPE &&
147 scsi_device_ius(sdev))
148 target->negoFlags |= MPT_TAPE_NEGO_IDP;
149 }
150 }
151 offset = pspi_data->maxSyncOffset;
152
153 /* If RAID, never disable QAS
154 * else if non RAID, do not disable
155 * QAS if bit 1 is set
156 * bit 1 QAS support, non-raid only
157 * bit 0 IU support
158 */
159 if (target->raidVolume == 1)
160 noQas = 0;
161 } else {
162 factor = MPT_ASYNC;
163 offset = 0;
164 }
165 }
166
167 if (!sdev->tagged_supported)
168 target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
169
170 /* Update tflags based on NVRAM settings. (SCSI only)
171 */
172 if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
173 nvram = pspi_data->nvram[id];
174 nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
175
176 if (width)
177 width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
178
179 if (offset > 0) {
180 /* Ensure factor is set to the
181 * maximum of: adapter, nvram, inquiry
182 */
183 if (nfactor) {
184 if (nfactor < pspi_data->minSyncFactor )
185 nfactor = pspi_data->minSyncFactor;
186
187 factor = max(factor, nfactor);
188 if (factor == MPT_ASYNC)
189 offset = 0;
190 } else {
191 offset = 0;
192 factor = MPT_ASYNC;
193 }
194 } else {
195 factor = MPT_ASYNC;
196 }
197 }
198
199 /* Make sure data is consistent
200 */
201 if ((!width) && (factor < MPT_ULTRA2))
202 factor = MPT_ULTRA2;
203
204 /* Save the data to the target structure.
205 */
206 target->minSyncFactor = factor;
207 target->maxOffset = offset;
208 target->maxWidth = width;
209
210 target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
211
212 /* Disable unused features.
213 */
214 if (!width)
215 target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
216
217 if (!offset)
218 target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
219
220 if ( factor > MPT_ULTRA320 )
221 noQas = 0;
222
223 if (noQas && (pspi_data->noQas == 0)) {
224 pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS;
225 target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
226
227 /* Disable QAS in a mixed configuration case
228 */
229
230 ddvprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
231 }
232}
233
234/**
235 * mptspi_writeIOCPage4 - write IOC Page 4
236 * @hd: Pointer to a SCSI Host Structure
237 * @channel:
238 * @id: write IOC Page4 for this ID & Bus
239 *
240 * Return: -EAGAIN if unable to obtain a Message Frame
241 * or 0 if success.
242 *
243 * Remark: We do not wait for a return, write pages sequentially.
244 **/
245static int
246mptspi_writeIOCPage4(MPT_SCSI_HOST *hd, u8 channel , u8 id)
247{
248 MPT_ADAPTER *ioc = hd->ioc;
249 Config_t *pReq;
250 IOCPage4_t *IOCPage4Ptr;
251 MPT_FRAME_HDR *mf;
252 dma_addr_t dataDma;
253 u16 req_idx;
254 u32 frameOffset;
255 u32 flagsLength;
256 int ii;
257
258 /* Get a MF for this command.
259 */
260 if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
261 dfailprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
262 ioc->name));
263 return -EAGAIN;
264 }
265
266 /* Set the request and the data pointers.
267 * Place data at end of MF.
268 */
269 pReq = (Config_t *)mf;
270
271 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
272 frameOffset = ioc->req_sz - sizeof(IOCPage4_t);
273
274 /* Complete the request frame (same for all requests).
275 */
276 pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
277 pReq->Reserved = 0;
278 pReq->ChainOffset = 0;
279 pReq->Function = MPI_FUNCTION_CONFIG;
280 pReq->ExtPageLength = 0;
281 pReq->ExtPageType = 0;
282 pReq->MsgFlags = 0;
283 for (ii=0; ii < 8; ii++) {
284 pReq->Reserved2[ii] = 0;
285 }
286
287 IOCPage4Ptr = ioc->spi_data.pIocPg4;
288 dataDma = ioc->spi_data.IocPg4_dma;
289 ii = IOCPage4Ptr->ActiveSEP++;
290 IOCPage4Ptr->SEP[ii].SEPTargetID = id;
291 IOCPage4Ptr->SEP[ii].SEPBus = channel;
292 pReq->Header = IOCPage4Ptr->Header;
293 pReq->PageAddress = cpu_to_le32(id | (channel << 8 ));
294
295 /* Add a SGE to the config request.
296 */
297 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
298 (IOCPage4Ptr->Header.PageLength + ii) * 4;
299
300 mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
301
302 ddvprintk((MYIOC_s_INFO_FMT
303 "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
304 ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel));
305
306 mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
307
308 return 0;
309}
310
311/**
312 * mptspi_initTarget - Target, LUN alloc/free functionality.
313 * @hd: Pointer to MPT_SCSI_HOST structure
314 * @vtarget: per target private data
315 * @sdev: SCSI device
316 *
317 * NOTE: It's only SAFE to call this routine if data points to
318 * sane & valid STANDARD INQUIRY data!
319 *
320 * Allocate and initialize memory for this target.
321 * Save inquiry data.
322 *
323 **/
324static void
325mptspi_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget,
326 struct scsi_device *sdev)
327{
328
329 /* Is LUN supported? If so, upper 2 bits will be 0
330 * in first byte of inquiry data.
331 */
332 if (sdev->inq_periph_qual != 0)
333 return;
334
335 if (vtarget == NULL)
336 return;
337
338 vtarget->type = sdev->type;
339
340 if ((sdev->type == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) {
341 /* Treat all Processors as SAF-TE if
342 * command line option is set */
343 vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
344 mptspi_writeIOCPage4(hd, vtarget->channel, vtarget->id);
345 }else if ((sdev->type == TYPE_PROCESSOR) &&
346 !(vtarget->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) {
347 if (sdev->inquiry_len > 49 ) {
348 if (sdev->inquiry[44] == 'S' &&
349 sdev->inquiry[45] == 'A' &&
350 sdev->inquiry[46] == 'F' &&
351 sdev->inquiry[47] == '-' &&
352 sdev->inquiry[48] == 'T' &&
353 sdev->inquiry[49] == 'E' ) {
354 vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
355 mptspi_writeIOCPage4(hd, vtarget->channel, vtarget->id);
356 }
357 }
358 }
359 mptspi_setTargetNegoParms(hd, vtarget, sdev);
360}
Eric Moore793955f2007-01-29 09:42:20 -0700361
362/**
363 * mptspi_is_raid - Determines whether target is belonging to volume
364 * @hd: Pointer to a SCSI HOST structure
365 * @id: target device id
366 *
367 * Return:
368 * non-zero = true
369 * zero = false
370 *
371 */
372static int
373mptspi_is_raid(struct _MPT_SCSI_HOST *hd, u32 id)
374{
375 int i, rc = 0;
376
377 if (!hd->ioc->raid_data.pIocPg2)
378 goto out;
379
380 if (!hd->ioc->raid_data.pIocPg2->NumActiveVolumes)
381 goto out;
382 for (i=0; i < hd->ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
383 if (hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) {
384 rc = 1;
385 goto out;
386 }
387 }
388
389 out:
390 return rc;
391}
392
James Bottomleyc92f2222006-03-01 09:02:49 -0600393static int mptspi_target_alloc(struct scsi_target *starget)
394{
395 struct Scsi_Host *shost = dev_to_shost(&starget->dev);
396 struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata;
Eric Moore793955f2007-01-29 09:42:20 -0700397 VirtTarget *vtarget;
James Bottomleyc92f2222006-03-01 09:02:49 -0600398
399 if (hd == NULL)
400 return -ENODEV;
401
Eric Moore793955f2007-01-29 09:42:20 -0700402 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
403 if (!vtarget)
404 return -ENOMEM;
James Bottomleyc92f2222006-03-01 09:02:49 -0600405
Eric Moore793955f2007-01-29 09:42:20 -0700406 vtarget->ioc_id = hd->ioc->id;
407 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
408 vtarget->id = (u8)starget->id;
409 vtarget->channel = (u8)starget->channel;
410 vtarget->starget = starget;
411 starget->hostdata = vtarget;
412
413 if (starget->channel == 1) {
414 if (mptscsih_is_phys_disk(hd->ioc, 0, starget->id) == 0)
415 return 0;
416 vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
417 /* The real channel for this device is zero */
418 vtarget->channel = 0;
419 /* The actual physdisknum (for RAID passthrough) */
420 vtarget->id = mptscsih_raid_id_to_num(hd->ioc, 0,
421 starget->id);
422 }
423
424 if (starget->channel == 0 &&
425 mptspi_is_raid(hd, starget->id)) {
426 vtarget->raidVolume = 1;
427 ddvprintk((KERN_INFO
428 "RAID Volume @ channel=%d id=%d\n", starget->channel,
429 starget->id));
430 }
James Bottomleyc92f2222006-03-01 09:02:49 -0600431
432 if (hd->ioc->spi_data.nvram &&
433 hd->ioc->spi_data.nvram[starget->id] != MPT_HOST_NVRAM_INVALID) {
434 u32 nvram = hd->ioc->spi_data.nvram[starget->id];
435 spi_min_period(starget) = (nvram & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
436 spi_max_width(starget) = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
437 } else {
438 spi_min_period(starget) = hd->ioc->spi_data.minSyncFactor;
439 spi_max_width(starget) = hd->ioc->spi_data.maxBusWidth;
440 }
441 spi_max_offset(starget) = hd->ioc->spi_data.maxSyncOffset;
442
443 spi_offset(starget) = 0;
444 mptspi_write_width(starget, 0);
445
446 return 0;
447}
448
Eric Moore793955f2007-01-29 09:42:20 -0700449void
450mptspi_target_destroy(struct scsi_target *starget)
451{
452 if (starget->hostdata)
453 kfree(starget->hostdata);
454 starget->hostdata = NULL;
455}
456
James Bottomleyc92f2222006-03-01 09:02:49 -0600457static int mptspi_read_spi_device_pg0(struct scsi_target *starget,
458 struct _CONFIG_PAGE_SCSI_DEVICE_0 *pass_pg0)
459{
460 struct Scsi_Host *shost = dev_to_shost(&starget->dev);
461 struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata;
462 struct _MPT_ADAPTER *ioc = hd->ioc;
463 struct _CONFIG_PAGE_SCSI_DEVICE_0 *pg0;
464 dma_addr_t pg0_dma;
465 int size;
466 struct _x_config_parms cfg;
467 struct _CONFIG_PAGE_HEADER hdr;
468 int err = -EBUSY;
469
470 /* No SPI parameters for RAID devices */
471 if (starget->channel == 0 &&
Eric Moore793955f2007-01-29 09:42:20 -0700472 mptspi_is_raid(hd, starget->id))
James Bottomleyc92f2222006-03-01 09:02:49 -0600473 return -1;
474
475 size = ioc->spi_data.sdp0length * 4;
476 /*
477 if (ioc->spi_data.sdp0length & 1)
478 size += size + 4;
479 size += 2048;
480 */
481
482 pg0 = dma_alloc_coherent(&ioc->pcidev->dev, size, &pg0_dma, GFP_KERNEL);
483 if (pg0 == NULL) {
484 starget_printk(KERN_ERR, starget, "dma_alloc_coherent for parameters failed\n");
485 return -EINVAL;
486 }
487
488 memset(&hdr, 0, sizeof(hdr));
489
490 hdr.PageVersion = ioc->spi_data.sdp0version;
491 hdr.PageLength = ioc->spi_data.sdp0length;
492 hdr.PageNumber = 0;
493 hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
494
495 memset(&cfg, 0, sizeof(cfg));
496
497 cfg.cfghdr.hdr = &hdr;
498 cfg.physAddr = pg0_dma;
499 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
500 cfg.dir = 0;
501 cfg.pageAddr = starget->id;
502
503 if (mpt_config(ioc, &cfg)) {
504 starget_printk(KERN_ERR, starget, "mpt_config failed\n");
505 goto out_free;
506 }
507 err = 0;
508 memcpy(pass_pg0, pg0, size);
509
510 out_free:
511 dma_free_coherent(&ioc->pcidev->dev, size, pg0, pg0_dma);
512 return err;
513}
514
515static u32 mptspi_getRP(struct scsi_target *starget)
516{
517 u32 nego = 0;
518
519 nego |= spi_iu(starget) ? MPI_SCSIDEVPAGE1_RP_IU : 0;
520 nego |= spi_dt(starget) ? MPI_SCSIDEVPAGE1_RP_DT : 0;
521 nego |= spi_qas(starget) ? MPI_SCSIDEVPAGE1_RP_QAS : 0;
522 nego |= spi_hold_mcs(starget) ? MPI_SCSIDEVPAGE1_RP_HOLD_MCS : 0;
523 nego |= spi_wr_flow(starget) ? MPI_SCSIDEVPAGE1_RP_WR_FLOW : 0;
524 nego |= spi_rd_strm(starget) ? MPI_SCSIDEVPAGE1_RP_RD_STRM : 0;
525 nego |= spi_rti(starget) ? MPI_SCSIDEVPAGE1_RP_RTI : 0;
526 nego |= spi_pcomp_en(starget) ? MPI_SCSIDEVPAGE1_RP_PCOMP_EN : 0;
527
528 nego |= (spi_period(starget) << MPI_SCSIDEVPAGE1_RP_SHIFT_MIN_SYNC_PERIOD) & MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK;
529 nego |= (spi_offset(starget) << MPI_SCSIDEVPAGE1_RP_SHIFT_MAX_SYNC_OFFSET) & MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK;
530 nego |= spi_width(starget) ? MPI_SCSIDEVPAGE1_RP_WIDE : 0;
531
532 return nego;
533}
534
535static void mptspi_read_parameters(struct scsi_target *starget)
536{
537 int nego;
538 struct _CONFIG_PAGE_SCSI_DEVICE_0 pg0;
539
540 mptspi_read_spi_device_pg0(starget, &pg0);
541
542 nego = le32_to_cpu(pg0.NegotiatedParameters);
543
544 spi_iu(starget) = (nego & MPI_SCSIDEVPAGE0_NP_IU) ? 1 : 0;
545 spi_dt(starget) = (nego & MPI_SCSIDEVPAGE0_NP_DT) ? 1 : 0;
546 spi_qas(starget) = (nego & MPI_SCSIDEVPAGE0_NP_QAS) ? 1 : 0;
547 spi_wr_flow(starget) = (nego & MPI_SCSIDEVPAGE0_NP_WR_FLOW) ? 1 : 0;
548 spi_rd_strm(starget) = (nego & MPI_SCSIDEVPAGE0_NP_RD_STRM) ? 1 : 0;
549 spi_rti(starget) = (nego & MPI_SCSIDEVPAGE0_NP_RTI) ? 1 : 0;
550 spi_pcomp_en(starget) = (nego & MPI_SCSIDEVPAGE0_NP_PCOMP_EN) ? 1 : 0;
551 spi_hold_mcs(starget) = (nego & MPI_SCSIDEVPAGE0_NP_HOLD_MCS) ? 1 : 0;
552 spi_period(starget) = (nego & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> MPI_SCSIDEVPAGE0_NP_SHIFT_SYNC_PERIOD;
553 spi_offset(starget) = (nego & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) >> MPI_SCSIDEVPAGE0_NP_SHIFT_SYNC_OFFSET;
554 spi_width(starget) = (nego & MPI_SCSIDEVPAGE0_NP_WIDE) ? 1 : 0;
555}
556
557static int
Eric Moore793955f2007-01-29 09:42:20 -0700558mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id)
James Bottomleyc92f2222006-03-01 09:02:49 -0600559{
560 MpiRaidActionRequest_t *pReq;
561 MPT_FRAME_HDR *mf;
562
563 /* Get and Populate a free Frame
564 */
565 if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
566 ddvprintk((MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
567 hd->ioc->name));
568 return -EAGAIN;
569 }
570 pReq = (MpiRaidActionRequest_t *)mf;
571 if (quiesce)
572 pReq->Action = MPI_RAID_ACTION_QUIESCE_PHYS_IO;
573 else
574 pReq->Action = MPI_RAID_ACTION_ENABLE_PHYS_IO;
575 pReq->Reserved1 = 0;
576 pReq->ChainOffset = 0;
577 pReq->Function = MPI_FUNCTION_RAID_ACTION;
Eric Moore793955f2007-01-29 09:42:20 -0700578 pReq->VolumeID = id;
579 pReq->VolumeBus = channel;
James Bottomleyc92f2222006-03-01 09:02:49 -0600580 pReq->PhysDiskNum = 0;
581 pReq->MsgFlags = 0;
582 pReq->Reserved2 = 0;
583 pReq->ActionDataWord = 0; /* Reserved for this action */
584
585 mpt_add_sge((char *)&pReq->ActionDataSGE,
586 MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
587
Eric Moore793955f2007-01-29 09:42:20 -0700588 ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action=%x channel=%d id=%d\n",
589 hd->ioc->name, pReq->Action, channel, id));
James Bottomleyc92f2222006-03-01 09:02:49 -0600590
591 hd->pLocal = NULL;
592 hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */
593 hd->scandv_wait_done = 0;
594
595 /* Save cmd pointer, for resource free if timeout or
596 * FW reload occurs
597 */
598 hd->cmdPtr = mf;
599
600 add_timer(&hd->timer);
601 mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
602 wait_event(hd->scandv_waitq, hd->scandv_wait_done);
603
604 if ((hd->pLocal == NULL) || (hd->pLocal->completion != 0))
605 return -1;
606
607 return 0;
608}
609
610static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
611 struct scsi_device *sdev)
612{
613 VirtTarget *vtarget = scsi_target(sdev)->hostdata;
614
615 /* no DV on RAID devices */
616 if (sdev->channel == 0 &&
Eric Moore793955f2007-01-29 09:42:20 -0700617 mptspi_is_raid(hd, sdev->id))
James Bottomleyc92f2222006-03-01 09:02:49 -0600618 return;
619
620 /* If this is a piece of a RAID, then quiesce first */
621 if (sdev->channel == 1 &&
Eric Moore793955f2007-01-29 09:42:20 -0700622 mptscsih_quiesce_raid(hd, 1, vtarget->channel, vtarget->id) < 0) {
James Bottomleyc92f2222006-03-01 09:02:49 -0600623 starget_printk(KERN_ERR, scsi_target(sdev),
624 "Integrated RAID quiesce failed\n");
625 return;
626 }
627
628 spi_dv_device(sdev);
629
630 if (sdev->channel == 1 &&
Eric Moore793955f2007-01-29 09:42:20 -0700631 mptscsih_quiesce_raid(hd, 0, vtarget->channel, vtarget->id) < 0)
James Bottomleyc92f2222006-03-01 09:02:49 -0600632 starget_printk(KERN_ERR, scsi_target(sdev),
633 "Integrated RAID resume failed\n");
634
635 mptspi_read_parameters(sdev->sdev_target);
636 spi_display_xfer_agreement(sdev->sdev_target);
637 mptspi_read_parameters(sdev->sdev_target);
638}
639
640static int mptspi_slave_alloc(struct scsi_device *sdev)
641{
James Bottomleyc92f2222006-03-01 09:02:49 -0600642 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
Eric Moore793955f2007-01-29 09:42:20 -0700643 VirtTarget *vtarget;
644 VirtDevice *vdev;
645 struct scsi_target *starget;
James Bottomleyc92f2222006-03-01 09:02:49 -0600646
Eric Moore793955f2007-01-29 09:42:20 -0700647 if (sdev->channel == 1 &&
648 mptscsih_is_phys_disk(hd->ioc, 0, sdev->id) == 0)
649 return -ENXIO;
James Bottomleyc92f2222006-03-01 09:02:49 -0600650
Eric Moore793955f2007-01-29 09:42:20 -0700651 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
652 if (!vdev) {
653 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
654 hd->ioc->name, sizeof(VirtDevice));
655 return -ENOMEM;
James Bottomleyc92f2222006-03-01 09:02:49 -0600656 }
657
Eric Moore793955f2007-01-29 09:42:20 -0700658 vdev->lun = sdev->lun;
659 sdev->hostdata = vdev;
James Bottomleyc92f2222006-03-01 09:02:49 -0600660
Eric Moore793955f2007-01-29 09:42:20 -0700661 starget = scsi_target(sdev);
662 vtarget = starget->hostdata;
663 vdev->vtarget = vtarget;
664 vtarget->num_luns++;
James Bottomleyc92f2222006-03-01 09:02:49 -0600665
Eric Moore793955f2007-01-29 09:42:20 -0700666 if (sdev->channel == 1)
James Bottomleyc92f2222006-03-01 09:02:49 -0600667 sdev->no_uld_attach = 1;
James Bottomleyc92f2222006-03-01 09:02:49 -0600668
669 return 0;
670}
671
672static int mptspi_slave_configure(struct scsi_device *sdev)
673{
James Bottomleyc92f2222006-03-01 09:02:49 -0600674 struct _MPT_SCSI_HOST *hd =
675 (struct _MPT_SCSI_HOST *)sdev->host->hostdata;
Eric Moore5a9c47b2007-01-29 09:43:17 -0700676 VirtTarget *vtarget = scsi_target(sdev)->hostdata;
677 int ret = mptscsih_slave_configure(sdev);
James Bottomleyc92f2222006-03-01 09:02:49 -0600678
679 if (ret)
680 return ret;
681
Eric Moore5a9c47b2007-01-29 09:43:17 -0700682 mptspi_initTarget(hd, vtarget, sdev);
683
James Bottomleyc92f2222006-03-01 09:02:49 -0600684 if ((sdev->channel == 1 ||
Eric Moore793955f2007-01-29 09:42:20 -0700685 !(mptspi_is_raid(hd, sdev->id))) &&
James Bottomleyc92f2222006-03-01 09:02:49 -0600686 !spi_initial_dv(sdev->sdev_target))
687 mptspi_dv_device(hd, sdev);
688
689 return 0;
690}
691
Eric Moore793955f2007-01-29 09:42:20 -0700692static int
693mptspi_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
694{
695 struct _MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
696 VirtDevice *vdev = SCpnt->device->hostdata;
697
698 if (!vdev || !vdev->vtarget) {
699 SCpnt->result = DID_NO_CONNECT << 16;
700 done(SCpnt);
701 return 0;
702 }
703
704 if (SCpnt->device->channel == 1 &&
705 mptscsih_is_phys_disk(hd->ioc, 0, SCpnt->device->id) == 0) {
706 SCpnt->result = DID_NO_CONNECT << 16;
707 done(SCpnt);
708 return 0;
709 }
710
711 return mptscsih_qcmd(SCpnt,done);
712}
713
James Bottomleyc92f2222006-03-01 09:02:49 -0600714static void mptspi_slave_destroy(struct scsi_device *sdev)
715{
716 struct scsi_target *starget = scsi_target(sdev);
717 VirtTarget *vtarget = starget->hostdata;
718 VirtDevice *vdevice = sdev->hostdata;
719
720 /* Will this be the last lun on a non-raid device? */
721 if (vtarget->num_luns == 1 && vdevice->configured_lun) {
722 struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
723
724 /* Async Narrow */
725 pg1.RequestedParameters = 0;
726 pg1.Reserved = 0;
727 pg1.Configuration = 0;
728
729 mptspi_write_spi_device_pg1(starget, &pg1);
730 }
731
732 mptscsih_slave_destroy(sdev);
733}
734
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -0400735static struct scsi_host_template mptspi_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -0700736 .module = THIS_MODULE,
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -0400737 .proc_name = "mptspi",
738 .proc_info = mptscsih_proc_info,
739 .name = "MPT SPI Host",
740 .info = mptscsih_info,
Eric Moore793955f2007-01-29 09:42:20 -0700741 .queuecommand = mptspi_qcmd,
James Bottomleyc92f2222006-03-01 09:02:49 -0600742 .target_alloc = mptspi_target_alloc,
743 .slave_alloc = mptspi_slave_alloc,
744 .slave_configure = mptspi_slave_configure,
Eric Moore793955f2007-01-29 09:42:20 -0700745 .target_destroy = mptspi_target_destroy,
James Bottomleyc92f2222006-03-01 09:02:49 -0600746 .slave_destroy = mptspi_slave_destroy,
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -0600747 .change_queue_depth = mptscsih_change_queue_depth,
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -0400748 .eh_abort_handler = mptscsih_abort,
749 .eh_device_reset_handler = mptscsih_dev_reset,
750 .eh_bus_reset_handler = mptscsih_bus_reset,
751 .eh_host_reset_handler = mptscsih_host_reset,
752 .bios_param = mptscsih_bios_param,
753 .can_queue = MPT_SCSI_CAN_QUEUE,
754 .this_id = -1,
755 .sg_tablesize = MPT_SCSI_SG_DEPTH,
756 .max_sectors = 8192,
757 .cmd_per_lun = 7,
758 .use_clustering = ENABLE_CLUSTERING,
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -0400759};
760
James Bottomleyc92f2222006-03-01 09:02:49 -0600761static int mptspi_write_spi_device_pg1(struct scsi_target *starget,
762 struct _CONFIG_PAGE_SCSI_DEVICE_1 *pass_pg1)
763{
764 struct Scsi_Host *shost = dev_to_shost(&starget->dev);
765 struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata;
766 struct _MPT_ADAPTER *ioc = hd->ioc;
767 struct _CONFIG_PAGE_SCSI_DEVICE_1 *pg1;
768 dma_addr_t pg1_dma;
769 int size;
770 struct _x_config_parms cfg;
771 struct _CONFIG_PAGE_HEADER hdr;
772 int err = -EBUSY;
773
774 /* don't allow updating nego parameters on RAID devices */
775 if (starget->channel == 0 &&
Eric Moore793955f2007-01-29 09:42:20 -0700776 mptspi_is_raid(hd, starget->id))
James Bottomleyc92f2222006-03-01 09:02:49 -0600777 return -1;
778
779 size = ioc->spi_data.sdp1length * 4;
780
781 pg1 = dma_alloc_coherent(&ioc->pcidev->dev, size, &pg1_dma, GFP_KERNEL);
782 if (pg1 == NULL) {
783 starget_printk(KERN_ERR, starget, "dma_alloc_coherent for parameters failed\n");
784 return -EINVAL;
785 }
786
787 memset(&hdr, 0, sizeof(hdr));
788
789 hdr.PageVersion = ioc->spi_data.sdp1version;
790 hdr.PageLength = ioc->spi_data.sdp1length;
791 hdr.PageNumber = 1;
792 hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
793
794 memset(&cfg, 0, sizeof(cfg));
795
796 cfg.cfghdr.hdr = &hdr;
797 cfg.physAddr = pg1_dma;
798 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
799 cfg.dir = 1;
800 cfg.pageAddr = starget->id;
801
802 memcpy(pg1, pass_pg1, size);
803
804 pg1->Header.PageVersion = hdr.PageVersion;
805 pg1->Header.PageLength = hdr.PageLength;
806 pg1->Header.PageNumber = hdr.PageNumber;
807 pg1->Header.PageType = hdr.PageType;
808
809 if (mpt_config(ioc, &cfg)) {
810 starget_printk(KERN_ERR, starget, "mpt_config failed\n");
811 goto out_free;
812 }
813 err = 0;
814
815 out_free:
816 dma_free_coherent(&ioc->pcidev->dev, size, pg1, pg1_dma);
817 return err;
818}
819
820static void mptspi_write_offset(struct scsi_target *starget, int offset)
821{
822 struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
823 u32 nego;
824
825 if (offset < 0)
826 offset = 0;
827
828 if (offset > 255)
829 offset = 255;
830
831 if (spi_offset(starget) == -1)
832 mptspi_read_parameters(starget);
833
834 spi_offset(starget) = offset;
835
836 nego = mptspi_getRP(starget);
837
838 pg1.RequestedParameters = cpu_to_le32(nego);
839 pg1.Reserved = 0;
840 pg1.Configuration = 0;
841
842 mptspi_write_spi_device_pg1(starget, &pg1);
843}
844
845static void mptspi_write_period(struct scsi_target *starget, int period)
846{
847 struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
848 u32 nego;
849
850 if (period < 8)
851 period = 8;
852
853 if (period > 255)
854 period = 255;
855
856 if (spi_period(starget) == -1)
857 mptspi_read_parameters(starget);
858
859 if (period == 8) {
860 spi_iu(starget) = 1;
861 spi_dt(starget) = 1;
862 } else if (period == 9) {
863 spi_dt(starget) = 1;
864 }
865
866 spi_period(starget) = period;
867
868 nego = mptspi_getRP(starget);
869
870 pg1.RequestedParameters = cpu_to_le32(nego);
871 pg1.Reserved = 0;
872 pg1.Configuration = 0;
873
874 mptspi_write_spi_device_pg1(starget, &pg1);
875}
876
877static void mptspi_write_dt(struct scsi_target *starget, int dt)
878{
879 struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
880 u32 nego;
881
882 if (spi_period(starget) == -1)
883 mptspi_read_parameters(starget);
884
885 if (!dt && spi_period(starget) < 10)
886 spi_period(starget) = 10;
887
888 spi_dt(starget) = dt;
889
890 nego = mptspi_getRP(starget);
891
892
893 pg1.RequestedParameters = cpu_to_le32(nego);
894 pg1.Reserved = 0;
895 pg1.Configuration = 0;
896
897 mptspi_write_spi_device_pg1(starget, &pg1);
898}
899
900static void mptspi_write_iu(struct scsi_target *starget, int iu)
901{
902 struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
903 u32 nego;
904
905 if (spi_period(starget) == -1)
906 mptspi_read_parameters(starget);
907
908 if (!iu && spi_period(starget) < 9)
909 spi_period(starget) = 9;
910
911 spi_iu(starget) = iu;
912
913 nego = mptspi_getRP(starget);
914
915 pg1.RequestedParameters = cpu_to_le32(nego);
916 pg1.Reserved = 0;
917 pg1.Configuration = 0;
918
919 mptspi_write_spi_device_pg1(starget, &pg1);
920}
921
922#define MPTSPI_SIMPLE_TRANSPORT_PARM(parm) \
923static void mptspi_write_##parm(struct scsi_target *starget, int parm)\
924{ \
925 struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; \
926 u32 nego; \
927 \
928 spi_##parm(starget) = parm; \
929 \
930 nego = mptspi_getRP(starget); \
931 \
932 pg1.RequestedParameters = cpu_to_le32(nego); \
933 pg1.Reserved = 0; \
934 pg1.Configuration = 0; \
935 \
936 mptspi_write_spi_device_pg1(starget, &pg1); \
937}
938
939MPTSPI_SIMPLE_TRANSPORT_PARM(rd_strm)
940MPTSPI_SIMPLE_TRANSPORT_PARM(wr_flow)
941MPTSPI_SIMPLE_TRANSPORT_PARM(rti)
942MPTSPI_SIMPLE_TRANSPORT_PARM(hold_mcs)
943MPTSPI_SIMPLE_TRANSPORT_PARM(pcomp_en)
944
945static void mptspi_write_qas(struct scsi_target *starget, int qas)
946{
947 struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
948 struct Scsi_Host *shost = dev_to_shost(&starget->dev);
949 struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata;
950 VirtTarget *vtarget = starget->hostdata;
951 u32 nego;
952
953 if ((vtarget->negoFlags & MPT_TARGET_NO_NEGO_QAS) ||
954 hd->ioc->spi_data.noQas)
955 spi_qas(starget) = 0;
956 else
957 spi_qas(starget) = qas;
958
959 nego = mptspi_getRP(starget);
960
961 pg1.RequestedParameters = cpu_to_le32(nego);
962 pg1.Reserved = 0;
963 pg1.Configuration = 0;
964
965 mptspi_write_spi_device_pg1(starget, &pg1);
966}
967
968static void mptspi_write_width(struct scsi_target *starget, int width)
969{
970 struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
971 u32 nego;
972
973 if (!width) {
974 spi_dt(starget) = 0;
975 if (spi_period(starget) < 10)
976 spi_period(starget) = 10;
977 }
978
979 spi_width(starget) = width;
980
981 nego = mptspi_getRP(starget);
982
983 pg1.RequestedParameters = cpu_to_le32(nego);
984 pg1.Reserved = 0;
985 pg1.Configuration = 0;
986
987 mptspi_write_spi_device_pg1(starget, &pg1);
988}
989
990struct work_queue_wrapper {
991 struct work_struct work;
992 struct _MPT_SCSI_HOST *hd;
993 int disk;
994};
995
David Howellsc4028952006-11-22 14:57:56 +0000996static void mpt_work_wrapper(struct work_struct *work)
James Bottomleyc92f2222006-03-01 09:02:49 -0600997{
David Howellsc4028952006-11-22 14:57:56 +0000998 struct work_queue_wrapper *wqw =
999 container_of(work, struct work_queue_wrapper, work);
James Bottomleyc92f2222006-03-01 09:02:49 -06001000 struct _MPT_SCSI_HOST *hd = wqw->hd;
1001 struct Scsi_Host *shost = hd->ioc->sh;
1002 struct scsi_device *sdev;
1003 int disk = wqw->disk;
1004 struct _CONFIG_PAGE_IOC_3 *pg3;
1005
1006 kfree(wqw);
1007
1008 mpt_findImVolumes(hd->ioc);
1009 pg3 = hd->ioc->raid_data.pIocPg3;
1010 if (!pg3)
1011 return;
1012
1013 shost_for_each_device(sdev,shost) {
1014 struct scsi_target *starget = scsi_target(sdev);
1015 VirtTarget *vtarget = starget->hostdata;
1016
1017 /* only want to search RAID components */
1018 if (sdev->channel != 1)
1019 continue;
1020
Eric Moore793955f2007-01-29 09:42:20 -07001021 /* The id is the raid PhysDiskNum, even if
James Bottomleyc92f2222006-03-01 09:02:49 -06001022 * starget->id is the actual target address */
Eric Moore793955f2007-01-29 09:42:20 -07001023 if(vtarget->id != disk)
James Bottomleyc92f2222006-03-01 09:02:49 -06001024 continue;
1025
1026 starget_printk(KERN_INFO, vtarget->starget,
1027 "Integrated RAID requests DV of new device\n");
1028 mptspi_dv_device(hd, sdev);
1029 }
1030 shost_printk(KERN_INFO, shost,
1031 "Integrated RAID detects new device %d\n", disk);
1032 scsi_scan_target(&hd->ioc->sh->shost_gendev, 1, disk, 0, 1);
1033}
1034
1035
1036static void mpt_dv_raid(struct _MPT_SCSI_HOST *hd, int disk)
1037{
1038 struct work_queue_wrapper *wqw = kmalloc(sizeof(*wqw), GFP_ATOMIC);
1039
1040 if (!wqw) {
1041 shost_printk(KERN_ERR, hd->ioc->sh,
1042 "Failed to act on RAID event for physical disk %d\n",
1043 disk);
1044 return;
1045 }
David Howellsc4028952006-11-22 14:57:56 +00001046 INIT_WORK(&wqw->work, mpt_work_wrapper);
James Bottomleyc92f2222006-03-01 09:02:49 -06001047 wqw->hd = hd;
1048 wqw->disk = disk;
1049
1050 schedule_work(&wqw->work);
1051}
1052
1053static int
1054mptspi_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
1055{
1056 u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
1057 struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)ioc->sh->hostdata;
1058
1059 if (hd && event == MPI_EVENT_INTEGRATED_RAID) {
1060 int reason
1061 = (le32_to_cpu(pEvReply->Data[0]) & 0x00FF0000) >> 16;
1062
1063 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
1064 int disk = (le32_to_cpu(pEvReply->Data[0]) & 0xFF000000) >> 24;
1065 mpt_dv_raid(hd, disk);
1066 }
1067 }
1068 return mptscsih_event_process(ioc, pEvReply);
1069}
1070
1071static int
1072mptspi_deny_binding(struct scsi_target *starget)
1073{
1074 struct _MPT_SCSI_HOST *hd =
1075 (struct _MPT_SCSI_HOST *)dev_to_shost(starget->dev.parent)->hostdata;
Eric Moore793955f2007-01-29 09:42:20 -07001076 return ((mptspi_is_raid(hd, starget->id)) &&
James Bottomleyc92f2222006-03-01 09:02:49 -06001077 starget->channel == 0) ? 1 : 0;
1078}
1079
1080static struct spi_function_template mptspi_transport_functions = {
1081 .get_offset = mptspi_read_parameters,
1082 .set_offset = mptspi_write_offset,
1083 .show_offset = 1,
1084 .get_period = mptspi_read_parameters,
1085 .set_period = mptspi_write_period,
1086 .show_period = 1,
1087 .get_width = mptspi_read_parameters,
1088 .set_width = mptspi_write_width,
1089 .show_width = 1,
1090 .get_iu = mptspi_read_parameters,
1091 .set_iu = mptspi_write_iu,
1092 .show_iu = 1,
1093 .get_dt = mptspi_read_parameters,
1094 .set_dt = mptspi_write_dt,
1095 .show_dt = 1,
1096 .get_qas = mptspi_read_parameters,
1097 .set_qas = mptspi_write_qas,
1098 .show_qas = 1,
1099 .get_wr_flow = mptspi_read_parameters,
1100 .set_wr_flow = mptspi_write_wr_flow,
1101 .show_wr_flow = 1,
1102 .get_rd_strm = mptspi_read_parameters,
1103 .set_rd_strm = mptspi_write_rd_strm,
1104 .show_rd_strm = 1,
1105 .get_rti = mptspi_read_parameters,
1106 .set_rti = mptspi_write_rti,
1107 .show_rti = 1,
1108 .get_pcomp_en = mptspi_read_parameters,
1109 .set_pcomp_en = mptspi_write_pcomp_en,
1110 .show_pcomp_en = 1,
1111 .get_hold_mcs = mptspi_read_parameters,
1112 .set_hold_mcs = mptspi_write_hold_mcs,
1113 .show_hold_mcs = 1,
1114 .deny_binding = mptspi_deny_binding,
1115};
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001116
1117/****************************************************************************
1118 * Supported hardware
1119 */
1120
1121static struct pci_device_id mptspi_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06001122 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1030,
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001123 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06001124 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1035,
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001125 PCI_ANY_ID, PCI_ANY_ID },
1126 {0} /* Terminating entry */
1127};
1128MODULE_DEVICE_TABLE(pci, mptspi_pci_table);
1129
Eric Moore6e1cad02006-04-25 17:38:58 -06001130
1131/*
1132 * renegotiate for a given target
1133 */
1134static void
David Howellsc4028952006-11-22 14:57:56 +00001135mptspi_dv_renegotiate_work(struct work_struct *work)
Eric Moore6e1cad02006-04-25 17:38:58 -06001136{
David Howellsc4028952006-11-22 14:57:56 +00001137 struct work_queue_wrapper *wqw =
1138 container_of(work, struct work_queue_wrapper, work);
Eric Moore6e1cad02006-04-25 17:38:58 -06001139 struct _MPT_SCSI_HOST *hd = wqw->hd;
1140 struct scsi_device *sdev;
1141
1142 kfree(wqw);
1143
1144 shost_for_each_device(sdev, hd->ioc->sh)
1145 mptspi_dv_device(hd, sdev);
1146}
1147
1148static void
1149mptspi_dv_renegotiate(struct _MPT_SCSI_HOST *hd)
1150{
1151 struct work_queue_wrapper *wqw = kmalloc(sizeof(*wqw), GFP_ATOMIC);
1152
1153 if (!wqw)
1154 return;
1155
David Howellsc4028952006-11-22 14:57:56 +00001156 INIT_WORK(&wqw->work, mptspi_dv_renegotiate_work);
Eric Moore6e1cad02006-04-25 17:38:58 -06001157 wqw->hd = hd;
1158
1159 schedule_work(&wqw->work);
1160}
1161
1162/*
1163 * spi module reset handler
1164 */
1165static int
1166mptspi_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
1167{
1168 struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)ioc->sh->hostdata;
1169 int rc;
1170
1171 rc = mptscsih_ioc_reset(ioc, reset_phase);
1172
1173 if (reset_phase == MPT_IOC_POST_RESET)
1174 mptspi_dv_renegotiate(hd);
1175
1176 return rc;
1177}
1178
Tom "spot" Callawayc29ca9d2006-06-09 17:01:48 -07001179#ifdef CONFIG_PM
Eric Moore6e1cad02006-04-25 17:38:58 -06001180/*
1181 * spi module resume handler
1182 */
1183static int
1184mptspi_resume(struct pci_dev *pdev)
1185{
1186 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1187 struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)ioc->sh->hostdata;
1188 int rc;
1189
1190 rc = mptscsih_resume(pdev);
1191 mptspi_dv_renegotiate(hd);
1192
1193 return rc;
1194}
Tom "spot" Callawayc29ca9d2006-06-09 17:01:48 -07001195#endif
Eric Moore6e1cad02006-04-25 17:38:58 -06001196
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001197/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1198/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1199/*
1200 * mptspi_probe - Installs scsi devices per bus.
1201 * @pdev: Pointer to pci_dev structure
1202 *
1203 * Returns 0 for success, non-zero for failure.
1204 *
1205 */
1206static int
1207mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
1208{
1209 struct Scsi_Host *sh;
1210 MPT_SCSI_HOST *hd;
1211 MPT_ADAPTER *ioc;
1212 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001213 int ii;
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001214 int numSGE = 0;
1215 int scale;
1216 int ioc_cap;
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001217 int error=0;
1218 int r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001219
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001220 if ((r = mpt_attach(pdev,id)) != 0)
1221 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001222
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001223 ioc = pci_get_drvdata(pdev);
Moore, Eric Dean d335cc32005-04-30 17:09:38 -05001224 ioc->DoneCtx = mptspiDoneCtx;
1225 ioc->TaskCtx = mptspiTaskCtx;
1226 ioc->InternalCtx = mptspiInternalCtx;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001227
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001228 /* Added sanity check on readiness of the MPT adapter.
1229 */
1230 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
1231 printk(MYIOC_s_WARN_FMT
1232 "Skipping because it's not operational!\n",
1233 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001234 error = -ENODEV;
1235 goto out_mptspi_probe;
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001236 }
1237
1238 if (!ioc->active) {
1239 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
1240 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001241 error = -ENODEV;
1242 goto out_mptspi_probe;
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001243 }
1244
1245 /* Sanity check - ensure at least 1 port is INITIATOR capable
1246 */
1247 ioc_cap = 0;
1248 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
1249 if (ioc->pfacts[ii].ProtocolFlags &
1250 MPI_PORTFACTS_PROTOCOL_INITIATOR)
1251 ioc_cap ++;
1252 }
1253
1254 if (!ioc_cap) {
1255 printk(MYIOC_s_WARN_FMT
1256 "Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",
1257 ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001258 return 0;
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001259 }
1260
1261 sh = scsi_host_alloc(&mptspi_driver_template, sizeof(MPT_SCSI_HOST));
1262
1263 if (!sh) {
1264 printk(MYIOC_s_WARN_FMT
1265 "Unable to register controller with SCSI subsystem\n",
1266 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001267 error = -1;
1268 goto out_mptspi_probe;
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001269 }
1270
1271 spin_lock_irqsave(&ioc->FreeQlock, flags);
1272
1273 /* Attach the SCSI Host to the IOC structure
1274 */
1275 ioc->sh = sh;
1276
1277 sh->io_port = 0;
1278 sh->n_io_port = 0;
1279 sh->irq = 0;
1280
1281 /* set 16 byte cdb's */
1282 sh->max_cmd_len = 16;
1283
1284 /* Yikes! This is important!
1285 * Otherwise, by default, linux
1286 * only scans target IDs 0-7!
1287 * pfactsN->MaxDevices unreliable
1288 * (not supported in early
1289 * versions of the FW).
1290 * max_id = 1 + actual max id,
1291 * max_lun = 1 + actual last lun,
1292 * see hosts.h :o(
1293 */
Eric Moore793955f2007-01-29 09:42:20 -07001294 sh->max_id = ioc->devices_per_bus;
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001295
1296 sh->max_lun = MPT_LAST_LUN + 1;
James Bottomleyc92f2222006-03-01 09:02:49 -06001297 /*
1298 * If RAID Firmware Detected, setup virtual channel
1299 */
1300 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
1301 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
1302 sh->max_channel = 1;
1303 else
1304 sh->max_channel = 0;
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001305 sh->this_id = ioc->pfacts[0].PortSCSIID;
1306
1307 /* Required entry.
1308 */
1309 sh->unique_id = ioc->id;
1310
1311 /* Verify that we won't exceed the maximum
1312 * number of chain buffers
1313 * We can optimize: ZZ = req_sz/sizeof(SGE)
1314 * For 32bit SGE's:
1315 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
1316 * + (req_sz - 64)/sizeof(SGE)
1317 * A slightly different algorithm is required for
1318 * 64bit SGEs.
1319 */
1320 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
1321 if (sizeof(dma_addr_t) == sizeof(u64)) {
1322 numSGE = (scale - 1) *
1323 (ioc->facts.MaxChainDepth-1) + scale +
1324 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
1325 sizeof(u32));
1326 } else {
1327 numSGE = 1 + (scale - 1) *
1328 (ioc->facts.MaxChainDepth-1) + scale +
1329 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
1330 sizeof(u32));
1331 }
1332
1333 if (numSGE < sh->sg_tablesize) {
1334 /* Reset this value */
1335 dprintk((MYIOC_s_INFO_FMT
1336 "Resetting sg_tablesize to %d from %d\n",
1337 ioc->name, numSGE, sh->sg_tablesize));
1338 sh->sg_tablesize = numSGE;
1339 }
1340
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001341 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1342
1343 hd = (MPT_SCSI_HOST *) sh->hostdata;
1344 hd->ioc = ioc;
1345
1346 /* SCSI needs scsi_cmnd lookup table!
1347 * (with size equal to req_depth*PtrSz!)
1348 */
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001349 hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
1350 if (!hd->ScsiLookup) {
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001351 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001352 goto out_mptspi_probe;
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001353 }
1354
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001355 dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
1356 ioc->name, hd->ScsiLookup));
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001357
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001358 /* Clear the TM flags
1359 */
1360 hd->tmPending = 0;
1361 hd->tmState = TM_STATE_NONE;
1362 hd->resetPending = 0;
1363 hd->abortSCpnt = NULL;
1364
1365 /* Clear the pointer used to store
1366 * single-threaded commands, i.e., those
1367 * issued during a bus scan, dv and
1368 * configuration pages.
1369 */
1370 hd->cmdPtr = NULL;
1371
1372 /* Initialize this SCSI Hosts' timers
1373 * To use, set the timer expires field
1374 * and add_timer
1375 */
1376 init_timer(&hd->timer);
1377 hd->timer.data = (unsigned long) hd;
1378 hd->timer.function = mptscsih_timer_expired;
1379
1380 ioc->spi_data.Saf_Te = mpt_saf_te;
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001381
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001382 hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
1383 ddvprintk((MYIOC_s_INFO_FMT
Eric Mooreba856d32006-07-11 17:34:01 -06001384 "saf_te %x\n",
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001385 ioc->name,
Eric Mooreba856d32006-07-11 17:34:01 -06001386 mpt_saf_te));
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001387 ioc->spi_data.noQas = 0;
1388
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001389 init_waitqueue_head(&hd->scandv_waitq);
1390 hd->scandv_wait_done = 0;
1391 hd->last_queue_full = 0;
1392
James Bottomleyc92f2222006-03-01 09:02:49 -06001393 /* Some versions of the firmware don't support page 0; without
1394 * that we can't get the parameters */
1395 if (hd->ioc->spi_data.sdp0length != 0)
1396 sh->transportt = mptspi_transport_template;
1397
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001398 error = scsi_add_host (sh, &ioc->pcidev->dev);
1399 if(error) {
1400 dprintk((KERN_ERR MYNAM
1401 "scsi_add_host failed\n"));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001402 goto out_mptspi_probe;
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001403 }
1404
Moore, Ericd8e925d2006-01-16 18:53:06 -07001405 /*
1406 * issue internal bus reset
1407 */
1408 if (ioc->spi_data.bus_reset)
1409 mptscsih_TMHandler(hd,
1410 MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
1411 0, 0, 0, 0, 5);
1412
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001413 scsi_scan_host(sh);
1414 return 0;
1415
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07001416out_mptspi_probe:
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001417
1418 mptscsih_remove(pdev);
1419 return error;
1420}
1421
1422static struct pci_driver mptspi_driver = {
1423 .name = "mptspi",
1424 .id_table = mptspi_pci_table,
1425 .probe = mptspi_probe,
1426 .remove = __devexit_p(mptscsih_remove),
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -07001427 .shutdown = mptscsih_shutdown,
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001428#ifdef CONFIG_PM
1429 .suspend = mptscsih_suspend,
Eric Moore6e1cad02006-04-25 17:38:58 -06001430 .resume = mptspi_resume,
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001431#endif
1432};
1433
1434/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1435/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001436 * mptspi_init - Register MPT adapter(s) as SCSI host(s) with SCSI mid-layer.
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001437 *
1438 * Returns 0 for success, non-zero for failure.
1439 */
1440static int __init
1441mptspi_init(void)
1442{
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001443 show_mptmod_ver(my_NAME, my_VERSION);
1444
James Bottomleyc92f2222006-03-01 09:02:49 -06001445 mptspi_transport_template = spi_attach_transport(&mptspi_transport_functions);
1446 if (!mptspi_transport_template)
1447 return -ENODEV;
1448
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001449 mptspiDoneCtx = mpt_register(mptscsih_io_done, MPTSPI_DRIVER);
1450 mptspiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSPI_DRIVER);
1451 mptspiInternalCtx = mpt_register(mptscsih_scandv_complete, MPTSPI_DRIVER);
1452
James Bottomleyc92f2222006-03-01 09:02:49 -06001453 if (mpt_event_register(mptspiDoneCtx, mptspi_event_process) == 0) {
Moore, Eric3a892be2006-03-14 09:14:03 -07001454 devtverboseprintk((KERN_INFO MYNAM
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001455 ": Registered for IOC event notifications\n"));
1456 }
1457
Eric Moore6e1cad02006-04-25 17:38:58 -06001458 if (mpt_reset_register(mptspiDoneCtx, mptspi_ioc_reset) == 0) {
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001459 dprintk((KERN_INFO MYNAM
1460 ": Registered for IOC reset notifications\n"));
1461 }
1462
1463 return pci_register_driver(&mptspi_driver);
1464}
1465
1466/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1467/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1468/**
1469 * mptspi_exit - Unregisters MPT adapter(s)
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001470 */
1471static void __exit
1472mptspi_exit(void)
1473{
1474 pci_unregister_driver(&mptspi_driver);
Moore, Ericd8e925d2006-01-16 18:53:06 -07001475
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001476 mpt_reset_deregister(mptspiDoneCtx);
1477 dprintk((KERN_INFO MYNAM
1478 ": Deregistered for IOC reset notifications\n"));
1479
1480 mpt_event_deregister(mptspiDoneCtx);
1481 dprintk((KERN_INFO MYNAM
1482 ": Deregistered for IOC event notifications\n"));
1483
1484 mpt_deregister(mptspiInternalCtx);
1485 mpt_deregister(mptspiTaskCtx);
1486 mpt_deregister(mptspiDoneCtx);
James Bottomleyc92f2222006-03-01 09:02:49 -06001487 spi_release_transport(mptspi_transport_template);
Moore, Eric Dean 243eabc2005-04-22 18:02:25 -04001488}
1489
1490module_init(mptspi_init);
1491module_exit(mptspi_exit);