diff options
author | Mark Haverkamp <markh@linux-foundation.org> | 2007-03-15 15:55:07 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2007-03-20 11:54:49 -0400 |
commit | fe76df4235986cfacc2d3b71cef7c42bc1a6dd6c (patch) | |
tree | a8b31caeae0d4a60b0271c5e83a0c219de0fde72 /drivers/scsi/aacraid/aachba.c | |
parent | a8166a52968216ae079a5530ac3269147de2ef31 (diff) |
[SCSI] aacraid: Fix blocking issue with container probing function (cast update)
Received from Mark Salyzyn,
The aac_probe_container call blocks. This is an issue because it is called on
occasion in the context of the queuecommand handler. Once in a blue moon this
has resulted in a kernel panic sleeping during interrupt; or problems with some
embedded system versions of the kernel that depend on queuecommand to not
block. This ugly patch rewrites the aac_probe_container call into a new routine
_aac_probe_container that is an asynchronous state machine to complete the
series of operations. The legacy blocking aac_probe_container call used in
other areas of the driver (during initialization scanning for all targets and
in the separate hot-add/remove [aacraid] thread) merely issues
_aac_probe_container and then simple spins calling schedule() waiting for
completion.
Signed-off-by: Mark Haverkamp <markh@linux-foundation.org>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/aacraid/aachba.c')
-rw-r--r-- | drivers/scsi/aacraid/aachba.c | 311 |
1 files changed, 169 insertions, 142 deletions
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index d789e61bdc49..1610f0670c78 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c | |||
@@ -258,13 +258,10 @@ int aac_get_containers(struct aac_dev *dev) | |||
258 | u32 index; | 258 | u32 index; |
259 | int status = 0; | 259 | int status = 0; |
260 | struct fib * fibptr; | 260 | struct fib * fibptr; |
261 | unsigned instance; | ||
262 | struct aac_get_container_count *dinfo; | 261 | struct aac_get_container_count *dinfo; |
263 | struct aac_get_container_count_resp *dresp; | 262 | struct aac_get_container_count_resp *dresp; |
264 | int maximum_num_containers = MAXIMUM_NUM_CONTAINERS; | 263 | int maximum_num_containers = MAXIMUM_NUM_CONTAINERS; |
265 | 264 | ||
266 | instance = dev->scsi_host_ptr->unique_id; | ||
267 | |||
268 | if (!(fibptr = aac_fib_alloc(dev))) | 265 | if (!(fibptr = aac_fib_alloc(dev))) |
269 | return -ENOMEM; | 266 | return -ENOMEM; |
270 | 267 | ||
@@ -284,88 +281,35 @@ int aac_get_containers(struct aac_dev *dev) | |||
284 | maximum_num_containers = le32_to_cpu(dresp->ContainerSwitchEntries); | 281 | maximum_num_containers = le32_to_cpu(dresp->ContainerSwitchEntries); |
285 | aac_fib_complete(fibptr); | 282 | aac_fib_complete(fibptr); |
286 | } | 283 | } |
284 | aac_fib_free(fibptr); | ||
287 | 285 | ||
288 | if (maximum_num_containers < MAXIMUM_NUM_CONTAINERS) | 286 | if (maximum_num_containers < MAXIMUM_NUM_CONTAINERS) |
289 | maximum_num_containers = MAXIMUM_NUM_CONTAINERS; | 287 | maximum_num_containers = MAXIMUM_NUM_CONTAINERS; |
290 | fsa_dev_ptr = kmalloc( | 288 | fsa_dev_ptr = kmalloc(sizeof(*fsa_dev_ptr) * maximum_num_containers, |
291 | sizeof(*fsa_dev_ptr) * maximum_num_containers, GFP_KERNEL); | 289 | GFP_KERNEL); |
292 | if (!fsa_dev_ptr) { | 290 | if (!fsa_dev_ptr) |
293 | aac_fib_free(fibptr); | ||
294 | return -ENOMEM; | 291 | return -ENOMEM; |
295 | } | ||
296 | memset(fsa_dev_ptr, 0, sizeof(*fsa_dev_ptr) * maximum_num_containers); | 292 | memset(fsa_dev_ptr, 0, sizeof(*fsa_dev_ptr) * maximum_num_containers); |
297 | 293 | ||
298 | dev->fsa_dev = fsa_dev_ptr; | 294 | dev->fsa_dev = fsa_dev_ptr; |
299 | dev->maximum_num_containers = maximum_num_containers; | 295 | dev->maximum_num_containers = maximum_num_containers; |
300 | 296 | ||
301 | for (index = 0; index < dev->maximum_num_containers; index++) { | 297 | for (index = 0; index < dev->maximum_num_containers; ) { |
302 | struct aac_query_mount *dinfo; | ||
303 | struct aac_mount *dresp; | ||
304 | |||
305 | fsa_dev_ptr[index].devname[0] = '\0'; | 298 | fsa_dev_ptr[index].devname[0] = '\0'; |
306 | 299 | ||
307 | aac_fib_init(fibptr); | 300 | status = aac_probe_container(dev, index); |
308 | dinfo = (struct aac_query_mount *) fib_data(fibptr); | ||
309 | |||
310 | dinfo->command = cpu_to_le32(VM_NameServe); | ||
311 | dinfo->count = cpu_to_le32(index); | ||
312 | dinfo->type = cpu_to_le32(FT_FILESYS); | ||
313 | 301 | ||
314 | status = aac_fib_send(ContainerCommand, | 302 | if (status < 0) { |
315 | fibptr, | ||
316 | sizeof (struct aac_query_mount), | ||
317 | FsaNormal, | ||
318 | 1, 1, | ||
319 | NULL, NULL); | ||
320 | if (status < 0 ) { | ||
321 | printk(KERN_WARNING "aac_get_containers: SendFIB failed.\n"); | 303 | printk(KERN_WARNING "aac_get_containers: SendFIB failed.\n"); |
322 | break; | 304 | break; |
323 | } | 305 | } |
324 | dresp = (struct aac_mount *)fib_data(fibptr); | ||
325 | |||
326 | if ((le32_to_cpu(dresp->status) == ST_OK) && | ||
327 | (le32_to_cpu(dresp->mnt[0].vol) == CT_NONE)) { | ||
328 | dinfo->command = cpu_to_le32(VM_NameServe64); | ||
329 | dinfo->count = cpu_to_le32(index); | ||
330 | dinfo->type = cpu_to_le32(FT_FILESYS); | ||
331 | 306 | ||
332 | if (aac_fib_send(ContainerCommand, | ||
333 | fibptr, | ||
334 | sizeof(struct aac_query_mount), | ||
335 | FsaNormal, | ||
336 | 1, 1, | ||
337 | NULL, NULL) < 0) | ||
338 | continue; | ||
339 | } else | ||
340 | dresp->mnt[0].capacityhigh = 0; | ||
341 | |||
342 | dprintk ((KERN_DEBUG | ||
343 | "VM_NameServe cid=%d status=%d vol=%d state=%d cap=%llu\n", | ||
344 | (int)index, (int)le32_to_cpu(dresp->status), | ||
345 | (int)le32_to_cpu(dresp->mnt[0].vol), | ||
346 | (int)le32_to_cpu(dresp->mnt[0].state), | ||
347 | ((u64)le32_to_cpu(dresp->mnt[0].capacity)) + | ||
348 | (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32))); | ||
349 | if ((le32_to_cpu(dresp->status) == ST_OK) && | ||
350 | (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) && | ||
351 | (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) { | ||
352 | fsa_dev_ptr[index].valid = 1; | ||
353 | fsa_dev_ptr[index].type = le32_to_cpu(dresp->mnt[0].vol); | ||
354 | fsa_dev_ptr[index].size | ||
355 | = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) + | ||
356 | (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32); | ||
357 | if (le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY) | ||
358 | fsa_dev_ptr[index].ro = 1; | ||
359 | } | ||
360 | aac_fib_complete(fibptr); | ||
361 | /* | 307 | /* |
362 | * If there are no more containers, then stop asking. | 308 | * If there are no more containers, then stop asking. |
363 | */ | 309 | */ |
364 | if ((index + 1) >= le32_to_cpu(dresp->count)){ | 310 | if (++index >= status) |
365 | break; | 311 | break; |
366 | } | ||
367 | } | 312 | } |
368 | aac_fib_free(fibptr); | ||
369 | return status; | 313 | return status; |
370 | } | 314 | } |
371 | 315 | ||
@@ -473,85 +417,185 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd, int cid) | |||
473 | return -1; | 417 | return -1; |
474 | } | 418 | } |
475 | 419 | ||
476 | /** | 420 | static int aac_probe_container_callback2(struct scsi_cmnd * scsicmd) |
477 | * aac_probe_container - query a logical volume | ||
478 | * @dev: device to query | ||
479 | * @cid: container identifier | ||
480 | * | ||
481 | * Queries the controller about the given volume. The volume information | ||
482 | * is updated in the struct fsa_dev_info structure rather than returned. | ||
483 | */ | ||
484 | |||
485 | int aac_probe_container(struct aac_dev *dev, int cid) | ||
486 | { | 421 | { |
487 | struct fsa_dev_info *fsa_dev_ptr; | 422 | struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev; |
488 | int status; | ||
489 | struct aac_query_mount *dinfo; | ||
490 | struct aac_mount *dresp; | ||
491 | struct fib * fibptr; | ||
492 | unsigned instance; | ||
493 | 423 | ||
494 | fsa_dev_ptr = dev->fsa_dev; | 424 | if (fsa_dev_ptr[scmd_id(scsicmd)].valid) |
495 | if (!fsa_dev_ptr) | 425 | return aac_scsi_cmd(scsicmd); |
496 | return -ENOMEM; | ||
497 | instance = dev->scsi_host_ptr->unique_id; | ||
498 | 426 | ||
499 | if (!(fibptr = aac_fib_alloc(dev))) | 427 | scsicmd->result = DID_NO_CONNECT << 16; |
500 | return -ENOMEM; | 428 | scsicmd->scsi_done(scsicmd); |
429 | return 0; | ||
430 | } | ||
431 | |||
432 | static int _aac_probe_container2(void * context, struct fib * fibptr) | ||
433 | { | ||
434 | struct scsi_cmnd * scsicmd = (struct scsi_cmnd *)context; | ||
435 | struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev; | ||
436 | int (*callback)(struct scsi_cmnd *); | ||
437 | |||
438 | scsicmd->SCp.Status = 0; | ||
439 | if (fsa_dev_ptr) { | ||
440 | struct aac_mount * dresp = (struct aac_mount *) fib_data(fibptr); | ||
441 | fsa_dev_ptr += scmd_id(scsicmd); | ||
442 | |||
443 | if ((le32_to_cpu(dresp->status) == ST_OK) && | ||
444 | (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) && | ||
445 | (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) { | ||
446 | fsa_dev_ptr->valid = 1; | ||
447 | fsa_dev_ptr->type = le32_to_cpu(dresp->mnt[0].vol); | ||
448 | fsa_dev_ptr->size | ||
449 | = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) + | ||
450 | (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32); | ||
451 | fsa_dev_ptr->ro = ((le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY) != 0); | ||
452 | } | ||
453 | if ((fsa_dev_ptr->valid & 1) == 0) | ||
454 | fsa_dev_ptr->valid = 0; | ||
455 | scsicmd->SCp.Status = le32_to_cpu(dresp->count); | ||
456 | } | ||
457 | aac_fib_complete(fibptr); | ||
458 | aac_fib_free(fibptr); | ||
459 | callback = (int (*)(struct scsi_cmnd *))(scsicmd->SCp.ptr); | ||
460 | scsicmd->SCp.ptr = NULL; | ||
461 | return (*callback)(scsicmd); | ||
462 | } | ||
463 | |||
464 | static int _aac_probe_container1(void * context, struct fib * fibptr) | ||
465 | { | ||
466 | struct scsi_cmnd * scsicmd; | ||
467 | struct aac_mount * dresp; | ||
468 | struct aac_query_mount *dinfo; | ||
469 | int status; | ||
470 | |||
471 | dresp = (struct aac_mount *) fib_data(fibptr); | ||
472 | dresp->mnt[0].capacityhigh = 0; | ||
473 | if ((le32_to_cpu(dresp->status) != ST_OK) || | ||
474 | ((le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) && | ||
475 | (le32_to_cpu(dresp->mnt[0].state) == FSCS_HIDDEN))) | ||
476 | return _aac_probe_container2(context, fibptr); | ||
477 | scsicmd = (struct scsi_cmnd *) context; | ||
478 | scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL; | ||
501 | 479 | ||
502 | aac_fib_init(fibptr); | 480 | aac_fib_init(fibptr); |
503 | 481 | ||
504 | dinfo = (struct aac_query_mount *)fib_data(fibptr); | 482 | dinfo = (struct aac_query_mount *)fib_data(fibptr); |
505 | 483 | ||
506 | dinfo->command = cpu_to_le32(VM_NameServe); | 484 | dinfo->command = cpu_to_le32(VM_NameServe64); |
507 | dinfo->count = cpu_to_le32(cid); | 485 | dinfo->count = cpu_to_le32(scmd_id(scsicmd)); |
508 | dinfo->type = cpu_to_le32(FT_FILESYS); | 486 | dinfo->type = cpu_to_le32(FT_FILESYS); |
509 | 487 | ||
510 | status = aac_fib_send(ContainerCommand, | 488 | status = aac_fib_send(ContainerCommand, |
511 | fibptr, | 489 | fibptr, |
512 | sizeof(struct aac_query_mount), | 490 | sizeof(struct aac_query_mount), |
513 | FsaNormal, | 491 | FsaNormal, |
514 | 1, 1, | 492 | 0, 1, |
515 | NULL, NULL); | 493 | (fib_callback) _aac_probe_container2, |
494 | (void *) scsicmd); | ||
495 | /* | ||
496 | * Check that the command queued to the controller | ||
497 | */ | ||
498 | if (status == -EINPROGRESS) { | ||
499 | scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; | ||
500 | return 0; | ||
501 | } | ||
516 | if (status < 0) { | 502 | if (status < 0) { |
517 | printk(KERN_WARNING "aacraid: aac_probe_container query failed.\n"); | 503 | /* Inherit results from VM_NameServe, if any */ |
518 | goto error; | 504 | dresp->status = cpu_to_le32(ST_OK); |
505 | return _aac_probe_container2(context, fibptr); | ||
519 | } | 506 | } |
507 | return 0; | ||
508 | } | ||
520 | 509 | ||
521 | dresp = (struct aac_mount *) fib_data(fibptr); | 510 | static int _aac_probe_container(struct scsi_cmnd * scsicmd, int (*callback)(struct scsi_cmnd *)) |
511 | { | ||
512 | struct fib * fibptr; | ||
513 | int status = -ENOMEM; | ||
522 | 514 | ||
523 | if ((le32_to_cpu(dresp->status) == ST_OK) && | 515 | if ((fibptr = aac_fib_alloc((struct aac_dev *)scsicmd->device->host->hostdata))) { |
524 | (le32_to_cpu(dresp->mnt[0].vol) == CT_NONE)) { | 516 | struct aac_query_mount *dinfo; |
525 | dinfo->command = cpu_to_le32(VM_NameServe64); | ||
526 | dinfo->count = cpu_to_le32(cid); | ||
527 | dinfo->type = cpu_to_le32(FT_FILESYS); | ||
528 | 517 | ||
529 | if (aac_fib_send(ContainerCommand, | 518 | aac_fib_init(fibptr); |
530 | fibptr, | 519 | |
531 | sizeof(struct aac_query_mount), | 520 | dinfo = (struct aac_query_mount *)fib_data(fibptr); |
532 | FsaNormal, | 521 | |
533 | 1, 1, | 522 | dinfo->command = cpu_to_le32(VM_NameServe); |
534 | NULL, NULL) < 0) | 523 | dinfo->count = cpu_to_le32(scmd_id(scsicmd)); |
535 | goto error; | 524 | dinfo->type = cpu_to_le32(FT_FILESYS); |
536 | } else | 525 | scsicmd->SCp.ptr = (char *)callback; |
537 | dresp->mnt[0].capacityhigh = 0; | ||
538 | 526 | ||
539 | if ((le32_to_cpu(dresp->status) == ST_OK) && | 527 | status = aac_fib_send(ContainerCommand, |
540 | (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) && | 528 | fibptr, |
541 | (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) { | 529 | sizeof(struct aac_query_mount), |
542 | fsa_dev_ptr[cid].valid = 1; | 530 | FsaNormal, |
543 | fsa_dev_ptr[cid].type = le32_to_cpu(dresp->mnt[0].vol); | 531 | 0, 1, |
544 | fsa_dev_ptr[cid].size | 532 | (fib_callback) _aac_probe_container1, |
545 | = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) + | 533 | (void *) scsicmd); |
546 | (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32); | 534 | /* |
547 | if (le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY) | 535 | * Check that the command queued to the controller |
548 | fsa_dev_ptr[cid].ro = 1; | 536 | */ |
537 | if (status == -EINPROGRESS) { | ||
538 | scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; | ||
539 | return 0; | ||
540 | } | ||
541 | if (status < 0) { | ||
542 | scsicmd->SCp.ptr = NULL; | ||
543 | aac_fib_complete(fibptr); | ||
544 | aac_fib_free(fibptr); | ||
545 | } | ||
546 | } | ||
547 | if (status < 0) { | ||
548 | struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev; | ||
549 | if (fsa_dev_ptr) { | ||
550 | fsa_dev_ptr += scmd_id(scsicmd); | ||
551 | if ((fsa_dev_ptr->valid & 1) == 0) { | ||
552 | fsa_dev_ptr->valid = 0; | ||
553 | return (*callback)(scsicmd); | ||
554 | } | ||
555 | } | ||
549 | } | 556 | } |
557 | return status; | ||
558 | } | ||
550 | 559 | ||
551 | error: | 560 | /** |
552 | aac_fib_complete(fibptr); | 561 | * aac_probe_container - query a logical volume |
553 | aac_fib_free(fibptr); | 562 | * @dev: device to query |
563 | * @cid: container identifier | ||
564 | * | ||
565 | * Queries the controller about the given volume. The volume information | ||
566 | * is updated in the struct fsa_dev_info structure rather than returned. | ||
567 | */ | ||
568 | static int aac_probe_container_callback1(struct scsi_cmnd * scsicmd) | ||
569 | { | ||
570 | scsicmd->device = NULL; | ||
571 | return 0; | ||
572 | } | ||
554 | 573 | ||
574 | int aac_probe_container(struct aac_dev *dev, int cid) | ||
575 | { | ||
576 | struct scsi_cmnd *scsicmd = kmalloc(sizeof(*scsicmd), GFP_KERNEL); | ||
577 | struct scsi_device *scsidev = kmalloc(sizeof(*scsidev), GFP_KERNEL); | ||
578 | int status; | ||
579 | |||
580 | if (!scsicmd || !scsidev) { | ||
581 | kfree(scsicmd); | ||
582 | kfree(scsidev); | ||
583 | return -ENOMEM; | ||
584 | } | ||
585 | scsicmd->list.next = NULL; | ||
586 | scsicmd->scsi_done = (void (*)(struct scsi_cmnd*))_aac_probe_container1; | ||
587 | |||
588 | scsicmd->device = scsidev; | ||
589 | scsidev->sdev_state = 0; | ||
590 | scsidev->id = cid; | ||
591 | scsidev->host = dev->scsi_host_ptr; | ||
592 | |||
593 | if (_aac_probe_container(scsicmd, aac_probe_container_callback1) == 0) | ||
594 | while (scsicmd->device == scsidev) | ||
595 | schedule(); | ||
596 | status = scsicmd->SCp.Status; | ||
597 | kfree(scsicmd); | ||
598 | kfree(scsidev); | ||
555 | return status; | 599 | return status; |
556 | } | 600 | } |
557 | 601 | ||
@@ -1646,29 +1690,12 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) | |||
1646 | case TEST_UNIT_READY: | 1690 | case TEST_UNIT_READY: |
1647 | if (dev->in_reset) | 1691 | if (dev->in_reset) |
1648 | return -1; | 1692 | return -1; |
1649 | spin_unlock_irq(host->host_lock); | 1693 | return _aac_probe_container(scsicmd, |
1650 | aac_probe_container(dev, cid); | 1694 | aac_probe_container_callback2); |
1651 | if ((fsa_dev_ptr[cid].valid & 1) == 0) | ||
1652 | fsa_dev_ptr[cid].valid = 0; | ||
1653 | spin_lock_irq(host->host_lock); | ||
1654 | if (fsa_dev_ptr[cid].valid == 0) { | ||
1655 | scsicmd->result = DID_NO_CONNECT << 16; | ||
1656 | scsicmd->scsi_done(scsicmd); | ||
1657 | return 0; | ||
1658 | } | ||
1659 | default: | 1695 | default: |
1660 | break; | 1696 | break; |
1661 | } | 1697 | } |
1662 | } | 1698 | } |
1663 | /* | ||
1664 | * If the target container still doesn't exist, | ||
1665 | * return failure | ||
1666 | */ | ||
1667 | if (fsa_dev_ptr[cid].valid == 0) { | ||
1668 | scsicmd->result = DID_BAD_TARGET << 16; | ||
1669 | scsicmd->scsi_done(scsicmd); | ||
1670 | return 0; | ||
1671 | } | ||
1672 | } else { /* check for physical non-dasd devices */ | 1699 | } else { /* check for physical non-dasd devices */ |
1673 | if ((dev->nondasd_support == 1) || expose_physicals) { | 1700 | if ((dev->nondasd_support == 1) || expose_physicals) { |
1674 | if (dev->in_reset) | 1701 | if (dev->in_reset) |