diff options
Diffstat (limited to 'drivers/message/fusion/mptspi.c')
-rw-r--r-- | drivers/message/fusion/mptspi.c | 527 |
1 files changed, 462 insertions, 65 deletions
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index 203c661d2c79..c31a9e3c8a26 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * running LSI Logic Fusion MPT (Message Passing Technology) firmware. | 4 | * running LSI Logic Fusion MPT (Message Passing Technology) firmware. |
5 | * | 5 | * |
6 | * Copyright (c) 1999-2007 LSI Logic Corporation | 6 | * Copyright (c) 1999-2007 LSI Logic Corporation |
7 | * (mailto:mpt_linux_developer@lsil.com) | 7 | * (mailto:mpt_linux_developer@lsi.com) |
8 | * | 8 | * |
9 | */ | 9 | */ |
10 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 10 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
@@ -65,6 +65,7 @@ | |||
65 | #include <scsi/scsi_tcq.h> | 65 | #include <scsi/scsi_tcq.h> |
66 | #include <scsi/scsi_transport.h> | 66 | #include <scsi/scsi_transport.h> |
67 | #include <scsi/scsi_transport_spi.h> | 67 | #include <scsi/scsi_transport_spi.h> |
68 | #include <scsi/scsi_dbg.h> | ||
68 | 69 | ||
69 | #include "mptbase.h" | 70 | #include "mptbase.h" |
70 | #include "mptscsih.h" | 71 | #include "mptscsih.h" |
@@ -95,25 +96,339 @@ static int mptspiDoneCtx = -1; | |||
95 | static int mptspiTaskCtx = -1; | 96 | static int mptspiTaskCtx = -1; |
96 | static int mptspiInternalCtx = -1; /* Used only for internal commands */ | 97 | static int mptspiInternalCtx = -1; /* Used only for internal commands */ |
97 | 98 | ||
99 | /** | ||
100 | * mptspi_setTargetNegoParms - Update the target negotiation | ||
101 | * parameters based on the the Inquiry data, adapter capabilities, | ||
102 | * and NVRAM settings | ||
103 | * | ||
104 | * @hd: Pointer to a SCSI Host Structure | ||
105 | * @vtarget: per target private data | ||
106 | * @sdev: SCSI device | ||
107 | * | ||
108 | **/ | ||
109 | static void | ||
110 | mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target, | ||
111 | struct scsi_device *sdev) | ||
112 | { | ||
113 | SpiCfgData *pspi_data = &hd->ioc->spi_data; | ||
114 | int id = (int) target->id; | ||
115 | int nvram; | ||
116 | u8 width = MPT_NARROW; | ||
117 | u8 factor = MPT_ASYNC; | ||
118 | u8 offset = 0; | ||
119 | u8 nfactor; | ||
120 | u8 noQas = 1; | ||
121 | |||
122 | target->negoFlags = pspi_data->noQas; | ||
123 | |||
124 | if (sdev->scsi_level < SCSI_2) { | ||
125 | width = 0; | ||
126 | factor = MPT_ULTRA2; | ||
127 | offset = pspi_data->maxSyncOffset; | ||
128 | target->tflags &= ~MPT_TARGET_FLAGS_Q_YES; | ||
129 | } else { | ||
130 | if (scsi_device_wide(sdev)) | ||
131 | width = 1; | ||
132 | |||
133 | if (scsi_device_sync(sdev)) { | ||
134 | factor = pspi_data->minSyncFactor; | ||
135 | if (!scsi_device_dt(sdev)) | ||
136 | factor = MPT_ULTRA2; | ||
137 | else { | ||
138 | if (!scsi_device_ius(sdev) && | ||
139 | !scsi_device_qas(sdev)) | ||
140 | factor = MPT_ULTRA160; | ||
141 | else { | ||
142 | factor = MPT_ULTRA320; | ||
143 | if (scsi_device_qas(sdev)) { | ||
144 | ddvprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", scsi_device_qas(sdev), id)); | ||
145 | noQas = 0; | ||
146 | } | ||
147 | if (sdev->type == TYPE_TAPE && | ||
148 | scsi_device_ius(sdev)) | ||
149 | target->negoFlags |= MPT_TAPE_NEGO_IDP; | ||
150 | } | ||
151 | } | ||
152 | offset = pspi_data->maxSyncOffset; | ||
153 | |||
154 | /* If RAID, never disable QAS | ||
155 | * else if non RAID, do not disable | ||
156 | * QAS if bit 1 is set | ||
157 | * bit 1 QAS support, non-raid only | ||
158 | * bit 0 IU support | ||
159 | */ | ||
160 | if (target->raidVolume == 1) | ||
161 | noQas = 0; | ||
162 | } else { | ||
163 | factor = MPT_ASYNC; | ||
164 | offset = 0; | ||
165 | } | ||
166 | } | ||
167 | |||
168 | if (!sdev->tagged_supported) | ||
169 | target->tflags &= ~MPT_TARGET_FLAGS_Q_YES; | ||
170 | |||
171 | /* Update tflags based on NVRAM settings. (SCSI only) | ||
172 | */ | ||
173 | if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) { | ||
174 | nvram = pspi_data->nvram[id]; | ||
175 | nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8; | ||
176 | |||
177 | if (width) | ||
178 | width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1; | ||
179 | |||
180 | if (offset > 0) { | ||
181 | /* Ensure factor is set to the | ||
182 | * maximum of: adapter, nvram, inquiry | ||
183 | */ | ||
184 | if (nfactor) { | ||
185 | if (nfactor < pspi_data->minSyncFactor ) | ||
186 | nfactor = pspi_data->minSyncFactor; | ||
187 | |||
188 | factor = max(factor, nfactor); | ||
189 | if (factor == MPT_ASYNC) | ||
190 | offset = 0; | ||
191 | } else { | ||
192 | offset = 0; | ||
193 | factor = MPT_ASYNC; | ||
194 | } | ||
195 | } else { | ||
196 | factor = MPT_ASYNC; | ||
197 | } | ||
198 | } | ||
199 | |||
200 | /* Make sure data is consistent | ||
201 | */ | ||
202 | if ((!width) && (factor < MPT_ULTRA2)) | ||
203 | factor = MPT_ULTRA2; | ||
204 | |||
205 | /* Save the data to the target structure. | ||
206 | */ | ||
207 | target->minSyncFactor = factor; | ||
208 | target->maxOffset = offset; | ||
209 | target->maxWidth = width; | ||
210 | |||
211 | target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO; | ||
212 | |||
213 | /* Disable unused features. | ||
214 | */ | ||
215 | if (!width) | ||
216 | target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE; | ||
217 | |||
218 | if (!offset) | ||
219 | target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC; | ||
220 | |||
221 | if ( factor > MPT_ULTRA320 ) | ||
222 | noQas = 0; | ||
223 | |||
224 | if (noQas && (pspi_data->noQas == 0)) { | ||
225 | pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS; | ||
226 | target->negoFlags |= MPT_TARGET_NO_NEGO_QAS; | ||
227 | |||
228 | /* Disable QAS in a mixed configuration case | ||
229 | */ | ||
230 | |||
231 | ddvprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id)); | ||
232 | } | ||
233 | } | ||
234 | |||
235 | /** | ||
236 | * mptspi_writeIOCPage4 - write IOC Page 4 | ||
237 | * @hd: Pointer to a SCSI Host Structure | ||
238 | * @channel: | ||
239 | * @id: write IOC Page4 for this ID & Bus | ||
240 | * | ||
241 | * Return: -EAGAIN if unable to obtain a Message Frame | ||
242 | * or 0 if success. | ||
243 | * | ||
244 | * Remark: We do not wait for a return, write pages sequentially. | ||
245 | **/ | ||
246 | static int | ||
247 | mptspi_writeIOCPage4(MPT_SCSI_HOST *hd, u8 channel , u8 id) | ||
248 | { | ||
249 | MPT_ADAPTER *ioc = hd->ioc; | ||
250 | Config_t *pReq; | ||
251 | IOCPage4_t *IOCPage4Ptr; | ||
252 | MPT_FRAME_HDR *mf; | ||
253 | dma_addr_t dataDma; | ||
254 | u16 req_idx; | ||
255 | u32 frameOffset; | ||
256 | u32 flagsLength; | ||
257 | int ii; | ||
258 | |||
259 | /* Get a MF for this command. | ||
260 | */ | ||
261 | if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) { | ||
262 | dfailprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n", | ||
263 | ioc->name)); | ||
264 | return -EAGAIN; | ||
265 | } | ||
266 | |||
267 | /* Set the request and the data pointers. | ||
268 | * Place data at end of MF. | ||
269 | */ | ||
270 | pReq = (Config_t *)mf; | ||
271 | |||
272 | req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); | ||
273 | frameOffset = ioc->req_sz - sizeof(IOCPage4_t); | ||
274 | |||
275 | /* Complete the request frame (same for all requests). | ||
276 | */ | ||
277 | pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; | ||
278 | pReq->Reserved = 0; | ||
279 | pReq->ChainOffset = 0; | ||
280 | pReq->Function = MPI_FUNCTION_CONFIG; | ||
281 | pReq->ExtPageLength = 0; | ||
282 | pReq->ExtPageType = 0; | ||
283 | pReq->MsgFlags = 0; | ||
284 | for (ii=0; ii < 8; ii++) { | ||
285 | pReq->Reserved2[ii] = 0; | ||
286 | } | ||
287 | |||
288 | IOCPage4Ptr = ioc->spi_data.pIocPg4; | ||
289 | dataDma = ioc->spi_data.IocPg4_dma; | ||
290 | ii = IOCPage4Ptr->ActiveSEP++; | ||
291 | IOCPage4Ptr->SEP[ii].SEPTargetID = id; | ||
292 | IOCPage4Ptr->SEP[ii].SEPBus = channel; | ||
293 | pReq->Header = IOCPage4Ptr->Header; | ||
294 | pReq->PageAddress = cpu_to_le32(id | (channel << 8 )); | ||
295 | |||
296 | /* Add a SGE to the config request. | ||
297 | */ | ||
298 | flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE | | ||
299 | (IOCPage4Ptr->Header.PageLength + ii) * 4; | ||
300 | |||
301 | mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma); | ||
302 | |||
303 | ddvprintk((MYIOC_s_INFO_FMT | ||
304 | "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n", | ||
305 | ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel)); | ||
306 | |||
307 | mpt_put_msg_frame(ioc->DoneCtx, ioc, mf); | ||
308 | |||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | /** | ||
313 | * mptspi_initTarget - Target, LUN alloc/free functionality. | ||
314 | * @hd: Pointer to MPT_SCSI_HOST structure | ||
315 | * @vtarget: per target private data | ||
316 | * @sdev: SCSI device | ||
317 | * | ||
318 | * NOTE: It's only SAFE to call this routine if data points to | ||
319 | * sane & valid STANDARD INQUIRY data! | ||
320 | * | ||
321 | * Allocate and initialize memory for this target. | ||
322 | * Save inquiry data. | ||
323 | * | ||
324 | **/ | ||
325 | static void | ||
326 | mptspi_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget, | ||
327 | struct scsi_device *sdev) | ||
328 | { | ||
329 | |||
330 | /* Is LUN supported? If so, upper 2 bits will be 0 | ||
331 | * in first byte of inquiry data. | ||
332 | */ | ||
333 | if (sdev->inq_periph_qual != 0) | ||
334 | return; | ||
335 | |||
336 | if (vtarget == NULL) | ||
337 | return; | ||
338 | |||
339 | vtarget->type = sdev->type; | ||
340 | |||
341 | if ((sdev->type == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) { | ||
342 | /* Treat all Processors as SAF-TE if | ||
343 | * command line option is set */ | ||
344 | vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED; | ||
345 | mptspi_writeIOCPage4(hd, vtarget->channel, vtarget->id); | ||
346 | }else if ((sdev->type == TYPE_PROCESSOR) && | ||
347 | !(vtarget->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) { | ||
348 | if (sdev->inquiry_len > 49 ) { | ||
349 | if (sdev->inquiry[44] == 'S' && | ||
350 | sdev->inquiry[45] == 'A' && | ||
351 | sdev->inquiry[46] == 'F' && | ||
352 | sdev->inquiry[47] == '-' && | ||
353 | sdev->inquiry[48] == 'T' && | ||
354 | sdev->inquiry[49] == 'E' ) { | ||
355 | vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED; | ||
356 | mptspi_writeIOCPage4(hd, vtarget->channel, vtarget->id); | ||
357 | } | ||
358 | } | ||
359 | } | ||
360 | mptspi_setTargetNegoParms(hd, vtarget, sdev); | ||
361 | } | ||
362 | |||
363 | /** | ||
364 | * mptspi_is_raid - Determines whether target is belonging to volume | ||
365 | * @hd: Pointer to a SCSI HOST structure | ||
366 | * @id: target device id | ||
367 | * | ||
368 | * Return: | ||
369 | * non-zero = true | ||
370 | * zero = false | ||
371 | * | ||
372 | */ | ||
373 | static int | ||
374 | mptspi_is_raid(struct _MPT_SCSI_HOST *hd, u32 id) | ||
375 | { | ||
376 | int i, rc = 0; | ||
377 | |||
378 | if (!hd->ioc->raid_data.pIocPg2) | ||
379 | goto out; | ||
380 | |||
381 | if (!hd->ioc->raid_data.pIocPg2->NumActiveVolumes) | ||
382 | goto out; | ||
383 | for (i=0; i < hd->ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { | ||
384 | if (hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) { | ||
385 | rc = 1; | ||
386 | goto out; | ||
387 | } | ||
388 | } | ||
389 | |||
390 | out: | ||
391 | return rc; | ||
392 | } | ||
393 | |||
98 | static int mptspi_target_alloc(struct scsi_target *starget) | 394 | static int mptspi_target_alloc(struct scsi_target *starget) |
99 | { | 395 | { |
100 | struct Scsi_Host *shost = dev_to_shost(&starget->dev); | 396 | struct Scsi_Host *shost = dev_to_shost(&starget->dev); |
101 | struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata; | 397 | struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata; |
102 | int ret; | 398 | VirtTarget *vtarget; |
103 | 399 | ||
104 | if (hd == NULL) | 400 | if (hd == NULL) |
105 | return -ENODEV; | 401 | return -ENODEV; |
106 | 402 | ||
107 | ret = mptscsih_target_alloc(starget); | 403 | vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL); |
108 | if (ret) | 404 | if (!vtarget) |
109 | return ret; | 405 | return -ENOMEM; |
406 | |||
407 | vtarget->ioc_id = hd->ioc->id; | ||
408 | vtarget->tflags = MPT_TARGET_FLAGS_Q_YES; | ||
409 | vtarget->id = (u8)starget->id; | ||
410 | vtarget->channel = (u8)starget->channel; | ||
411 | vtarget->starget = starget; | ||
412 | starget->hostdata = vtarget; | ||
413 | |||
414 | if (starget->channel == 1) { | ||
415 | if (mptscsih_is_phys_disk(hd->ioc, 0, starget->id) == 0) | ||
416 | return 0; | ||
417 | vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; | ||
418 | /* The real channel for this device is zero */ | ||
419 | vtarget->channel = 0; | ||
420 | /* The actual physdisknum (for RAID passthrough) */ | ||
421 | vtarget->id = mptscsih_raid_id_to_num(hd->ioc, 0, | ||
422 | starget->id); | ||
423 | } | ||
110 | 424 | ||
111 | /* if we're a device on virtual channel 1 and we're not part | 425 | if (starget->channel == 0 && |
112 | * of an array, just return here (otherwise the setup below | 426 | mptspi_is_raid(hd, starget->id)) { |
113 | * may actually affect a real physical device on channel 0 */ | 427 | vtarget->raidVolume = 1; |
114 | if (starget->channel == 1 && | 428 | ddvprintk((KERN_INFO |
115 | mptscsih_raid_id_to_num(hd, starget->id) < 0) | 429 | "RAID Volume @ channel=%d id=%d\n", starget->channel, |
116 | return 0; | 430 | starget->id)); |
431 | } | ||
117 | 432 | ||
118 | if (hd->ioc->spi_data.nvram && | 433 | if (hd->ioc->spi_data.nvram && |
119 | hd->ioc->spi_data.nvram[starget->id] != MPT_HOST_NVRAM_INVALID) { | 434 | hd->ioc->spi_data.nvram[starget->id] != MPT_HOST_NVRAM_INVALID) { |
@@ -132,6 +447,64 @@ static int mptspi_target_alloc(struct scsi_target *starget) | |||
132 | return 0; | 447 | return 0; |
133 | } | 448 | } |
134 | 449 | ||
450 | void | ||
451 | mptspi_target_destroy(struct scsi_target *starget) | ||
452 | { | ||
453 | if (starget->hostdata) | ||
454 | kfree(starget->hostdata); | ||
455 | starget->hostdata = NULL; | ||
456 | } | ||
457 | |||
458 | /** | ||
459 | * mptspi_print_write_nego - negotiation parameters debug info that is being sent | ||
460 | * @hd: Pointer to a SCSI HOST structure | ||
461 | * @starget: SCSI target | ||
462 | * @ii: negotiation parameters | ||
463 | * | ||
464 | */ | ||
465 | static void | ||
466 | mptspi_print_write_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u32 ii) | ||
467 | { | ||
468 | ddvprintk((MYIOC_s_INFO_FMT "id=%d Requested = 0x%08x" | ||
469 | " ( %s factor = 0x%02x @ offset = 0x%02x %s%s%s%s%s%s%s%s)\n", | ||
470 | hd->ioc->name, starget->id, ii, | ||
471 | ii & MPI_SCSIDEVPAGE0_NP_WIDE ? "Wide ": "", | ||
472 | ((ii >> 8) & 0xFF), ((ii >> 16) & 0xFF), | ||
473 | ii & MPI_SCSIDEVPAGE0_NP_IU ? "IU ": "", | ||
474 | ii & MPI_SCSIDEVPAGE0_NP_DT ? "DT ": "", | ||
475 | ii & MPI_SCSIDEVPAGE0_NP_QAS ? "QAS ": "", | ||
476 | ii & MPI_SCSIDEVPAGE0_NP_HOLD_MCS ? "HOLDMCS ": "", | ||
477 | ii & MPI_SCSIDEVPAGE0_NP_WR_FLOW ? "WRFLOW ": "", | ||
478 | ii & MPI_SCSIDEVPAGE0_NP_RD_STRM ? "RDSTRM ": "", | ||
479 | ii & MPI_SCSIDEVPAGE0_NP_RTI ? "RTI ": "", | ||
480 | ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": "")); | ||
481 | } | ||
482 | |||
483 | /** | ||
484 | * mptspi_print_read_nego - negotiation parameters debug info that is being read | ||
485 | * @hd: Pointer to a SCSI HOST structure | ||
486 | * @starget: SCSI target | ||
487 | * @ii: negotiation parameters | ||
488 | * | ||
489 | */ | ||
490 | static void | ||
491 | mptspi_print_read_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u32 ii) | ||
492 | { | ||
493 | ddvprintk((MYIOC_s_INFO_FMT "id=%d Read = 0x%08x" | ||
494 | " ( %s factor = 0x%02x @ offset = 0x%02x %s%s%s%s%s%s%s%s)\n", | ||
495 | hd->ioc->name, starget->id, ii, | ||
496 | ii & MPI_SCSIDEVPAGE0_NP_WIDE ? "Wide ": "", | ||
497 | ((ii >> 8) & 0xFF), ((ii >> 16) & 0xFF), | ||
498 | ii & MPI_SCSIDEVPAGE0_NP_IU ? "IU ": "", | ||
499 | ii & MPI_SCSIDEVPAGE0_NP_DT ? "DT ": "", | ||
500 | ii & MPI_SCSIDEVPAGE0_NP_QAS ? "QAS ": "", | ||
501 | ii & MPI_SCSIDEVPAGE0_NP_HOLD_MCS ? "HOLDMCS ": "", | ||
502 | ii & MPI_SCSIDEVPAGE0_NP_WR_FLOW ? "WRFLOW ": "", | ||
503 | ii & MPI_SCSIDEVPAGE0_NP_RD_STRM ? "RDSTRM ": "", | ||
504 | ii & MPI_SCSIDEVPAGE0_NP_RTI ? "RTI ": "", | ||
505 | ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": "")); | ||
506 | } | ||
507 | |||
135 | static int mptspi_read_spi_device_pg0(struct scsi_target *starget, | 508 | static int mptspi_read_spi_device_pg0(struct scsi_target *starget, |
136 | struct _CONFIG_PAGE_SCSI_DEVICE_0 *pass_pg0) | 509 | struct _CONFIG_PAGE_SCSI_DEVICE_0 *pass_pg0) |
137 | { | 510 | { |
@@ -147,7 +520,7 @@ static int mptspi_read_spi_device_pg0(struct scsi_target *starget, | |||
147 | 520 | ||
148 | /* No SPI parameters for RAID devices */ | 521 | /* No SPI parameters for RAID devices */ |
149 | if (starget->channel == 0 && | 522 | if (starget->channel == 0 && |
150 | (hd->ioc->raid_data.isRaid & (1 << starget->id))) | 523 | mptspi_is_raid(hd, starget->id)) |
151 | return -1; | 524 | return -1; |
152 | 525 | ||
153 | size = ioc->spi_data.sdp0length * 4; | 526 | size = ioc->spi_data.sdp0length * 4; |
@@ -185,6 +558,8 @@ static int mptspi_read_spi_device_pg0(struct scsi_target *starget, | |||
185 | err = 0; | 558 | err = 0; |
186 | memcpy(pass_pg0, pg0, size); | 559 | memcpy(pass_pg0, pg0, size); |
187 | 560 | ||
561 | mptspi_print_read_nego(hd, starget, le32_to_cpu(pg0->NegotiatedParameters)); | ||
562 | |||
188 | out_free: | 563 | out_free: |
189 | dma_free_coherent(&ioc->pcidev->dev, size, pg0, pg0_dma); | 564 | dma_free_coherent(&ioc->pcidev->dev, size, pg0, pg0_dma); |
190 | return err; | 565 | return err; |
@@ -233,7 +608,7 @@ static void mptspi_read_parameters(struct scsi_target *starget) | |||
233 | } | 608 | } |
234 | 609 | ||
235 | static int | 610 | static int |
236 | mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, int disk) | 611 | mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id) |
237 | { | 612 | { |
238 | MpiRaidActionRequest_t *pReq; | 613 | MpiRaidActionRequest_t *pReq; |
239 | MPT_FRAME_HDR *mf; | 614 | MPT_FRAME_HDR *mf; |
@@ -253,8 +628,8 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, int disk) | |||
253 | pReq->Reserved1 = 0; | 628 | pReq->Reserved1 = 0; |
254 | pReq->ChainOffset = 0; | 629 | pReq->ChainOffset = 0; |
255 | pReq->Function = MPI_FUNCTION_RAID_ACTION; | 630 | pReq->Function = MPI_FUNCTION_RAID_ACTION; |
256 | pReq->VolumeID = disk; | 631 | pReq->VolumeID = id; |
257 | pReq->VolumeBus = 0; | 632 | pReq->VolumeBus = channel; |
258 | pReq->PhysDiskNum = 0; | 633 | pReq->PhysDiskNum = 0; |
259 | pReq->MsgFlags = 0; | 634 | pReq->MsgFlags = 0; |
260 | pReq->Reserved2 = 0; | 635 | pReq->Reserved2 = 0; |
@@ -263,8 +638,8 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, int disk) | |||
263 | mpt_add_sge((char *)&pReq->ActionDataSGE, | 638 | mpt_add_sge((char *)&pReq->ActionDataSGE, |
264 | MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1); | 639 | MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1); |
265 | 640 | ||
266 | ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action %x id %d\n", | 641 | ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action=%x channel=%d id=%d\n", |
267 | hd->ioc->name, action, io->id)); | 642 | hd->ioc->name, pReq->Action, channel, id)); |
268 | 643 | ||
269 | hd->pLocal = NULL; | 644 | hd->pLocal = NULL; |
270 | hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */ | 645 | hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */ |
@@ -292,12 +667,12 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd, | |||
292 | 667 | ||
293 | /* no DV on RAID devices */ | 668 | /* no DV on RAID devices */ |
294 | if (sdev->channel == 0 && | 669 | if (sdev->channel == 0 && |
295 | (hd->ioc->raid_data.isRaid & (1 << sdev->id))) | 670 | mptspi_is_raid(hd, sdev->id)) |
296 | return; | 671 | return; |
297 | 672 | ||
298 | /* If this is a piece of a RAID, then quiesce first */ | 673 | /* If this is a piece of a RAID, then quiesce first */ |
299 | if (sdev->channel == 1 && | 674 | if (sdev->channel == 1 && |
300 | mptscsih_quiesce_raid(hd, 1, vtarget->target_id) < 0) { | 675 | mptscsih_quiesce_raid(hd, 1, vtarget->channel, vtarget->id) < 0) { |
301 | starget_printk(KERN_ERR, scsi_target(sdev), | 676 | starget_printk(KERN_ERR, scsi_target(sdev), |
302 | "Integrated RAID quiesce failed\n"); | 677 | "Integrated RAID quiesce failed\n"); |
303 | return; | 678 | return; |
@@ -306,7 +681,7 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd, | |||
306 | spi_dv_device(sdev); | 681 | spi_dv_device(sdev); |
307 | 682 | ||
308 | if (sdev->channel == 1 && | 683 | if (sdev->channel == 1 && |
309 | mptscsih_quiesce_raid(hd, 0, vtarget->target_id) < 0) | 684 | mptscsih_quiesce_raid(hd, 0, vtarget->channel, vtarget->id) < 0) |
310 | starget_printk(KERN_ERR, scsi_target(sdev), | 685 | starget_printk(KERN_ERR, scsi_target(sdev), |
311 | "Integrated RAID resume failed\n"); | 686 | "Integrated RAID resume failed\n"); |
312 | 687 | ||
@@ -317,54 +692,89 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd, | |||
317 | 692 | ||
318 | static int mptspi_slave_alloc(struct scsi_device *sdev) | 693 | static int mptspi_slave_alloc(struct scsi_device *sdev) |
319 | { | 694 | { |
320 | int ret; | ||
321 | MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata; | 695 | MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata; |
322 | /* gcc doesn't see that all uses of this variable occur within | 696 | VirtTarget *vtarget; |
323 | * the if() statements, so stop it from whining */ | 697 | VirtDevice *vdev; |
324 | int physdisknum = 0; | 698 | struct scsi_target *starget; |
325 | |||
326 | if (sdev->channel == 1) { | ||
327 | physdisknum = mptscsih_raid_id_to_num(hd, sdev->id); | ||
328 | 699 | ||
329 | if (physdisknum < 0) | 700 | if (sdev->channel == 1 && |
330 | return physdisknum; | 701 | mptscsih_is_phys_disk(hd->ioc, 0, sdev->id) == 0) |
702 | return -ENXIO; | ||
703 | |||
704 | vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL); | ||
705 | if (!vdev) { | ||
706 | printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", | ||
707 | hd->ioc->name, sizeof(VirtDevice)); | ||
708 | return -ENOMEM; | ||
331 | } | 709 | } |
332 | 710 | ||
333 | ret = mptscsih_slave_alloc(sdev); | 711 | vdev->lun = sdev->lun; |
712 | sdev->hostdata = vdev; | ||
334 | 713 | ||
335 | if (ret) | 714 | starget = scsi_target(sdev); |
336 | return ret; | 715 | vtarget = starget->hostdata; |
716 | vdev->vtarget = vtarget; | ||
717 | vtarget->num_luns++; | ||
337 | 718 | ||
338 | if (sdev->channel == 1) { | 719 | if (sdev->channel == 1) |
339 | VirtDevice *vdev = sdev->hostdata; | ||
340 | sdev->no_uld_attach = 1; | 720 | sdev->no_uld_attach = 1; |
341 | vdev->vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; | ||
342 | /* The real channel for this device is zero */ | ||
343 | vdev->vtarget->bus_id = 0; | ||
344 | /* The actual physdisknum (for RAID passthrough) */ | ||
345 | vdev->vtarget->target_id = physdisknum; | ||
346 | } | ||
347 | 721 | ||
348 | return 0; | 722 | return 0; |
349 | } | 723 | } |
350 | 724 | ||
351 | static int mptspi_slave_configure(struct scsi_device *sdev) | 725 | static int mptspi_slave_configure(struct scsi_device *sdev) |
352 | { | 726 | { |
353 | int ret = mptscsih_slave_configure(sdev); | ||
354 | struct _MPT_SCSI_HOST *hd = | 727 | struct _MPT_SCSI_HOST *hd = |
355 | (struct _MPT_SCSI_HOST *)sdev->host->hostdata; | 728 | (struct _MPT_SCSI_HOST *)sdev->host->hostdata; |
729 | VirtTarget *vtarget = scsi_target(sdev)->hostdata; | ||
730 | int ret = mptscsih_slave_configure(sdev); | ||
356 | 731 | ||
357 | if (ret) | 732 | if (ret) |
358 | return ret; | 733 | return ret; |
359 | 734 | ||
735 | mptspi_initTarget(hd, vtarget, sdev); | ||
736 | |||
737 | ddvprintk((MYIOC_s_INFO_FMT "id=%d min_period=0x%02x" | ||
738 | " max_offset=0x%02x max_width=%d\n", hd->ioc->name, | ||
739 | sdev->id, spi_min_period(scsi_target(sdev)), | ||
740 | spi_max_offset(scsi_target(sdev)), | ||
741 | spi_max_width(scsi_target(sdev)))); | ||
742 | |||
360 | if ((sdev->channel == 1 || | 743 | if ((sdev->channel == 1 || |
361 | !(hd->ioc->raid_data.isRaid & (1 << sdev->id))) && | 744 | !(mptspi_is_raid(hd, sdev->id))) && |
362 | !spi_initial_dv(sdev->sdev_target)) | 745 | !spi_initial_dv(sdev->sdev_target)) |
363 | mptspi_dv_device(hd, sdev); | 746 | mptspi_dv_device(hd, sdev); |
364 | 747 | ||
365 | return 0; | 748 | return 0; |
366 | } | 749 | } |
367 | 750 | ||
751 | static int | ||
752 | mptspi_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) | ||
753 | { | ||
754 | struct _MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata; | ||
755 | VirtDevice *vdev = SCpnt->device->hostdata; | ||
756 | |||
757 | if (!vdev || !vdev->vtarget) { | ||
758 | SCpnt->result = DID_NO_CONNECT << 16; | ||
759 | done(SCpnt); | ||
760 | return 0; | ||
761 | } | ||
762 | |||
763 | if (SCpnt->device->channel == 1 && | ||
764 | mptscsih_is_phys_disk(hd->ioc, 0, SCpnt->device->id) == 0) { | ||
765 | SCpnt->result = DID_NO_CONNECT << 16; | ||
766 | done(SCpnt); | ||
767 | return 0; | ||
768 | } | ||
769 | |||
770 | #ifdef MPT_DEBUG_DV | ||
771 | if (spi_dv_pending(scsi_target(SCpnt->device))) | ||
772 | scsi_print_command(SCpnt); | ||
773 | #endif | ||
774 | |||
775 | return mptscsih_qcmd(SCpnt,done); | ||
776 | } | ||
777 | |||
368 | static void mptspi_slave_destroy(struct scsi_device *sdev) | 778 | static void mptspi_slave_destroy(struct scsi_device *sdev) |
369 | { | 779 | { |
370 | struct scsi_target *starget = scsi_target(sdev); | 780 | struct scsi_target *starget = scsi_target(sdev); |
@@ -392,11 +802,11 @@ static struct scsi_host_template mptspi_driver_template = { | |||
392 | .proc_info = mptscsih_proc_info, | 802 | .proc_info = mptscsih_proc_info, |
393 | .name = "MPT SPI Host", | 803 | .name = "MPT SPI Host", |
394 | .info = mptscsih_info, | 804 | .info = mptscsih_info, |
395 | .queuecommand = mptscsih_qcmd, | 805 | .queuecommand = mptspi_qcmd, |
396 | .target_alloc = mptspi_target_alloc, | 806 | .target_alloc = mptspi_target_alloc, |
397 | .slave_alloc = mptspi_slave_alloc, | 807 | .slave_alloc = mptspi_slave_alloc, |
398 | .slave_configure = mptspi_slave_configure, | 808 | .slave_configure = mptspi_slave_configure, |
399 | .target_destroy = mptscsih_target_destroy, | 809 | .target_destroy = mptspi_target_destroy, |
400 | .slave_destroy = mptspi_slave_destroy, | 810 | .slave_destroy = mptspi_slave_destroy, |
401 | .change_queue_depth = mptscsih_change_queue_depth, | 811 | .change_queue_depth = mptscsih_change_queue_depth, |
402 | .eh_abort_handler = mptscsih_abort, | 812 | .eh_abort_handler = mptscsih_abort, |
@@ -427,7 +837,7 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget, | |||
427 | 837 | ||
428 | /* don't allow updating nego parameters on RAID devices */ | 838 | /* don't allow updating nego parameters on RAID devices */ |
429 | if (starget->channel == 0 && | 839 | if (starget->channel == 0 && |
430 | (hd->ioc->raid_data.isRaid & (1 << starget->id))) | 840 | mptspi_is_raid(hd, starget->id)) |
431 | return -1; | 841 | return -1; |
432 | 842 | ||
433 | size = ioc->spi_data.sdp1length * 4; | 843 | size = ioc->spi_data.sdp1length * 4; |
@@ -460,6 +870,8 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget, | |||
460 | pg1->Header.PageNumber = hdr.PageNumber; | 870 | pg1->Header.PageNumber = hdr.PageNumber; |
461 | pg1->Header.PageType = hdr.PageType; | 871 | pg1->Header.PageType = hdr.PageType; |
462 | 872 | ||
873 | mptspi_print_write_nego(hd, starget, le32_to_cpu(pg1->RequestedParameters)); | ||
874 | |||
463 | if (mpt_config(ioc, &cfg)) { | 875 | if (mpt_config(ioc, &cfg)) { |
464 | starget_printk(KERN_ERR, starget, "mpt_config failed\n"); | 876 | starget_printk(KERN_ERR, starget, "mpt_config failed\n"); |
465 | goto out_free; | 877 | goto out_free; |
@@ -672,9 +1084,9 @@ static void mpt_work_wrapper(struct work_struct *work) | |||
672 | if (sdev->channel != 1) | 1084 | if (sdev->channel != 1) |
673 | continue; | 1085 | continue; |
674 | 1086 | ||
675 | /* The target_id is the raid PhysDiskNum, even if | 1087 | /* The id is the raid PhysDiskNum, even if |
676 | * starget->id is the actual target address */ | 1088 | * starget->id is the actual target address */ |
677 | if(vtarget->target_id != disk) | 1089 | if(vtarget->id != disk) |
678 | continue; | 1090 | continue; |
679 | 1091 | ||
680 | starget_printk(KERN_INFO, vtarget->starget, | 1092 | starget_printk(KERN_INFO, vtarget->starget, |
@@ -727,7 +1139,7 @@ mptspi_deny_binding(struct scsi_target *starget) | |||
727 | { | 1139 | { |
728 | struct _MPT_SCSI_HOST *hd = | 1140 | struct _MPT_SCSI_HOST *hd = |
729 | (struct _MPT_SCSI_HOST *)dev_to_shost(starget->dev.parent)->hostdata; | 1141 | (struct _MPT_SCSI_HOST *)dev_to_shost(starget->dev.parent)->hostdata; |
730 | return ((hd->ioc->raid_data.isRaid & (1 << starget->id)) && | 1142 | return ((mptspi_is_raid(hd, starget->id)) && |
731 | starget->channel == 0) ? 1 : 0; | 1143 | starget->channel == 0) ? 1 : 0; |
732 | } | 1144 | } |
733 | 1145 | ||
@@ -945,14 +1357,13 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
945 | * max_lun = 1 + actual last lun, | 1357 | * max_lun = 1 + actual last lun, |
946 | * see hosts.h :o( | 1358 | * see hosts.h :o( |
947 | */ | 1359 | */ |
948 | sh->max_id = MPT_MAX_SCSI_DEVICES; | 1360 | sh->max_id = ioc->devices_per_bus; |
949 | 1361 | ||
950 | sh->max_lun = MPT_LAST_LUN + 1; | 1362 | sh->max_lun = MPT_LAST_LUN + 1; |
951 | /* | 1363 | /* |
952 | * If RAID Firmware Detected, setup virtual channel | 1364 | * If RAID Firmware Detected, setup virtual channel |
953 | */ | 1365 | */ |
954 | if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK) | 1366 | if (ioc->ir_firmware) |
955 | > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) | ||
956 | sh->max_channel = 1; | 1367 | sh->max_channel = 1; |
957 | else | 1368 | else |
958 | sh->max_channel = 0; | 1369 | sh->max_channel = 0; |
@@ -1009,20 +1420,6 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
1009 | dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n", | 1420 | dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n", |
1010 | ioc->name, hd->ScsiLookup)); | 1421 | ioc->name, hd->ScsiLookup)); |
1011 | 1422 | ||
1012 | /* Allocate memory for the device structures. | ||
1013 | * A non-Null pointer at an offset | ||
1014 | * indicates a device exists. | ||
1015 | * max_id = 1 + maximum id (hosts.h) | ||
1016 | */ | ||
1017 | hd->Targets = kcalloc(sh->max_id * (sh->max_channel + 1), | ||
1018 | sizeof(void *), GFP_ATOMIC); | ||
1019 | if (!hd->Targets) { | ||
1020 | error = -ENOMEM; | ||
1021 | goto out_mptspi_probe; | ||
1022 | } | ||
1023 | |||
1024 | dprintk((KERN_INFO " vdev @ %p\n", hd->Targets)); | ||
1025 | |||
1026 | /* Clear the TM flags | 1423 | /* Clear the TM flags |
1027 | */ | 1424 | */ |
1028 | hd->tmPending = 0; | 1425 | hd->tmPending = 0; |