diff options
Diffstat (limited to 'drivers/message/fusion/mptspi.c')
-rw-r--r-- | drivers/message/fusion/mptspi.c | 188 |
1 files changed, 127 insertions, 61 deletions
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index 203c661d2c79..aec0c2fe221f 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c | |||
@@ -95,25 +95,76 @@ static int mptspiDoneCtx = -1; | |||
95 | static int mptspiTaskCtx = -1; | 95 | static int mptspiTaskCtx = -1; |
96 | static int mptspiInternalCtx = -1; /* Used only for internal commands */ | 96 | static int mptspiInternalCtx = -1; /* Used only for internal commands */ |
97 | 97 | ||
98 | |||
99 | /** | ||
100 | * mptspi_is_raid - Determines whether target is belonging to volume | ||
101 | * @hd: Pointer to a SCSI HOST structure | ||
102 | * @id: target device id | ||
103 | * | ||
104 | * Return: | ||
105 | * non-zero = true | ||
106 | * zero = false | ||
107 | * | ||
108 | */ | ||
109 | static int | ||
110 | mptspi_is_raid(struct _MPT_SCSI_HOST *hd, u32 id) | ||
111 | { | ||
112 | int i, rc = 0; | ||
113 | |||
114 | if (!hd->ioc->raid_data.pIocPg2) | ||
115 | goto out; | ||
116 | |||
117 | if (!hd->ioc->raid_data.pIocPg2->NumActiveVolumes) | ||
118 | goto out; | ||
119 | for (i=0; i < hd->ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { | ||
120 | if (hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) { | ||
121 | rc = 1; | ||
122 | goto out; | ||
123 | } | ||
124 | } | ||
125 | |||
126 | out: | ||
127 | return rc; | ||
128 | } | ||
129 | |||
98 | static int mptspi_target_alloc(struct scsi_target *starget) | 130 | static int mptspi_target_alloc(struct scsi_target *starget) |
99 | { | 131 | { |
100 | struct Scsi_Host *shost = dev_to_shost(&starget->dev); | 132 | struct Scsi_Host *shost = dev_to_shost(&starget->dev); |
101 | struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata; | 133 | struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata; |
102 | int ret; | 134 | VirtTarget *vtarget; |
103 | 135 | ||
104 | if (hd == NULL) | 136 | if (hd == NULL) |
105 | return -ENODEV; | 137 | return -ENODEV; |
106 | 138 | ||
107 | ret = mptscsih_target_alloc(starget); | 139 | vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL); |
108 | if (ret) | 140 | if (!vtarget) |
109 | return ret; | 141 | return -ENOMEM; |
142 | |||
143 | vtarget->ioc_id = hd->ioc->id; | ||
144 | vtarget->tflags = MPT_TARGET_FLAGS_Q_YES; | ||
145 | vtarget->id = (u8)starget->id; | ||
146 | vtarget->channel = (u8)starget->channel; | ||
147 | vtarget->starget = starget; | ||
148 | starget->hostdata = vtarget; | ||
149 | |||
150 | if (starget->channel == 1) { | ||
151 | if (mptscsih_is_phys_disk(hd->ioc, 0, starget->id) == 0) | ||
152 | return 0; | ||
153 | vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; | ||
154 | /* The real channel for this device is zero */ | ||
155 | vtarget->channel = 0; | ||
156 | /* The actual physdisknum (for RAID passthrough) */ | ||
157 | vtarget->id = mptscsih_raid_id_to_num(hd->ioc, 0, | ||
158 | starget->id); | ||
159 | } | ||
110 | 160 | ||
111 | /* if we're a device on virtual channel 1 and we're not part | 161 | if (starget->channel == 0 && |
112 | * of an array, just return here (otherwise the setup below | 162 | mptspi_is_raid(hd, starget->id)) { |
113 | * may actually affect a real physical device on channel 0 */ | 163 | vtarget->raidVolume = 1; |
114 | if (starget->channel == 1 && | 164 | ddvprintk((KERN_INFO |
115 | mptscsih_raid_id_to_num(hd, starget->id) < 0) | 165 | "RAID Volume @ channel=%d id=%d\n", starget->channel, |
116 | return 0; | 166 | starget->id)); |
167 | } | ||
117 | 168 | ||
118 | if (hd->ioc->spi_data.nvram && | 169 | if (hd->ioc->spi_data.nvram && |
119 | hd->ioc->spi_data.nvram[starget->id] != MPT_HOST_NVRAM_INVALID) { | 170 | hd->ioc->spi_data.nvram[starget->id] != MPT_HOST_NVRAM_INVALID) { |
@@ -132,6 +183,14 @@ static int mptspi_target_alloc(struct scsi_target *starget) | |||
132 | return 0; | 183 | return 0; |
133 | } | 184 | } |
134 | 185 | ||
186 | void | ||
187 | mptspi_target_destroy(struct scsi_target *starget) | ||
188 | { | ||
189 | if (starget->hostdata) | ||
190 | kfree(starget->hostdata); | ||
191 | starget->hostdata = NULL; | ||
192 | } | ||
193 | |||
135 | static int mptspi_read_spi_device_pg0(struct scsi_target *starget, | 194 | static int mptspi_read_spi_device_pg0(struct scsi_target *starget, |
136 | struct _CONFIG_PAGE_SCSI_DEVICE_0 *pass_pg0) | 195 | struct _CONFIG_PAGE_SCSI_DEVICE_0 *pass_pg0) |
137 | { | 196 | { |
@@ -147,7 +206,7 @@ static int mptspi_read_spi_device_pg0(struct scsi_target *starget, | |||
147 | 206 | ||
148 | /* No SPI parameters for RAID devices */ | 207 | /* No SPI parameters for RAID devices */ |
149 | if (starget->channel == 0 && | 208 | if (starget->channel == 0 && |
150 | (hd->ioc->raid_data.isRaid & (1 << starget->id))) | 209 | mptspi_is_raid(hd, starget->id)) |
151 | return -1; | 210 | return -1; |
152 | 211 | ||
153 | size = ioc->spi_data.sdp0length * 4; | 212 | size = ioc->spi_data.sdp0length * 4; |
@@ -233,7 +292,7 @@ static void mptspi_read_parameters(struct scsi_target *starget) | |||
233 | } | 292 | } |
234 | 293 | ||
235 | static int | 294 | static int |
236 | mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, int disk) | 295 | mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id) |
237 | { | 296 | { |
238 | MpiRaidActionRequest_t *pReq; | 297 | MpiRaidActionRequest_t *pReq; |
239 | MPT_FRAME_HDR *mf; | 298 | MPT_FRAME_HDR *mf; |
@@ -253,8 +312,8 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, int disk) | |||
253 | pReq->Reserved1 = 0; | 312 | pReq->Reserved1 = 0; |
254 | pReq->ChainOffset = 0; | 313 | pReq->ChainOffset = 0; |
255 | pReq->Function = MPI_FUNCTION_RAID_ACTION; | 314 | pReq->Function = MPI_FUNCTION_RAID_ACTION; |
256 | pReq->VolumeID = disk; | 315 | pReq->VolumeID = id; |
257 | pReq->VolumeBus = 0; | 316 | pReq->VolumeBus = channel; |
258 | pReq->PhysDiskNum = 0; | 317 | pReq->PhysDiskNum = 0; |
259 | pReq->MsgFlags = 0; | 318 | pReq->MsgFlags = 0; |
260 | pReq->Reserved2 = 0; | 319 | pReq->Reserved2 = 0; |
@@ -263,8 +322,8 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, int disk) | |||
263 | mpt_add_sge((char *)&pReq->ActionDataSGE, | 322 | mpt_add_sge((char *)&pReq->ActionDataSGE, |
264 | MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1); | 323 | MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1); |
265 | 324 | ||
266 | ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action %x id %d\n", | 325 | ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action=%x channel=%d id=%d\n", |
267 | hd->ioc->name, action, io->id)); | 326 | hd->ioc->name, pReq->Action, channel, id)); |
268 | 327 | ||
269 | hd->pLocal = NULL; | 328 | hd->pLocal = NULL; |
270 | hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */ | 329 | hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */ |
@@ -292,12 +351,12 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd, | |||
292 | 351 | ||
293 | /* no DV on RAID devices */ | 352 | /* no DV on RAID devices */ |
294 | if (sdev->channel == 0 && | 353 | if (sdev->channel == 0 && |
295 | (hd->ioc->raid_data.isRaid & (1 << sdev->id))) | 354 | mptspi_is_raid(hd, sdev->id)) |
296 | return; | 355 | return; |
297 | 356 | ||
298 | /* If this is a piece of a RAID, then quiesce first */ | 357 | /* If this is a piece of a RAID, then quiesce first */ |
299 | if (sdev->channel == 1 && | 358 | if (sdev->channel == 1 && |
300 | mptscsih_quiesce_raid(hd, 1, vtarget->target_id) < 0) { | 359 | mptscsih_quiesce_raid(hd, 1, vtarget->channel, vtarget->id) < 0) { |
301 | starget_printk(KERN_ERR, scsi_target(sdev), | 360 | starget_printk(KERN_ERR, scsi_target(sdev), |
302 | "Integrated RAID quiesce failed\n"); | 361 | "Integrated RAID quiesce failed\n"); |
303 | return; | 362 | return; |
@@ -306,7 +365,7 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd, | |||
306 | spi_dv_device(sdev); | 365 | spi_dv_device(sdev); |
307 | 366 | ||
308 | if (sdev->channel == 1 && | 367 | if (sdev->channel == 1 && |
309 | mptscsih_quiesce_raid(hd, 0, vtarget->target_id) < 0) | 368 | mptscsih_quiesce_raid(hd, 0, vtarget->channel, vtarget->id) < 0) |
310 | starget_printk(KERN_ERR, scsi_target(sdev), | 369 | starget_printk(KERN_ERR, scsi_target(sdev), |
311 | "Integrated RAID resume failed\n"); | 370 | "Integrated RAID resume failed\n"); |
312 | 371 | ||
@@ -317,33 +376,32 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd, | |||
317 | 376 | ||
318 | static int mptspi_slave_alloc(struct scsi_device *sdev) | 377 | static int mptspi_slave_alloc(struct scsi_device *sdev) |
319 | { | 378 | { |
320 | int ret; | ||
321 | MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata; | 379 | MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata; |
322 | /* gcc doesn't see that all uses of this variable occur within | 380 | VirtTarget *vtarget; |
323 | * the if() statements, so stop it from whining */ | 381 | VirtDevice *vdev; |
324 | int physdisknum = 0; | 382 | struct scsi_target *starget; |
325 | |||
326 | if (sdev->channel == 1) { | ||
327 | physdisknum = mptscsih_raid_id_to_num(hd, sdev->id); | ||
328 | 383 | ||
329 | if (physdisknum < 0) | 384 | if (sdev->channel == 1 && |
330 | return physdisknum; | 385 | mptscsih_is_phys_disk(hd->ioc, 0, sdev->id) == 0) |
386 | return -ENXIO; | ||
387 | |||
388 | vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL); | ||
389 | if (!vdev) { | ||
390 | printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", | ||
391 | hd->ioc->name, sizeof(VirtDevice)); | ||
392 | return -ENOMEM; | ||
331 | } | 393 | } |
332 | 394 | ||
333 | ret = mptscsih_slave_alloc(sdev); | 395 | vdev->lun = sdev->lun; |
396 | sdev->hostdata = vdev; | ||
334 | 397 | ||
335 | if (ret) | 398 | starget = scsi_target(sdev); |
336 | return ret; | 399 | vtarget = starget->hostdata; |
400 | vdev->vtarget = vtarget; | ||
401 | vtarget->num_luns++; | ||
337 | 402 | ||
338 | if (sdev->channel == 1) { | 403 | if (sdev->channel == 1) |
339 | VirtDevice *vdev = sdev->hostdata; | ||
340 | sdev->no_uld_attach = 1; | 404 | 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 | 405 | ||
348 | return 0; | 406 | return 0; |
349 | } | 407 | } |
@@ -358,13 +416,35 @@ static int mptspi_slave_configure(struct scsi_device *sdev) | |||
358 | return ret; | 416 | return ret; |
359 | 417 | ||
360 | if ((sdev->channel == 1 || | 418 | if ((sdev->channel == 1 || |
361 | !(hd->ioc->raid_data.isRaid & (1 << sdev->id))) && | 419 | !(mptspi_is_raid(hd, sdev->id))) && |
362 | !spi_initial_dv(sdev->sdev_target)) | 420 | !spi_initial_dv(sdev->sdev_target)) |
363 | mptspi_dv_device(hd, sdev); | 421 | mptspi_dv_device(hd, sdev); |
364 | 422 | ||
365 | return 0; | 423 | return 0; |
366 | } | 424 | } |
367 | 425 | ||
426 | static int | ||
427 | mptspi_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) | ||
428 | { | ||
429 | struct _MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata; | ||
430 | VirtDevice *vdev = SCpnt->device->hostdata; | ||
431 | |||
432 | if (!vdev || !vdev->vtarget) { | ||
433 | SCpnt->result = DID_NO_CONNECT << 16; | ||
434 | done(SCpnt); | ||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | if (SCpnt->device->channel == 1 && | ||
439 | mptscsih_is_phys_disk(hd->ioc, 0, SCpnt->device->id) == 0) { | ||
440 | SCpnt->result = DID_NO_CONNECT << 16; | ||
441 | done(SCpnt); | ||
442 | return 0; | ||
443 | } | ||
444 | |||
445 | return mptscsih_qcmd(SCpnt,done); | ||
446 | } | ||
447 | |||
368 | static void mptspi_slave_destroy(struct scsi_device *sdev) | 448 | static void mptspi_slave_destroy(struct scsi_device *sdev) |
369 | { | 449 | { |
370 | struct scsi_target *starget = scsi_target(sdev); | 450 | struct scsi_target *starget = scsi_target(sdev); |
@@ -392,11 +472,11 @@ static struct scsi_host_template mptspi_driver_template = { | |||
392 | .proc_info = mptscsih_proc_info, | 472 | .proc_info = mptscsih_proc_info, |
393 | .name = "MPT SPI Host", | 473 | .name = "MPT SPI Host", |
394 | .info = mptscsih_info, | 474 | .info = mptscsih_info, |
395 | .queuecommand = mptscsih_qcmd, | 475 | .queuecommand = mptspi_qcmd, |
396 | .target_alloc = mptspi_target_alloc, | 476 | .target_alloc = mptspi_target_alloc, |
397 | .slave_alloc = mptspi_slave_alloc, | 477 | .slave_alloc = mptspi_slave_alloc, |
398 | .slave_configure = mptspi_slave_configure, | 478 | .slave_configure = mptspi_slave_configure, |
399 | .target_destroy = mptscsih_target_destroy, | 479 | .target_destroy = mptspi_target_destroy, |
400 | .slave_destroy = mptspi_slave_destroy, | 480 | .slave_destroy = mptspi_slave_destroy, |
401 | .change_queue_depth = mptscsih_change_queue_depth, | 481 | .change_queue_depth = mptscsih_change_queue_depth, |
402 | .eh_abort_handler = mptscsih_abort, | 482 | .eh_abort_handler = mptscsih_abort, |
@@ -427,7 +507,7 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget, | |||
427 | 507 | ||
428 | /* don't allow updating nego parameters on RAID devices */ | 508 | /* don't allow updating nego parameters on RAID devices */ |
429 | if (starget->channel == 0 && | 509 | if (starget->channel == 0 && |
430 | (hd->ioc->raid_data.isRaid & (1 << starget->id))) | 510 | mptspi_is_raid(hd, starget->id)) |
431 | return -1; | 511 | return -1; |
432 | 512 | ||
433 | size = ioc->spi_data.sdp1length * 4; | 513 | size = ioc->spi_data.sdp1length * 4; |
@@ -672,9 +752,9 @@ static void mpt_work_wrapper(struct work_struct *work) | |||
672 | if (sdev->channel != 1) | 752 | if (sdev->channel != 1) |
673 | continue; | 753 | continue; |
674 | 754 | ||
675 | /* The target_id is the raid PhysDiskNum, even if | 755 | /* The id is the raid PhysDiskNum, even if |
676 | * starget->id is the actual target address */ | 756 | * starget->id is the actual target address */ |
677 | if(vtarget->target_id != disk) | 757 | if(vtarget->id != disk) |
678 | continue; | 758 | continue; |
679 | 759 | ||
680 | starget_printk(KERN_INFO, vtarget->starget, | 760 | starget_printk(KERN_INFO, vtarget->starget, |
@@ -727,7 +807,7 @@ mptspi_deny_binding(struct scsi_target *starget) | |||
727 | { | 807 | { |
728 | struct _MPT_SCSI_HOST *hd = | 808 | struct _MPT_SCSI_HOST *hd = |
729 | (struct _MPT_SCSI_HOST *)dev_to_shost(starget->dev.parent)->hostdata; | 809 | (struct _MPT_SCSI_HOST *)dev_to_shost(starget->dev.parent)->hostdata; |
730 | return ((hd->ioc->raid_data.isRaid & (1 << starget->id)) && | 810 | return ((mptspi_is_raid(hd, starget->id)) && |
731 | starget->channel == 0) ? 1 : 0; | 811 | starget->channel == 0) ? 1 : 0; |
732 | } | 812 | } |
733 | 813 | ||
@@ -945,7 +1025,7 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
945 | * max_lun = 1 + actual last lun, | 1025 | * max_lun = 1 + actual last lun, |
946 | * see hosts.h :o( | 1026 | * see hosts.h :o( |
947 | */ | 1027 | */ |
948 | sh->max_id = MPT_MAX_SCSI_DEVICES; | 1028 | sh->max_id = ioc->devices_per_bus; |
949 | 1029 | ||
950 | sh->max_lun = MPT_LAST_LUN + 1; | 1030 | sh->max_lun = MPT_LAST_LUN + 1; |
951 | /* | 1031 | /* |
@@ -1009,20 +1089,6 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
1009 | dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n", | 1089 | dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n", |
1010 | ioc->name, hd->ScsiLookup)); | 1090 | ioc->name, hd->ScsiLookup)); |
1011 | 1091 | ||
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 | 1092 | /* Clear the TM flags |
1027 | */ | 1093 | */ |
1028 | hd->tmPending = 0; | 1094 | hd->tmPending = 0; |