diff options
Diffstat (limited to 'drivers/message/fusion/mptspi.c')
-rw-r--r-- | drivers/message/fusion/mptspi.c | 733 |
1 files changed, 680 insertions, 53 deletions
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index f148dfa39117..437189f871b0 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c | |||
@@ -56,12 +56,15 @@ | |||
56 | #include <linux/reboot.h> /* notifier code */ | 56 | #include <linux/reboot.h> /* notifier code */ |
57 | #include <linux/sched.h> | 57 | #include <linux/sched.h> |
58 | #include <linux/workqueue.h> | 58 | #include <linux/workqueue.h> |
59 | #include <linux/raid_class.h> | ||
59 | 60 | ||
60 | #include <scsi/scsi.h> | 61 | #include <scsi/scsi.h> |
61 | #include <scsi/scsi_cmnd.h> | 62 | #include <scsi/scsi_cmnd.h> |
62 | #include <scsi/scsi_device.h> | 63 | #include <scsi/scsi_device.h> |
63 | #include <scsi/scsi_host.h> | 64 | #include <scsi/scsi_host.h> |
64 | #include <scsi/scsi_tcq.h> | 65 | #include <scsi/scsi_tcq.h> |
66 | #include <scsi/scsi_transport.h> | ||
67 | #include <scsi/scsi_transport_spi.h> | ||
65 | 68 | ||
66 | #include "mptbase.h" | 69 | #include "mptbase.h" |
67 | #include "mptscsih.h" | 70 | #include "mptscsih.h" |
@@ -76,20 +79,6 @@ MODULE_DESCRIPTION(my_NAME); | |||
76 | MODULE_LICENSE("GPL"); | 79 | MODULE_LICENSE("GPL"); |
77 | 80 | ||
78 | /* Command line args */ | 81 | /* Command line args */ |
79 | #ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION | ||
80 | static int mpt_dv = MPTSCSIH_DOMAIN_VALIDATION; | ||
81 | module_param(mpt_dv, int, 0); | ||
82 | MODULE_PARM_DESC(mpt_dv, " DV Algorithm: enhanced=1, basic=0 (default=MPTSCSIH_DOMAIN_VALIDATION=1)"); | ||
83 | |||
84 | static int mpt_width = MPTSCSIH_MAX_WIDTH; | ||
85 | module_param(mpt_width, int, 0); | ||
86 | MODULE_PARM_DESC(mpt_width, " Max Bus Width: wide=1, narrow=0 (default=MPTSCSIH_MAX_WIDTH=1)"); | ||
87 | |||
88 | static ushort mpt_factor = MPTSCSIH_MIN_SYNC; | ||
89 | module_param(mpt_factor, ushort, 0); | ||
90 | MODULE_PARM_DESC(mpt_factor, " Min Sync Factor (default=MPTSCSIH_MIN_SYNC=0x08)"); | ||
91 | #endif | ||
92 | |||
93 | static int mpt_saf_te = MPTSCSIH_SAF_TE; | 82 | static int mpt_saf_te = MPTSCSIH_SAF_TE; |
94 | module_param(mpt_saf_te, int, 0); | 83 | module_param(mpt_saf_te, int, 0); |
95 | MODULE_PARM_DESC(mpt_saf_te, " Force enabling SEP Processor: enable=1 (default=MPTSCSIH_SAF_TE=0)"); | 84 | MODULE_PARM_DESC(mpt_saf_te, " Force enabling SEP Processor: enable=1 (default=MPTSCSIH_SAF_TE=0)"); |
@@ -98,10 +87,308 @@ static int mpt_pq_filter = 0; | |||
98 | module_param(mpt_pq_filter, int, 0); | 87 | module_param(mpt_pq_filter, int, 0); |
99 | MODULE_PARM_DESC(mpt_pq_filter, " Enable peripheral qualifier filter: enable=1 (default=0)"); | 88 | MODULE_PARM_DESC(mpt_pq_filter, " Enable peripheral qualifier filter: enable=1 (default=0)"); |
100 | 89 | ||
90 | static void mptspi_write_offset(struct scsi_target *, int); | ||
91 | static void mptspi_write_width(struct scsi_target *, int); | ||
92 | static int mptspi_write_spi_device_pg1(struct scsi_target *, | ||
93 | struct _CONFIG_PAGE_SCSI_DEVICE_1 *); | ||
94 | |||
95 | static struct scsi_transport_template *mptspi_transport_template = NULL; | ||
96 | |||
101 | static int mptspiDoneCtx = -1; | 97 | static int mptspiDoneCtx = -1; |
102 | static int mptspiTaskCtx = -1; | 98 | static int mptspiTaskCtx = -1; |
103 | static int mptspiInternalCtx = -1; /* Used only for internal commands */ | 99 | static int mptspiInternalCtx = -1; /* Used only for internal commands */ |
104 | 100 | ||
101 | static int mptspi_target_alloc(struct scsi_target *starget) | ||
102 | { | ||
103 | struct Scsi_Host *shost = dev_to_shost(&starget->dev); | ||
104 | struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata; | ||
105 | int ret; | ||
106 | |||
107 | if (hd == NULL) | ||
108 | return -ENODEV; | ||
109 | |||
110 | ret = mptscsih_target_alloc(starget); | ||
111 | if (ret) | ||
112 | return ret; | ||
113 | |||
114 | /* if we're a device on virtual channel 1 and we're not part | ||
115 | * of an array, just return here (otherwise the setup below | ||
116 | * may actually affect a real physical device on channel 0 */ | ||
117 | if (starget->channel == 1 && | ||
118 | mptscsih_raid_id_to_num(hd, starget->id) < 0) | ||
119 | return 0; | ||
120 | |||
121 | if (hd->ioc->spi_data.nvram && | ||
122 | hd->ioc->spi_data.nvram[starget->id] != MPT_HOST_NVRAM_INVALID) { | ||
123 | u32 nvram = hd->ioc->spi_data.nvram[starget->id]; | ||
124 | spi_min_period(starget) = (nvram & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT; | ||
125 | spi_max_width(starget) = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1; | ||
126 | } else { | ||
127 | spi_min_period(starget) = hd->ioc->spi_data.minSyncFactor; | ||
128 | spi_max_width(starget) = hd->ioc->spi_data.maxBusWidth; | ||
129 | } | ||
130 | spi_max_offset(starget) = hd->ioc->spi_data.maxSyncOffset; | ||
131 | |||
132 | spi_offset(starget) = 0; | ||
133 | mptspi_write_width(starget, 0); | ||
134 | |||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | static int mptspi_read_spi_device_pg0(struct scsi_target *starget, | ||
139 | struct _CONFIG_PAGE_SCSI_DEVICE_0 *pass_pg0) | ||
140 | { | ||
141 | struct Scsi_Host *shost = dev_to_shost(&starget->dev); | ||
142 | struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata; | ||
143 | struct _MPT_ADAPTER *ioc = hd->ioc; | ||
144 | struct _CONFIG_PAGE_SCSI_DEVICE_0 *pg0; | ||
145 | dma_addr_t pg0_dma; | ||
146 | int size; | ||
147 | struct _x_config_parms cfg; | ||
148 | struct _CONFIG_PAGE_HEADER hdr; | ||
149 | int err = -EBUSY; | ||
150 | |||
151 | /* No SPI parameters for RAID devices */ | ||
152 | if (starget->channel == 0 && | ||
153 | (hd->ioc->raid_data.isRaid & (1 << starget->id))) | ||
154 | return -1; | ||
155 | |||
156 | size = ioc->spi_data.sdp0length * 4; | ||
157 | /* | ||
158 | if (ioc->spi_data.sdp0length & 1) | ||
159 | size += size + 4; | ||
160 | size += 2048; | ||
161 | */ | ||
162 | |||
163 | pg0 = dma_alloc_coherent(&ioc->pcidev->dev, size, &pg0_dma, GFP_KERNEL); | ||
164 | if (pg0 == NULL) { | ||
165 | starget_printk(KERN_ERR, starget, "dma_alloc_coherent for parameters failed\n"); | ||
166 | return -EINVAL; | ||
167 | } | ||
168 | |||
169 | memset(&hdr, 0, sizeof(hdr)); | ||
170 | |||
171 | hdr.PageVersion = ioc->spi_data.sdp0version; | ||
172 | hdr.PageLength = ioc->spi_data.sdp0length; | ||
173 | hdr.PageNumber = 0; | ||
174 | hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; | ||
175 | |||
176 | memset(&cfg, 0, sizeof(cfg)); | ||
177 | |||
178 | cfg.cfghdr.hdr = &hdr; | ||
179 | cfg.physAddr = pg0_dma; | ||
180 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; | ||
181 | cfg.dir = 0; | ||
182 | cfg.pageAddr = starget->id; | ||
183 | |||
184 | if (mpt_config(ioc, &cfg)) { | ||
185 | starget_printk(KERN_ERR, starget, "mpt_config failed\n"); | ||
186 | goto out_free; | ||
187 | } | ||
188 | err = 0; | ||
189 | memcpy(pass_pg0, pg0, size); | ||
190 | |||
191 | out_free: | ||
192 | dma_free_coherent(&ioc->pcidev->dev, size, pg0, pg0_dma); | ||
193 | return err; | ||
194 | } | ||
195 | |||
196 | static u32 mptspi_getRP(struct scsi_target *starget) | ||
197 | { | ||
198 | u32 nego = 0; | ||
199 | |||
200 | nego |= spi_iu(starget) ? MPI_SCSIDEVPAGE1_RP_IU : 0; | ||
201 | nego |= spi_dt(starget) ? MPI_SCSIDEVPAGE1_RP_DT : 0; | ||
202 | nego |= spi_qas(starget) ? MPI_SCSIDEVPAGE1_RP_QAS : 0; | ||
203 | nego |= spi_hold_mcs(starget) ? MPI_SCSIDEVPAGE1_RP_HOLD_MCS : 0; | ||
204 | nego |= spi_wr_flow(starget) ? MPI_SCSIDEVPAGE1_RP_WR_FLOW : 0; | ||
205 | nego |= spi_rd_strm(starget) ? MPI_SCSIDEVPAGE1_RP_RD_STRM : 0; | ||
206 | nego |= spi_rti(starget) ? MPI_SCSIDEVPAGE1_RP_RTI : 0; | ||
207 | nego |= spi_pcomp_en(starget) ? MPI_SCSIDEVPAGE1_RP_PCOMP_EN : 0; | ||
208 | |||
209 | nego |= (spi_period(starget) << MPI_SCSIDEVPAGE1_RP_SHIFT_MIN_SYNC_PERIOD) & MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK; | ||
210 | nego |= (spi_offset(starget) << MPI_SCSIDEVPAGE1_RP_SHIFT_MAX_SYNC_OFFSET) & MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK; | ||
211 | nego |= spi_width(starget) ? MPI_SCSIDEVPAGE1_RP_WIDE : 0; | ||
212 | |||
213 | return nego; | ||
214 | } | ||
215 | |||
216 | static void mptspi_read_parameters(struct scsi_target *starget) | ||
217 | { | ||
218 | int nego; | ||
219 | struct _CONFIG_PAGE_SCSI_DEVICE_0 pg0; | ||
220 | |||
221 | mptspi_read_spi_device_pg0(starget, &pg0); | ||
222 | |||
223 | nego = le32_to_cpu(pg0.NegotiatedParameters); | ||
224 | |||
225 | spi_iu(starget) = (nego & MPI_SCSIDEVPAGE0_NP_IU) ? 1 : 0; | ||
226 | spi_dt(starget) = (nego & MPI_SCSIDEVPAGE0_NP_DT) ? 1 : 0; | ||
227 | spi_qas(starget) = (nego & MPI_SCSIDEVPAGE0_NP_QAS) ? 1 : 0; | ||
228 | spi_wr_flow(starget) = (nego & MPI_SCSIDEVPAGE0_NP_WR_FLOW) ? 1 : 0; | ||
229 | spi_rd_strm(starget) = (nego & MPI_SCSIDEVPAGE0_NP_RD_STRM) ? 1 : 0; | ||
230 | spi_rti(starget) = (nego & MPI_SCSIDEVPAGE0_NP_RTI) ? 1 : 0; | ||
231 | spi_pcomp_en(starget) = (nego & MPI_SCSIDEVPAGE0_NP_PCOMP_EN) ? 1 : 0; | ||
232 | spi_hold_mcs(starget) = (nego & MPI_SCSIDEVPAGE0_NP_HOLD_MCS) ? 1 : 0; | ||
233 | spi_period(starget) = (nego & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> MPI_SCSIDEVPAGE0_NP_SHIFT_SYNC_PERIOD; | ||
234 | spi_offset(starget) = (nego & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) >> MPI_SCSIDEVPAGE0_NP_SHIFT_SYNC_OFFSET; | ||
235 | spi_width(starget) = (nego & MPI_SCSIDEVPAGE0_NP_WIDE) ? 1 : 0; | ||
236 | } | ||
237 | |||
238 | static int | ||
239 | mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, int disk) | ||
240 | { | ||
241 | MpiRaidActionRequest_t *pReq; | ||
242 | MPT_FRAME_HDR *mf; | ||
243 | |||
244 | /* Get and Populate a free Frame | ||
245 | */ | ||
246 | if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) { | ||
247 | ddvprintk((MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n", | ||
248 | hd->ioc->name)); | ||
249 | return -EAGAIN; | ||
250 | } | ||
251 | pReq = (MpiRaidActionRequest_t *)mf; | ||
252 | if (quiesce) | ||
253 | pReq->Action = MPI_RAID_ACTION_QUIESCE_PHYS_IO; | ||
254 | else | ||
255 | pReq->Action = MPI_RAID_ACTION_ENABLE_PHYS_IO; | ||
256 | pReq->Reserved1 = 0; | ||
257 | pReq->ChainOffset = 0; | ||
258 | pReq->Function = MPI_FUNCTION_RAID_ACTION; | ||
259 | pReq->VolumeID = disk; | ||
260 | pReq->VolumeBus = 0; | ||
261 | pReq->PhysDiskNum = 0; | ||
262 | pReq->MsgFlags = 0; | ||
263 | pReq->Reserved2 = 0; | ||
264 | pReq->ActionDataWord = 0; /* Reserved for this action */ | ||
265 | |||
266 | mpt_add_sge((char *)&pReq->ActionDataSGE, | ||
267 | MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1); | ||
268 | |||
269 | ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action %x id %d\n", | ||
270 | hd->ioc->name, action, io->id)); | ||
271 | |||
272 | hd->pLocal = NULL; | ||
273 | hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */ | ||
274 | hd->scandv_wait_done = 0; | ||
275 | |||
276 | /* Save cmd pointer, for resource free if timeout or | ||
277 | * FW reload occurs | ||
278 | */ | ||
279 | hd->cmdPtr = mf; | ||
280 | |||
281 | add_timer(&hd->timer); | ||
282 | mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf); | ||
283 | wait_event(hd->scandv_waitq, hd->scandv_wait_done); | ||
284 | |||
285 | if ((hd->pLocal == NULL) || (hd->pLocal->completion != 0)) | ||
286 | return -1; | ||
287 | |||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd, | ||
292 | struct scsi_device *sdev) | ||
293 | { | ||
294 | VirtTarget *vtarget = scsi_target(sdev)->hostdata; | ||
295 | |||
296 | /* no DV on RAID devices */ | ||
297 | if (sdev->channel == 0 && | ||
298 | (hd->ioc->raid_data.isRaid & (1 << sdev->id))) | ||
299 | return; | ||
300 | |||
301 | /* If this is a piece of a RAID, then quiesce first */ | ||
302 | if (sdev->channel == 1 && | ||
303 | mptscsih_quiesce_raid(hd, 1, vtarget->target_id) < 0) { | ||
304 | starget_printk(KERN_ERR, scsi_target(sdev), | ||
305 | "Integrated RAID quiesce failed\n"); | ||
306 | return; | ||
307 | } | ||
308 | |||
309 | spi_dv_device(sdev); | ||
310 | |||
311 | if (sdev->channel == 1 && | ||
312 | mptscsih_quiesce_raid(hd, 0, vtarget->target_id) < 0) | ||
313 | starget_printk(KERN_ERR, scsi_target(sdev), | ||
314 | "Integrated RAID resume failed\n"); | ||
315 | |||
316 | mptspi_read_parameters(sdev->sdev_target); | ||
317 | spi_display_xfer_agreement(sdev->sdev_target); | ||
318 | mptspi_read_parameters(sdev->sdev_target); | ||
319 | } | ||
320 | |||
321 | static int mptspi_slave_alloc(struct scsi_device *sdev) | ||
322 | { | ||
323 | int ret; | ||
324 | MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata; | ||
325 | /* gcc doesn't see that all uses of this variable occur within | ||
326 | * the if() statements, so stop it from whining */ | ||
327 | int physdisknum = 0; | ||
328 | |||
329 | if (sdev->channel == 1) { | ||
330 | physdisknum = mptscsih_raid_id_to_num(hd, sdev->id); | ||
331 | |||
332 | if (physdisknum < 0) | ||
333 | return physdisknum; | ||
334 | } | ||
335 | |||
336 | ret = mptscsih_slave_alloc(sdev); | ||
337 | |||
338 | if (ret) | ||
339 | return ret; | ||
340 | |||
341 | if (sdev->channel == 1) { | ||
342 | VirtDevice *vdev = sdev->hostdata; | ||
343 | sdev->no_uld_attach = 1; | ||
344 | vdev->vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; | ||
345 | /* The real channel for this device is zero */ | ||
346 | vdev->bus_id = 0; | ||
347 | /* The actual physdisknum (for RAID passthrough) */ | ||
348 | vdev->target_id = physdisknum; | ||
349 | } | ||
350 | |||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | static int mptspi_slave_configure(struct scsi_device *sdev) | ||
355 | { | ||
356 | int ret = mptscsih_slave_configure(sdev); | ||
357 | struct _MPT_SCSI_HOST *hd = | ||
358 | (struct _MPT_SCSI_HOST *)sdev->host->hostdata; | ||
359 | |||
360 | if (ret) | ||
361 | return ret; | ||
362 | |||
363 | if ((sdev->channel == 1 || | ||
364 | !(hd->ioc->raid_data.isRaid & (1 << sdev->id))) && | ||
365 | !spi_initial_dv(sdev->sdev_target)) | ||
366 | mptspi_dv_device(hd, sdev); | ||
367 | |||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | static void mptspi_slave_destroy(struct scsi_device *sdev) | ||
372 | { | ||
373 | struct scsi_target *starget = scsi_target(sdev); | ||
374 | VirtTarget *vtarget = starget->hostdata; | ||
375 | VirtDevice *vdevice = sdev->hostdata; | ||
376 | |||
377 | /* Will this be the last lun on a non-raid device? */ | ||
378 | if (vtarget->num_luns == 1 && vdevice->configured_lun) { | ||
379 | struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; | ||
380 | |||
381 | /* Async Narrow */ | ||
382 | pg1.RequestedParameters = 0; | ||
383 | pg1.Reserved = 0; | ||
384 | pg1.Configuration = 0; | ||
385 | |||
386 | mptspi_write_spi_device_pg1(starget, &pg1); | ||
387 | } | ||
388 | |||
389 | mptscsih_slave_destroy(sdev); | ||
390 | } | ||
391 | |||
105 | static struct scsi_host_template mptspi_driver_template = { | 392 | static struct scsi_host_template mptspi_driver_template = { |
106 | .module = THIS_MODULE, | 393 | .module = THIS_MODULE, |
107 | .proc_name = "mptspi", | 394 | .proc_name = "mptspi", |
@@ -109,11 +396,11 @@ static struct scsi_host_template mptspi_driver_template = { | |||
109 | .name = "MPT SPI Host", | 396 | .name = "MPT SPI Host", |
110 | .info = mptscsih_info, | 397 | .info = mptscsih_info, |
111 | .queuecommand = mptscsih_qcmd, | 398 | .queuecommand = mptscsih_qcmd, |
112 | .target_alloc = mptscsih_target_alloc, | 399 | .target_alloc = mptspi_target_alloc, |
113 | .slave_alloc = mptscsih_slave_alloc, | 400 | .slave_alloc = mptspi_slave_alloc, |
114 | .slave_configure = mptscsih_slave_configure, | 401 | .slave_configure = mptspi_slave_configure, |
115 | .target_destroy = mptscsih_target_destroy, | 402 | .target_destroy = mptscsih_target_destroy, |
116 | .slave_destroy = mptscsih_slave_destroy, | 403 | .slave_destroy = mptspi_slave_destroy, |
117 | .change_queue_depth = mptscsih_change_queue_depth, | 404 | .change_queue_depth = mptscsih_change_queue_depth, |
118 | .eh_abort_handler = mptscsih_abort, | 405 | .eh_abort_handler = mptscsih_abort, |
119 | .eh_device_reset_handler = mptscsih_dev_reset, | 406 | .eh_device_reset_handler = mptscsih_dev_reset, |
@@ -128,6 +415,360 @@ static struct scsi_host_template mptspi_driver_template = { | |||
128 | .use_clustering = ENABLE_CLUSTERING, | 415 | .use_clustering = ENABLE_CLUSTERING, |
129 | }; | 416 | }; |
130 | 417 | ||
418 | static int mptspi_write_spi_device_pg1(struct scsi_target *starget, | ||
419 | struct _CONFIG_PAGE_SCSI_DEVICE_1 *pass_pg1) | ||
420 | { | ||
421 | struct Scsi_Host *shost = dev_to_shost(&starget->dev); | ||
422 | struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata; | ||
423 | struct _MPT_ADAPTER *ioc = hd->ioc; | ||
424 | struct _CONFIG_PAGE_SCSI_DEVICE_1 *pg1; | ||
425 | dma_addr_t pg1_dma; | ||
426 | int size; | ||
427 | struct _x_config_parms cfg; | ||
428 | struct _CONFIG_PAGE_HEADER hdr; | ||
429 | int err = -EBUSY; | ||
430 | |||
431 | /* don't allow updating nego parameters on RAID devices */ | ||
432 | if (starget->channel == 0 && | ||
433 | (hd->ioc->raid_data.isRaid & (1 << starget->id))) | ||
434 | return -1; | ||
435 | |||
436 | size = ioc->spi_data.sdp1length * 4; | ||
437 | |||
438 | pg1 = dma_alloc_coherent(&ioc->pcidev->dev, size, &pg1_dma, GFP_KERNEL); | ||
439 | if (pg1 == NULL) { | ||
440 | starget_printk(KERN_ERR, starget, "dma_alloc_coherent for parameters failed\n"); | ||
441 | return -EINVAL; | ||
442 | } | ||
443 | |||
444 | memset(&hdr, 0, sizeof(hdr)); | ||
445 | |||
446 | hdr.PageVersion = ioc->spi_data.sdp1version; | ||
447 | hdr.PageLength = ioc->spi_data.sdp1length; | ||
448 | hdr.PageNumber = 1; | ||
449 | hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; | ||
450 | |||
451 | memset(&cfg, 0, sizeof(cfg)); | ||
452 | |||
453 | cfg.cfghdr.hdr = &hdr; | ||
454 | cfg.physAddr = pg1_dma; | ||
455 | cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; | ||
456 | cfg.dir = 1; | ||
457 | cfg.pageAddr = starget->id; | ||
458 | |||
459 | memcpy(pg1, pass_pg1, size); | ||
460 | |||
461 | pg1->Header.PageVersion = hdr.PageVersion; | ||
462 | pg1->Header.PageLength = hdr.PageLength; | ||
463 | pg1->Header.PageNumber = hdr.PageNumber; | ||
464 | pg1->Header.PageType = hdr.PageType; | ||
465 | |||
466 | if (mpt_config(ioc, &cfg)) { | ||
467 | starget_printk(KERN_ERR, starget, "mpt_config failed\n"); | ||
468 | goto out_free; | ||
469 | } | ||
470 | err = 0; | ||
471 | |||
472 | out_free: | ||
473 | dma_free_coherent(&ioc->pcidev->dev, size, pg1, pg1_dma); | ||
474 | return err; | ||
475 | } | ||
476 | |||
477 | static void mptspi_write_offset(struct scsi_target *starget, int offset) | ||
478 | { | ||
479 | struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; | ||
480 | u32 nego; | ||
481 | |||
482 | if (offset < 0) | ||
483 | offset = 0; | ||
484 | |||
485 | if (offset > 255) | ||
486 | offset = 255; | ||
487 | |||
488 | if (spi_offset(starget) == -1) | ||
489 | mptspi_read_parameters(starget); | ||
490 | |||
491 | spi_offset(starget) = offset; | ||
492 | |||
493 | nego = mptspi_getRP(starget); | ||
494 | |||
495 | pg1.RequestedParameters = cpu_to_le32(nego); | ||
496 | pg1.Reserved = 0; | ||
497 | pg1.Configuration = 0; | ||
498 | |||
499 | mptspi_write_spi_device_pg1(starget, &pg1); | ||
500 | } | ||
501 | |||
502 | static void mptspi_write_period(struct scsi_target *starget, int period) | ||
503 | { | ||
504 | struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; | ||
505 | u32 nego; | ||
506 | |||
507 | if (period < 8) | ||
508 | period = 8; | ||
509 | |||
510 | if (period > 255) | ||
511 | period = 255; | ||
512 | |||
513 | if (spi_period(starget) == -1) | ||
514 | mptspi_read_parameters(starget); | ||
515 | |||
516 | if (period == 8) { | ||
517 | spi_iu(starget) = 1; | ||
518 | spi_dt(starget) = 1; | ||
519 | } else if (period == 9) { | ||
520 | spi_dt(starget) = 1; | ||
521 | } | ||
522 | |||
523 | spi_period(starget) = period; | ||
524 | |||
525 | nego = mptspi_getRP(starget); | ||
526 | |||
527 | pg1.RequestedParameters = cpu_to_le32(nego); | ||
528 | pg1.Reserved = 0; | ||
529 | pg1.Configuration = 0; | ||
530 | |||
531 | mptspi_write_spi_device_pg1(starget, &pg1); | ||
532 | } | ||
533 | |||
534 | static void mptspi_write_dt(struct scsi_target *starget, int dt) | ||
535 | { | ||
536 | struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; | ||
537 | u32 nego; | ||
538 | |||
539 | if (spi_period(starget) == -1) | ||
540 | mptspi_read_parameters(starget); | ||
541 | |||
542 | if (!dt && spi_period(starget) < 10) | ||
543 | spi_period(starget) = 10; | ||
544 | |||
545 | spi_dt(starget) = dt; | ||
546 | |||
547 | nego = mptspi_getRP(starget); | ||
548 | |||
549 | |||
550 | pg1.RequestedParameters = cpu_to_le32(nego); | ||
551 | pg1.Reserved = 0; | ||
552 | pg1.Configuration = 0; | ||
553 | |||
554 | mptspi_write_spi_device_pg1(starget, &pg1); | ||
555 | } | ||
556 | |||
557 | static void mptspi_write_iu(struct scsi_target *starget, int iu) | ||
558 | { | ||
559 | struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; | ||
560 | u32 nego; | ||
561 | |||
562 | if (spi_period(starget) == -1) | ||
563 | mptspi_read_parameters(starget); | ||
564 | |||
565 | if (!iu && spi_period(starget) < 9) | ||
566 | spi_period(starget) = 9; | ||
567 | |||
568 | spi_iu(starget) = iu; | ||
569 | |||
570 | nego = mptspi_getRP(starget); | ||
571 | |||
572 | pg1.RequestedParameters = cpu_to_le32(nego); | ||
573 | pg1.Reserved = 0; | ||
574 | pg1.Configuration = 0; | ||
575 | |||
576 | mptspi_write_spi_device_pg1(starget, &pg1); | ||
577 | } | ||
578 | |||
579 | #define MPTSPI_SIMPLE_TRANSPORT_PARM(parm) \ | ||
580 | static void mptspi_write_##parm(struct scsi_target *starget, int parm)\ | ||
581 | { \ | ||
582 | struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; \ | ||
583 | u32 nego; \ | ||
584 | \ | ||
585 | spi_##parm(starget) = parm; \ | ||
586 | \ | ||
587 | nego = mptspi_getRP(starget); \ | ||
588 | \ | ||
589 | pg1.RequestedParameters = cpu_to_le32(nego); \ | ||
590 | pg1.Reserved = 0; \ | ||
591 | pg1.Configuration = 0; \ | ||
592 | \ | ||
593 | mptspi_write_spi_device_pg1(starget, &pg1); \ | ||
594 | } | ||
595 | |||
596 | MPTSPI_SIMPLE_TRANSPORT_PARM(rd_strm) | ||
597 | MPTSPI_SIMPLE_TRANSPORT_PARM(wr_flow) | ||
598 | MPTSPI_SIMPLE_TRANSPORT_PARM(rti) | ||
599 | MPTSPI_SIMPLE_TRANSPORT_PARM(hold_mcs) | ||
600 | MPTSPI_SIMPLE_TRANSPORT_PARM(pcomp_en) | ||
601 | |||
602 | static void mptspi_write_qas(struct scsi_target *starget, int qas) | ||
603 | { | ||
604 | struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; | ||
605 | struct Scsi_Host *shost = dev_to_shost(&starget->dev); | ||
606 | struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata; | ||
607 | VirtTarget *vtarget = starget->hostdata; | ||
608 | u32 nego; | ||
609 | |||
610 | if ((vtarget->negoFlags & MPT_TARGET_NO_NEGO_QAS) || | ||
611 | hd->ioc->spi_data.noQas) | ||
612 | spi_qas(starget) = 0; | ||
613 | else | ||
614 | spi_qas(starget) = qas; | ||
615 | |||
616 | nego = mptspi_getRP(starget); | ||
617 | |||
618 | pg1.RequestedParameters = cpu_to_le32(nego); | ||
619 | pg1.Reserved = 0; | ||
620 | pg1.Configuration = 0; | ||
621 | |||
622 | mptspi_write_spi_device_pg1(starget, &pg1); | ||
623 | } | ||
624 | |||
625 | static void mptspi_write_width(struct scsi_target *starget, int width) | ||
626 | { | ||
627 | struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1; | ||
628 | u32 nego; | ||
629 | |||
630 | if (!width) { | ||
631 | spi_dt(starget) = 0; | ||
632 | if (spi_period(starget) < 10) | ||
633 | spi_period(starget) = 10; | ||
634 | } | ||
635 | |||
636 | spi_width(starget) = width; | ||
637 | |||
638 | nego = mptspi_getRP(starget); | ||
639 | |||
640 | pg1.RequestedParameters = cpu_to_le32(nego); | ||
641 | pg1.Reserved = 0; | ||
642 | pg1.Configuration = 0; | ||
643 | |||
644 | mptspi_write_spi_device_pg1(starget, &pg1); | ||
645 | } | ||
646 | |||
647 | struct work_queue_wrapper { | ||
648 | struct work_struct work; | ||
649 | struct _MPT_SCSI_HOST *hd; | ||
650 | int disk; | ||
651 | }; | ||
652 | |||
653 | static void mpt_work_wrapper(void *data) | ||
654 | { | ||
655 | struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data; | ||
656 | struct _MPT_SCSI_HOST *hd = wqw->hd; | ||
657 | struct Scsi_Host *shost = hd->ioc->sh; | ||
658 | struct scsi_device *sdev; | ||
659 | int disk = wqw->disk; | ||
660 | struct _CONFIG_PAGE_IOC_3 *pg3; | ||
661 | |||
662 | kfree(wqw); | ||
663 | |||
664 | mpt_findImVolumes(hd->ioc); | ||
665 | pg3 = hd->ioc->raid_data.pIocPg3; | ||
666 | if (!pg3) | ||
667 | return; | ||
668 | |||
669 | shost_for_each_device(sdev,shost) { | ||
670 | struct scsi_target *starget = scsi_target(sdev); | ||
671 | VirtTarget *vtarget = starget->hostdata; | ||
672 | |||
673 | /* only want to search RAID components */ | ||
674 | if (sdev->channel != 1) | ||
675 | continue; | ||
676 | |||
677 | /* The target_id is the raid PhysDiskNum, even if | ||
678 | * starget->id is the actual target address */ | ||
679 | if(vtarget->target_id != disk) | ||
680 | continue; | ||
681 | |||
682 | starget_printk(KERN_INFO, vtarget->starget, | ||
683 | "Integrated RAID requests DV of new device\n"); | ||
684 | mptspi_dv_device(hd, sdev); | ||
685 | } | ||
686 | shost_printk(KERN_INFO, shost, | ||
687 | "Integrated RAID detects new device %d\n", disk); | ||
688 | scsi_scan_target(&hd->ioc->sh->shost_gendev, 1, disk, 0, 1); | ||
689 | } | ||
690 | |||
691 | |||
692 | static void mpt_dv_raid(struct _MPT_SCSI_HOST *hd, int disk) | ||
693 | { | ||
694 | struct work_queue_wrapper *wqw = kmalloc(sizeof(*wqw), GFP_ATOMIC); | ||
695 | |||
696 | if (!wqw) { | ||
697 | shost_printk(KERN_ERR, hd->ioc->sh, | ||
698 | "Failed to act on RAID event for physical disk %d\n", | ||
699 | disk); | ||
700 | return; | ||
701 | } | ||
702 | INIT_WORK(&wqw->work, mpt_work_wrapper, wqw); | ||
703 | wqw->hd = hd; | ||
704 | wqw->disk = disk; | ||
705 | |||
706 | schedule_work(&wqw->work); | ||
707 | } | ||
708 | |||
709 | static int | ||
710 | mptspi_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) | ||
711 | { | ||
712 | u8 event = le32_to_cpu(pEvReply->Event) & 0xFF; | ||
713 | struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)ioc->sh->hostdata; | ||
714 | |||
715 | if (hd && event == MPI_EVENT_INTEGRATED_RAID) { | ||
716 | int reason | ||
717 | = (le32_to_cpu(pEvReply->Data[0]) & 0x00FF0000) >> 16; | ||
718 | |||
719 | if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) { | ||
720 | int disk = (le32_to_cpu(pEvReply->Data[0]) & 0xFF000000) >> 24; | ||
721 | mpt_dv_raid(hd, disk); | ||
722 | } | ||
723 | } | ||
724 | return mptscsih_event_process(ioc, pEvReply); | ||
725 | } | ||
726 | |||
727 | static int | ||
728 | mptspi_deny_binding(struct scsi_target *starget) | ||
729 | { | ||
730 | struct _MPT_SCSI_HOST *hd = | ||
731 | (struct _MPT_SCSI_HOST *)dev_to_shost(starget->dev.parent)->hostdata; | ||
732 | return ((hd->ioc->raid_data.isRaid & (1 << starget->id)) && | ||
733 | starget->channel == 0) ? 1 : 0; | ||
734 | } | ||
735 | |||
736 | static struct spi_function_template mptspi_transport_functions = { | ||
737 | .get_offset = mptspi_read_parameters, | ||
738 | .set_offset = mptspi_write_offset, | ||
739 | .show_offset = 1, | ||
740 | .get_period = mptspi_read_parameters, | ||
741 | .set_period = mptspi_write_period, | ||
742 | .show_period = 1, | ||
743 | .get_width = mptspi_read_parameters, | ||
744 | .set_width = mptspi_write_width, | ||
745 | .show_width = 1, | ||
746 | .get_iu = mptspi_read_parameters, | ||
747 | .set_iu = mptspi_write_iu, | ||
748 | .show_iu = 1, | ||
749 | .get_dt = mptspi_read_parameters, | ||
750 | .set_dt = mptspi_write_dt, | ||
751 | .show_dt = 1, | ||
752 | .get_qas = mptspi_read_parameters, | ||
753 | .set_qas = mptspi_write_qas, | ||
754 | .show_qas = 1, | ||
755 | .get_wr_flow = mptspi_read_parameters, | ||
756 | .set_wr_flow = mptspi_write_wr_flow, | ||
757 | .show_wr_flow = 1, | ||
758 | .get_rd_strm = mptspi_read_parameters, | ||
759 | .set_rd_strm = mptspi_write_rd_strm, | ||
760 | .show_rd_strm = 1, | ||
761 | .get_rti = mptspi_read_parameters, | ||
762 | .set_rti = mptspi_write_rti, | ||
763 | .show_rti = 1, | ||
764 | .get_pcomp_en = mptspi_read_parameters, | ||
765 | .set_pcomp_en = mptspi_write_pcomp_en, | ||
766 | .show_pcomp_en = 1, | ||
767 | .get_hold_mcs = mptspi_read_parameters, | ||
768 | .set_hold_mcs = mptspi_write_hold_mcs, | ||
769 | .show_hold_mcs = 1, | ||
770 | .deny_binding = mptspi_deny_binding, | ||
771 | }; | ||
131 | 772 | ||
132 | /**************************************************************************** | 773 | /**************************************************************************** |
133 | * Supported hardware | 774 | * Supported hardware |
@@ -242,7 +883,14 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
242 | sh->max_id = MPT_MAX_SCSI_DEVICES; | 883 | sh->max_id = MPT_MAX_SCSI_DEVICES; |
243 | 884 | ||
244 | sh->max_lun = MPT_LAST_LUN + 1; | 885 | sh->max_lun = MPT_LAST_LUN + 1; |
245 | sh->max_channel = 0; | 886 | /* |
887 | * If RAID Firmware Detected, setup virtual channel | ||
888 | */ | ||
889 | if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK) | ||
890 | > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) | ||
891 | sh->max_channel = 1; | ||
892 | else | ||
893 | sh->max_channel = 0; | ||
246 | sh->this_id = ioc->pfacts[0].PortSCSIID; | 894 | sh->this_id = ioc->pfacts[0].PortSCSIID; |
247 | 895 | ||
248 | /* Required entry. | 896 | /* Required entry. |
@@ -301,7 +949,8 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
301 | * indicates a device exists. | 949 | * indicates a device exists. |
302 | * max_id = 1 + maximum id (hosts.h) | 950 | * max_id = 1 + maximum id (hosts.h) |
303 | */ | 951 | */ |
304 | hd->Targets = kcalloc(sh->max_id, sizeof(void *), GFP_ATOMIC); | 952 | hd->Targets = kcalloc(sh->max_id * (sh->max_channel + 1), |
953 | sizeof(void *), GFP_ATOMIC); | ||
305 | if (!hd->Targets) { | 954 | if (!hd->Targets) { |
306 | error = -ENOMEM; | 955 | error = -ENOMEM; |
307 | goto out_mptspi_probe; | 956 | goto out_mptspi_probe; |
@@ -334,49 +983,23 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
334 | ioc->spi_data.Saf_Te = mpt_saf_te; | 983 | ioc->spi_data.Saf_Te = mpt_saf_te; |
335 | hd->mpt_pq_filter = mpt_pq_filter; | 984 | hd->mpt_pq_filter = mpt_pq_filter; |
336 | 985 | ||
337 | #ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION | ||
338 | if (ioc->spi_data.maxBusWidth > mpt_width) | ||
339 | ioc->spi_data.maxBusWidth = mpt_width; | ||
340 | if (ioc->spi_data.minSyncFactor < mpt_factor) | ||
341 | ioc->spi_data.minSyncFactor = mpt_factor; | ||
342 | if (ioc->spi_data.minSyncFactor == MPT_ASYNC) { | ||
343 | ioc->spi_data.maxSyncOffset = 0; | ||
344 | } | ||
345 | ioc->spi_data.mpt_dv = mpt_dv; | ||
346 | hd->negoNvram = 0; | ||
347 | |||
348 | ddvprintk((MYIOC_s_INFO_FMT | ||
349 | "dv %x width %x factor %x saf_te %x mpt_pq_filter %x\n", | ||
350 | ioc->name, | ||
351 | mpt_dv, | ||
352 | mpt_width, | ||
353 | mpt_factor, | ||
354 | mpt_saf_te, | ||
355 | mpt_pq_filter)); | ||
356 | #else | ||
357 | hd->negoNvram = MPT_SCSICFG_USE_NVRAM; | 986 | hd->negoNvram = MPT_SCSICFG_USE_NVRAM; |
358 | ddvprintk((MYIOC_s_INFO_FMT | 987 | ddvprintk((MYIOC_s_INFO_FMT |
359 | "saf_te %x mpt_pq_filter %x\n", | 988 | "saf_te %x mpt_pq_filter %x\n", |
360 | ioc->name, | 989 | ioc->name, |
361 | mpt_saf_te, | 990 | mpt_saf_te, |
362 | mpt_pq_filter)); | 991 | mpt_pq_filter)); |
363 | #endif | ||
364 | |||
365 | ioc->spi_data.forceDv = 0; | ||
366 | ioc->spi_data.noQas = 0; | 992 | ioc->spi_data.noQas = 0; |
367 | 993 | ||
368 | for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) | ||
369 | ioc->spi_data.dvStatus[ii] = | ||
370 | MPT_SCSICFG_NEGOTIATE; | ||
371 | |||
372 | for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) | ||
373 | ioc->spi_data.dvStatus[ii] |= | ||
374 | MPT_SCSICFG_DV_NOT_DONE; | ||
375 | |||
376 | init_waitqueue_head(&hd->scandv_waitq); | 994 | init_waitqueue_head(&hd->scandv_waitq); |
377 | hd->scandv_wait_done = 0; | 995 | hd->scandv_wait_done = 0; |
378 | hd->last_queue_full = 0; | 996 | hd->last_queue_full = 0; |
379 | 997 | ||
998 | /* Some versions of the firmware don't support page 0; without | ||
999 | * that we can't get the parameters */ | ||
1000 | if (hd->ioc->spi_data.sdp0length != 0) | ||
1001 | sh->transportt = mptspi_transport_template; | ||
1002 | |||
380 | error = scsi_add_host (sh, &ioc->pcidev->dev); | 1003 | error = scsi_add_host (sh, &ioc->pcidev->dev); |
381 | if(error) { | 1004 | if(error) { |
382 | dprintk((KERN_ERR MYNAM | 1005 | dprintk((KERN_ERR MYNAM |
@@ -423,14 +1046,17 @@ static struct pci_driver mptspi_driver = { | |||
423 | static int __init | 1046 | static int __init |
424 | mptspi_init(void) | 1047 | mptspi_init(void) |
425 | { | 1048 | { |
426 | |||
427 | show_mptmod_ver(my_NAME, my_VERSION); | 1049 | show_mptmod_ver(my_NAME, my_VERSION); |
428 | 1050 | ||
1051 | mptspi_transport_template = spi_attach_transport(&mptspi_transport_functions); | ||
1052 | if (!mptspi_transport_template) | ||
1053 | return -ENODEV; | ||
1054 | |||
429 | mptspiDoneCtx = mpt_register(mptscsih_io_done, MPTSPI_DRIVER); | 1055 | mptspiDoneCtx = mpt_register(mptscsih_io_done, MPTSPI_DRIVER); |
430 | mptspiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSPI_DRIVER); | 1056 | mptspiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSPI_DRIVER); |
431 | mptspiInternalCtx = mpt_register(mptscsih_scandv_complete, MPTSPI_DRIVER); | 1057 | mptspiInternalCtx = mpt_register(mptscsih_scandv_complete, MPTSPI_DRIVER); |
432 | 1058 | ||
433 | if (mpt_event_register(mptspiDoneCtx, mptscsih_event_process) == 0) { | 1059 | if (mpt_event_register(mptspiDoneCtx, mptspi_event_process) == 0) { |
434 | devtprintk((KERN_INFO MYNAM | 1060 | devtprintk((KERN_INFO MYNAM |
435 | ": Registered for IOC event notifications\n")); | 1061 | ": Registered for IOC event notifications\n")); |
436 | } | 1062 | } |
@@ -465,6 +1091,7 @@ mptspi_exit(void) | |||
465 | mpt_deregister(mptspiInternalCtx); | 1091 | mpt_deregister(mptspiInternalCtx); |
466 | mpt_deregister(mptspiTaskCtx); | 1092 | mpt_deregister(mptspiTaskCtx); |
467 | mpt_deregister(mptspiDoneCtx); | 1093 | mpt_deregister(mptspiDoneCtx); |
1094 | spi_release_transport(mptspi_transport_template); | ||
468 | } | 1095 | } |
469 | 1096 | ||
470 | module_init(mptspi_init); | 1097 | module_init(mptspi_init); |