diff options
Diffstat (limited to 'drivers/scsi/aic7xxx/aic79xx_osm.c')
-rw-r--r-- | drivers/scsi/aic7xxx/aic79xx_osm.c | 561 |
1 files changed, 260 insertions, 301 deletions
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 7254ea535a16..bcced0a417e6 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c | |||
@@ -373,8 +373,7 @@ static void ahd_linux_handle_scsi_status(struct ahd_softc *, | |||
373 | struct scb *); | 373 | struct scb *); |
374 | static void ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, | 374 | static void ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, |
375 | struct scsi_cmnd *cmd); | 375 | struct scsi_cmnd *cmd); |
376 | static void ahd_linux_sem_timeout(u_long arg); | 376 | static int ahd_linux_queue_abort_cmd(struct scsi_cmnd *cmd); |
377 | static int ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag); | ||
378 | static void ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd); | 377 | static void ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd); |
379 | static u_int ahd_linux_user_tagdepth(struct ahd_softc *ahd, | 378 | static u_int ahd_linux_user_tagdepth(struct ahd_softc *ahd, |
380 | struct ahd_devinfo *devinfo); | 379 | struct ahd_devinfo *devinfo); |
@@ -453,18 +452,13 @@ ahd_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *)) | |||
453 | struct ahd_softc *ahd; | 452 | struct ahd_softc *ahd; |
454 | struct ahd_linux_device *dev = scsi_transport_device_data(cmd->device); | 453 | struct ahd_linux_device *dev = scsi_transport_device_data(cmd->device); |
455 | int rtn = SCSI_MLQUEUE_HOST_BUSY; | 454 | int rtn = SCSI_MLQUEUE_HOST_BUSY; |
456 | unsigned long flags; | ||
457 | 455 | ||
458 | ahd = *(struct ahd_softc **)cmd->device->host->hostdata; | 456 | ahd = *(struct ahd_softc **)cmd->device->host->hostdata; |
459 | 457 | ||
460 | ahd_lock(ahd, &flags); | 458 | cmd->scsi_done = scsi_done; |
461 | if (ahd->platform_data->qfrozen == 0) { | 459 | cmd->result = CAM_REQ_INPROG << 16; |
462 | cmd->scsi_done = scsi_done; | 460 | rtn = ahd_linux_run_command(ahd, dev, cmd); |
463 | cmd->result = CAM_REQ_INPROG << 16; | ||
464 | rtn = ahd_linux_run_command(ahd, dev, cmd); | ||
465 | 461 | ||
466 | } | ||
467 | ahd_unlock(ahd, &flags); | ||
468 | return rtn; | 462 | return rtn; |
469 | } | 463 | } |
470 | 464 | ||
@@ -487,6 +481,7 @@ ahd_linux_target_alloc(struct scsi_target *starget) | |||
487 | { | 481 | { |
488 | struct ahd_softc *ahd = | 482 | struct ahd_softc *ahd = |
489 | *((struct ahd_softc **)dev_to_shost(&starget->dev)->hostdata); | 483 | *((struct ahd_softc **)dev_to_shost(&starget->dev)->hostdata); |
484 | struct seeprom_config *sc = ahd->seep_config; | ||
490 | unsigned long flags; | 485 | unsigned long flags; |
491 | struct scsi_target **ahd_targp = ahd_linux_target_in_softc(starget); | 486 | struct scsi_target **ahd_targp = ahd_linux_target_in_softc(starget); |
492 | struct ahd_linux_target *targ = scsi_transport_target_data(starget); | 487 | struct ahd_linux_target *targ = scsi_transport_target_data(starget); |
@@ -502,18 +497,38 @@ ahd_linux_target_alloc(struct scsi_target *starget) | |||
502 | *ahd_targp = starget; | 497 | *ahd_targp = starget; |
503 | memset(targ, 0, sizeof(*targ)); | 498 | memset(targ, 0, sizeof(*targ)); |
504 | 499 | ||
500 | if (sc) { | ||
501 | int flags = sc->device_flags[starget->id]; | ||
502 | |||
503 | tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, | ||
504 | starget->id, &tstate); | ||
505 | |||
506 | if ((flags & CFPACKETIZED) == 0) { | ||
507 | /* Do not negotiate packetized transfers */ | ||
508 | spi_rd_strm(starget) = 0; | ||
509 | spi_pcomp_en(starget) = 0; | ||
510 | spi_rti(starget) = 0; | ||
511 | spi_wr_flow(starget) = 0; | ||
512 | spi_hold_mcs(starget) = 0; | ||
513 | } else { | ||
514 | if ((ahd->features & AHD_RTI) == 0) | ||
515 | spi_rti(starget) = 0; | ||
516 | } | ||
517 | |||
518 | if ((flags & CFQAS) == 0) | ||
519 | spi_qas(starget) = 0; | ||
520 | |||
521 | /* Transinfo values have been set to BIOS settings */ | ||
522 | spi_max_width(starget) = (flags & CFWIDEB) ? 1 : 0; | ||
523 | spi_min_period(starget) = tinfo->user.period; | ||
524 | spi_max_offset(starget) = tinfo->user.offset; | ||
525 | } | ||
526 | |||
505 | tinfo = ahd_fetch_transinfo(ahd, channel, ahd->our_id, | 527 | tinfo = ahd_fetch_transinfo(ahd, channel, ahd->our_id, |
506 | starget->id, &tstate); | 528 | starget->id, &tstate); |
507 | ahd_compile_devinfo(&devinfo, ahd->our_id, starget->id, | 529 | ahd_compile_devinfo(&devinfo, ahd->our_id, starget->id, |
508 | CAM_LUN_WILDCARD, channel, | 530 | CAM_LUN_WILDCARD, channel, |
509 | ROLE_INITIATOR); | 531 | ROLE_INITIATOR); |
510 | spi_min_period(starget) = AHD_SYNCRATE_MAX; /* We can do U320 */ | ||
511 | if ((ahd->bugs & AHD_PACED_NEGTABLE_BUG) != 0) | ||
512 | spi_max_offset(starget) = MAX_OFFSET_PACED_BUG; | ||
513 | else | ||
514 | spi_max_offset(starget) = MAX_OFFSET_PACED; | ||
515 | spi_max_width(starget) = ahd->features & AHD_WIDE; | ||
516 | |||
517 | ahd_set_syncrate(ahd, &devinfo, 0, 0, 0, | 532 | ahd_set_syncrate(ahd, &devinfo, 0, 0, 0, |
518 | AHD_TRANS_GOAL, /*paused*/FALSE); | 533 | AHD_TRANS_GOAL, /*paused*/FALSE); |
519 | ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, | 534 | ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, |
@@ -654,10 +669,9 @@ static int | |||
654 | ahd_linux_abort(struct scsi_cmnd *cmd) | 669 | ahd_linux_abort(struct scsi_cmnd *cmd) |
655 | { | 670 | { |
656 | int error; | 671 | int error; |
672 | |||
673 | error = ahd_linux_queue_abort_cmd(cmd); | ||
657 | 674 | ||
658 | error = ahd_linux_queue_recovery_cmd(cmd, SCB_ABORT); | ||
659 | if (error != 0) | ||
660 | printf("aic79xx_abort returns 0x%x\n", error); | ||
661 | return error; | 675 | return error; |
662 | } | 676 | } |
663 | 677 | ||
@@ -667,12 +681,97 @@ ahd_linux_abort(struct scsi_cmnd *cmd) | |||
667 | static int | 681 | static int |
668 | ahd_linux_dev_reset(struct scsi_cmnd *cmd) | 682 | ahd_linux_dev_reset(struct scsi_cmnd *cmd) |
669 | { | 683 | { |
670 | int error; | 684 | struct ahd_softc *ahd; |
685 | struct ahd_linux_device *dev; | ||
686 | struct scb *reset_scb; | ||
687 | u_int cdb_byte; | ||
688 | int retval = SUCCESS; | ||
689 | int paused; | ||
690 | int wait; | ||
691 | struct ahd_initiator_tinfo *tinfo; | ||
692 | struct ahd_tmode_tstate *tstate; | ||
693 | unsigned long flags; | ||
694 | DECLARE_COMPLETION(done); | ||
671 | 695 | ||
672 | error = ahd_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET); | 696 | reset_scb = NULL; |
673 | if (error != 0) | 697 | paused = FALSE; |
674 | printf("aic79xx_dev_reset returns 0x%x\n", error); | 698 | wait = FALSE; |
675 | return error; | 699 | ahd = *(struct ahd_softc **)cmd->device->host->hostdata; |
700 | |||
701 | scmd_printk(KERN_INFO, cmd, | ||
702 | "Attempting to queue a TARGET RESET message:"); | ||
703 | |||
704 | printf("CDB:"); | ||
705 | for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++) | ||
706 | printf(" 0x%x", cmd->cmnd[cdb_byte]); | ||
707 | printf("\n"); | ||
708 | |||
709 | /* | ||
710 | * Determine if we currently own this command. | ||
711 | */ | ||
712 | dev = scsi_transport_device_data(cmd->device); | ||
713 | |||
714 | if (dev == NULL) { | ||
715 | /* | ||
716 | * No target device for this command exists, | ||
717 | * so we must not still own the command. | ||
718 | */ | ||
719 | scmd_printk(KERN_INFO, cmd, "Is not an active device\n"); | ||
720 | return SUCCESS; | ||
721 | } | ||
722 | |||
723 | /* | ||
724 | * Generate us a new SCB | ||
725 | */ | ||
726 | reset_scb = ahd_get_scb(ahd, AHD_NEVER_COL_IDX); | ||
727 | if (!reset_scb) { | ||
728 | scmd_printk(KERN_INFO, cmd, "No SCB available\n"); | ||
729 | return FAILED; | ||
730 | } | ||
731 | |||
732 | tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, | ||
733 | cmd->device->id, &tstate); | ||
734 | reset_scb->io_ctx = cmd; | ||
735 | reset_scb->platform_data->dev = dev; | ||
736 | reset_scb->sg_count = 0; | ||
737 | ahd_set_residual(reset_scb, 0); | ||
738 | ahd_set_sense_residual(reset_scb, 0); | ||
739 | reset_scb->platform_data->xfer_len = 0; | ||
740 | reset_scb->hscb->control = 0; | ||
741 | reset_scb->hscb->scsiid = BUILD_SCSIID(ahd,cmd); | ||
742 | reset_scb->hscb->lun = cmd->device->lun; | ||
743 | reset_scb->hscb->cdb_len = 0; | ||
744 | reset_scb->hscb->task_management = SIU_TASKMGMT_LUN_RESET; | ||
745 | reset_scb->flags |= SCB_DEVICE_RESET|SCB_RECOVERY_SCB|SCB_ACTIVE; | ||
746 | if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { | ||
747 | reset_scb->flags |= SCB_PACKETIZED; | ||
748 | } else { | ||
749 | reset_scb->hscb->control |= MK_MESSAGE; | ||
750 | } | ||
751 | dev->openings--; | ||
752 | dev->active++; | ||
753 | dev->commands_issued++; | ||
754 | |||
755 | ahd_lock(ahd, &flags); | ||
756 | |||
757 | LIST_INSERT_HEAD(&ahd->pending_scbs, reset_scb, pending_links); | ||
758 | ahd_queue_scb(ahd, reset_scb); | ||
759 | |||
760 | ahd->platform_data->eh_done = &done; | ||
761 | ahd_unlock(ahd, &flags); | ||
762 | |||
763 | printf("%s: Device reset code sleeping\n", ahd_name(ahd)); | ||
764 | if (!wait_for_completion_timeout(&done, 5 * HZ)) { | ||
765 | ahd_lock(ahd, &flags); | ||
766 | ahd->platform_data->eh_done = NULL; | ||
767 | ahd_unlock(ahd, &flags); | ||
768 | printf("%s: Device reset timer expired (active %d)\n", | ||
769 | ahd_name(ahd), dev->active); | ||
770 | retval = FAILED; | ||
771 | } | ||
772 | printf("%s: Device reset returning 0x%x\n", ahd_name(ahd), retval); | ||
773 | |||
774 | return (retval); | ||
676 | } | 775 | } |
677 | 776 | ||
678 | /* | 777 | /* |
@@ -682,7 +781,6 @@ static int | |||
682 | ahd_linux_bus_reset(struct scsi_cmnd *cmd) | 781 | ahd_linux_bus_reset(struct scsi_cmnd *cmd) |
683 | { | 782 | { |
684 | struct ahd_softc *ahd; | 783 | struct ahd_softc *ahd; |
685 | u_long s; | ||
686 | int found; | 784 | int found; |
687 | 785 | ||
688 | ahd = *(struct ahd_softc **)cmd->device->host->hostdata; | 786 | ahd = *(struct ahd_softc **)cmd->device->host->hostdata; |
@@ -691,10 +789,8 @@ ahd_linux_bus_reset(struct scsi_cmnd *cmd) | |||
691 | printf("%s: Bus reset called for cmd %p\n", | 789 | printf("%s: Bus reset called for cmd %p\n", |
692 | ahd_name(ahd), cmd); | 790 | ahd_name(ahd), cmd); |
693 | #endif | 791 | #endif |
694 | ahd_lock(ahd, &s); | ||
695 | found = ahd_reset_channel(ahd, scmd_channel(cmd) + 'A', | 792 | found = ahd_reset_channel(ahd, scmd_channel(cmd) + 'A', |
696 | /*initiate reset*/TRUE); | 793 | /*initiate reset*/TRUE); |
697 | ahd_unlock(ahd, &s); | ||
698 | 794 | ||
699 | if (bootverbose) | 795 | if (bootverbose) |
700 | printf("%s: SCSI bus reset delivered. " | 796 | printf("%s: SCSI bus reset delivered. " |
@@ -811,59 +907,6 @@ ahd_dmamap_unload(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map) | |||
811 | } | 907 | } |
812 | 908 | ||
813 | /********************* Platform Dependent Functions ***************************/ | 909 | /********************* Platform Dependent Functions ***************************/ |
814 | /* | ||
815 | * Compare "left hand" softc with "right hand" softc, returning: | ||
816 | * < 0 - lahd has a lower priority than rahd | ||
817 | * 0 - Softcs are equal | ||
818 | * > 0 - lahd has a higher priority than rahd | ||
819 | */ | ||
820 | int | ||
821 | ahd_softc_comp(struct ahd_softc *lahd, struct ahd_softc *rahd) | ||
822 | { | ||
823 | int value; | ||
824 | |||
825 | /* | ||
826 | * Under Linux, cards are ordered as follows: | ||
827 | * 1) PCI devices that are marked as the boot controller. | ||
828 | * 2) PCI devices with BIOS enabled sorted by bus/slot/func. | ||
829 | * 3) All remaining PCI devices sorted by bus/slot/func. | ||
830 | */ | ||
831 | #if 0 | ||
832 | value = (lahd->flags & AHD_BOOT_CHANNEL) | ||
833 | - (rahd->flags & AHD_BOOT_CHANNEL); | ||
834 | if (value != 0) | ||
835 | /* Controllers set for boot have a *higher* priority */ | ||
836 | return (value); | ||
837 | #endif | ||
838 | |||
839 | value = (lahd->flags & AHD_BIOS_ENABLED) | ||
840 | - (rahd->flags & AHD_BIOS_ENABLED); | ||
841 | if (value != 0) | ||
842 | /* Controllers with BIOS enabled have a *higher* priority */ | ||
843 | return (value); | ||
844 | |||
845 | /* Still equal. Sort by bus/slot/func. */ | ||
846 | if (aic79xx_reverse_scan != 0) | ||
847 | value = ahd_get_pci_bus(lahd->dev_softc) | ||
848 | - ahd_get_pci_bus(rahd->dev_softc); | ||
849 | else | ||
850 | value = ahd_get_pci_bus(rahd->dev_softc) | ||
851 | - ahd_get_pci_bus(lahd->dev_softc); | ||
852 | if (value != 0) | ||
853 | return (value); | ||
854 | if (aic79xx_reverse_scan != 0) | ||
855 | value = ahd_get_pci_slot(lahd->dev_softc) | ||
856 | - ahd_get_pci_slot(rahd->dev_softc); | ||
857 | else | ||
858 | value = ahd_get_pci_slot(rahd->dev_softc) | ||
859 | - ahd_get_pci_slot(lahd->dev_softc); | ||
860 | if (value != 0) | ||
861 | return (value); | ||
862 | |||
863 | value = rahd->channel - lahd->channel; | ||
864 | return (value); | ||
865 | } | ||
866 | |||
867 | static void | 910 | static void |
868 | ahd_linux_setup_iocell_info(u_long index, int instance, int targ, int32_t value) | 911 | ahd_linux_setup_iocell_info(u_long index, int instance, int targ, int32_t value) |
869 | { | 912 | { |
@@ -1194,7 +1237,6 @@ ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg) | |||
1194 | memset(ahd->platform_data, 0, sizeof(struct ahd_platform_data)); | 1237 | memset(ahd->platform_data, 0, sizeof(struct ahd_platform_data)); |
1195 | ahd->platform_data->irq = AHD_LINUX_NOIRQ; | 1238 | ahd->platform_data->irq = AHD_LINUX_NOIRQ; |
1196 | ahd_lockinit(ahd); | 1239 | ahd_lockinit(ahd); |
1197 | init_MUTEX_LOCKED(&ahd->platform_data->eh_sem); | ||
1198 | ahd->seltime = (aic79xx_seltime & 0x3) << 4; | 1240 | ahd->seltime = (aic79xx_seltime & 0x3) << 4; |
1199 | return (0); | 1241 | return (0); |
1200 | } | 1242 | } |
@@ -1346,14 +1388,12 @@ ahd_platform_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, | |||
1346 | 1388 | ||
1347 | switch ((dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED))) { | 1389 | switch ((dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED))) { |
1348 | case AHD_DEV_Q_BASIC: | 1390 | case AHD_DEV_Q_BASIC: |
1349 | scsi_adjust_queue_depth(sdev, | 1391 | scsi_set_tag_type(sdev, MSG_SIMPLE_TASK); |
1350 | MSG_SIMPLE_TASK, | 1392 | scsi_activate_tcq(sdev, dev->openings + dev->active); |
1351 | dev->openings + dev->active); | ||
1352 | break; | 1393 | break; |
1353 | case AHD_DEV_Q_TAGGED: | 1394 | case AHD_DEV_Q_TAGGED: |
1354 | scsi_adjust_queue_depth(sdev, | 1395 | scsi_set_tag_type(sdev, MSG_ORDERED_TASK); |
1355 | MSG_ORDERED_TASK, | 1396 | scsi_activate_tcq(sdev, dev->openings + dev->active); |
1356 | dev->openings + dev->active); | ||
1357 | break; | 1397 | break; |
1358 | default: | 1398 | default: |
1359 | /* | 1399 | /* |
@@ -1362,9 +1402,7 @@ ahd_platform_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, | |||
1362 | * serially on the controller/device. This should | 1402 | * serially on the controller/device. This should |
1363 | * remove some latency. | 1403 | * remove some latency. |
1364 | */ | 1404 | */ |
1365 | scsi_adjust_queue_depth(sdev, | 1405 | scsi_deactivate_tcq(sdev, 1); |
1366 | /*NON-TAGGED*/0, | ||
1367 | /*queue depth*/2); | ||
1368 | break; | 1406 | break; |
1369 | } | 1407 | } |
1370 | } | 1408 | } |
@@ -1443,6 +1481,9 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev, | |||
1443 | struct ahd_tmode_tstate *tstate; | 1481 | struct ahd_tmode_tstate *tstate; |
1444 | u_int col_idx; | 1482 | u_int col_idx; |
1445 | uint16_t mask; | 1483 | uint16_t mask; |
1484 | unsigned long flags; | ||
1485 | |||
1486 | ahd_lock(ahd, &flags); | ||
1446 | 1487 | ||
1447 | /* | 1488 | /* |
1448 | * Get an scb to use. | 1489 | * Get an scb to use. |
@@ -1458,6 +1499,7 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev, | |||
1458 | } | 1499 | } |
1459 | if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) { | 1500 | if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) { |
1460 | ahd->flags |= AHD_RESOURCE_SHORTAGE; | 1501 | ahd->flags |= AHD_RESOURCE_SHORTAGE; |
1502 | ahd_unlock(ahd, &flags); | ||
1461 | return SCSI_MLQUEUE_HOST_BUSY; | 1503 | return SCSI_MLQUEUE_HOST_BUSY; |
1462 | } | 1504 | } |
1463 | 1505 | ||
@@ -1484,30 +1526,6 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev, | |||
1484 | if ((tstate->auto_negotiate & mask) != 0) { | 1526 | if ((tstate->auto_negotiate & mask) != 0) { |
1485 | scb->flags |= SCB_AUTO_NEGOTIATE; | 1527 | scb->flags |= SCB_AUTO_NEGOTIATE; |
1486 | scb->hscb->control |= MK_MESSAGE; | 1528 | scb->hscb->control |= MK_MESSAGE; |
1487 | } else if (cmd->cmnd[0] == INQUIRY | ||
1488 | && (tinfo->curr.offset != 0 | ||
1489 | || tinfo->curr.width != MSG_EXT_WDTR_BUS_8_BIT | ||
1490 | || tinfo->curr.ppr_options != 0) | ||
1491 | && (tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ)==0) { | ||
1492 | /* | ||
1493 | * The SCSI spec requires inquiry | ||
1494 | * commands to complete without | ||
1495 | * reporting unit attention conditions. | ||
1496 | * Because of this, an inquiry command | ||
1497 | * that occurs just after a device is | ||
1498 | * reset will result in a data phase | ||
1499 | * with mismatched negotiated rates. | ||
1500 | * The core already forces a renegotiation | ||
1501 | * for reset events that are visible to | ||
1502 | * our controller or that we initiate, | ||
1503 | * but a third party device reset or a | ||
1504 | * hot-plug insertion can still cause this | ||
1505 | * issue. Therefore, we force a re-negotiation | ||
1506 | * for every inquiry command unless we | ||
1507 | * are async. | ||
1508 | */ | ||
1509 | scb->flags |= SCB_NEGOTIATE; | ||
1510 | scb->hscb->control |= MK_MESSAGE; | ||
1511 | } | 1529 | } |
1512 | 1530 | ||
1513 | if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) != 0) { | 1531 | if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) != 0) { |
@@ -1583,6 +1601,8 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev, | |||
1583 | scb->flags |= SCB_ACTIVE; | 1601 | scb->flags |= SCB_ACTIVE; |
1584 | ahd_queue_scb(ahd, scb); | 1602 | ahd_queue_scb(ahd, scb); |
1585 | 1603 | ||
1604 | ahd_unlock(ahd, &flags); | ||
1605 | |||
1586 | return 0; | 1606 | return 0; |
1587 | } | 1607 | } |
1588 | 1608 | ||
@@ -1604,12 +1624,6 @@ ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs) | |||
1604 | } | 1624 | } |
1605 | 1625 | ||
1606 | void | 1626 | void |
1607 | ahd_platform_flushwork(struct ahd_softc *ahd) | ||
1608 | { | ||
1609 | |||
1610 | } | ||
1611 | |||
1612 | void | ||
1613 | ahd_send_async(struct ahd_softc *ahd, char channel, | 1627 | ahd_send_async(struct ahd_softc *ahd, char channel, |
1614 | u_int target, u_int lun, ac_code code, void *arg) | 1628 | u_int target, u_int lun, ac_code code, void *arg) |
1615 | { | 1629 | { |
@@ -1618,7 +1632,6 @@ ahd_send_async(struct ahd_softc *ahd, char channel, | |||
1618 | { | 1632 | { |
1619 | char buf[80]; | 1633 | char buf[80]; |
1620 | struct scsi_target *starget; | 1634 | struct scsi_target *starget; |
1621 | struct ahd_linux_target *targ; | ||
1622 | struct info_str info; | 1635 | struct info_str info; |
1623 | struct ahd_initiator_tinfo *tinfo; | 1636 | struct ahd_initiator_tinfo *tinfo; |
1624 | struct ahd_tmode_tstate *tstate; | 1637 | struct ahd_tmode_tstate *tstate; |
@@ -1651,7 +1664,6 @@ ahd_send_async(struct ahd_softc *ahd, char channel, | |||
1651 | starget = ahd->platform_data->starget[target]; | 1664 | starget = ahd->platform_data->starget[target]; |
1652 | if (starget == NULL) | 1665 | if (starget == NULL) |
1653 | break; | 1666 | break; |
1654 | targ = scsi_transport_target_data(starget); | ||
1655 | 1667 | ||
1656 | target_ppr_options = | 1668 | target_ppr_options = |
1657 | (spi_dt(starget) ? MSG_EXT_PPR_DT_REQ : 0) | 1669 | (spi_dt(starget) ? MSG_EXT_PPR_DT_REQ : 0) |
@@ -1803,10 +1815,9 @@ ahd_done(struct ahd_softc *ahd, struct scb *scb) | |||
1803 | if (ahd_get_transaction_status(scb) == CAM_BDR_SENT | 1815 | if (ahd_get_transaction_status(scb) == CAM_BDR_SENT |
1804 | || ahd_get_transaction_status(scb) == CAM_REQ_ABORTED) | 1816 | || ahd_get_transaction_status(scb) == CAM_REQ_ABORTED) |
1805 | ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT); | 1817 | ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT); |
1806 | if ((ahd->platform_data->flags & AHD_SCB_UP_EH_SEM) != 0) { | 1818 | |
1807 | ahd->platform_data->flags &= ~AHD_SCB_UP_EH_SEM; | 1819 | if (ahd->platform_data->eh_done) |
1808 | up(&ahd->platform_data->eh_sem); | 1820 | complete(ahd->platform_data->eh_done); |
1809 | } | ||
1810 | } | 1821 | } |
1811 | 1822 | ||
1812 | ahd_free_scb(ahd, scb); | 1823 | ahd_free_scb(ahd, scb); |
@@ -1961,133 +1972,125 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd, | |||
1961 | static void | 1972 | static void |
1962 | ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, struct scsi_cmnd *cmd) | 1973 | ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, struct scsi_cmnd *cmd) |
1963 | { | 1974 | { |
1975 | int status; | ||
1976 | int new_status = DID_OK; | ||
1977 | int do_fallback = 0; | ||
1978 | int scsi_status; | ||
1979 | |||
1964 | /* | 1980 | /* |
1965 | * Map CAM error codes into Linux Error codes. We | 1981 | * Map CAM error codes into Linux Error codes. We |
1966 | * avoid the conversion so that the DV code has the | 1982 | * avoid the conversion so that the DV code has the |
1967 | * full error information available when making | 1983 | * full error information available when making |
1968 | * state change decisions. | 1984 | * state change decisions. |
1969 | */ | 1985 | */ |
1970 | { | 1986 | |
1971 | uint32_t status; | 1987 | status = ahd_cmd_get_transaction_status(cmd); |
1972 | u_int new_status; | 1988 | switch (status) { |
1973 | 1989 | case CAM_REQ_INPROG: | |
1974 | status = ahd_cmd_get_transaction_status(cmd); | 1990 | case CAM_REQ_CMP: |
1975 | switch (status) { | 1991 | new_status = DID_OK; |
1976 | case CAM_REQ_INPROG: | 1992 | break; |
1977 | case CAM_REQ_CMP: | 1993 | case CAM_AUTOSENSE_FAIL: |
1978 | case CAM_SCSI_STATUS_ERROR: | 1994 | new_status = DID_ERROR; |
1979 | new_status = DID_OK; | 1995 | /* Fallthrough */ |
1980 | break; | 1996 | case CAM_SCSI_STATUS_ERROR: |
1981 | case CAM_REQ_ABORTED: | 1997 | scsi_status = ahd_cmd_get_scsi_status(cmd); |
1982 | new_status = DID_ABORT; | 1998 | |
1983 | break; | 1999 | switch(scsi_status) { |
1984 | case CAM_BUSY: | 2000 | case SCSI_STATUS_CMD_TERMINATED: |
1985 | new_status = DID_BUS_BUSY; | 2001 | case SCSI_STATUS_CHECK_COND: |
1986 | break; | 2002 | if ((cmd->result >> 24) != DRIVER_SENSE) { |
1987 | case CAM_REQ_INVALID: | 2003 | do_fallback = 1; |
1988 | case CAM_PATH_INVALID: | 2004 | } else { |
1989 | new_status = DID_BAD_TARGET; | 2005 | struct scsi_sense_data *sense; |
1990 | break; | 2006 | |
1991 | case CAM_SEL_TIMEOUT: | 2007 | sense = (struct scsi_sense_data *) |
1992 | new_status = DID_NO_CONNECT; | 2008 | &cmd->sense_buffer; |
1993 | break; | 2009 | if (sense->extra_len >= 5 && |
1994 | case CAM_SCSI_BUS_RESET: | 2010 | (sense->add_sense_code == 0x47 |
1995 | case CAM_BDR_SENT: | 2011 | || sense->add_sense_code == 0x48)) |
1996 | new_status = DID_RESET; | 2012 | do_fallback = 1; |
1997 | break; | 2013 | } |
1998 | case CAM_UNCOR_PARITY: | ||
1999 | new_status = DID_PARITY; | ||
2000 | break; | ||
2001 | case CAM_CMD_TIMEOUT: | ||
2002 | new_status = DID_TIME_OUT; | ||
2003 | break; | ||
2004 | case CAM_UA_ABORT: | ||
2005 | case CAM_REQ_CMP_ERR: | ||
2006 | case CAM_AUTOSENSE_FAIL: | ||
2007 | case CAM_NO_HBA: | ||
2008 | case CAM_DATA_RUN_ERR: | ||
2009 | case CAM_UNEXP_BUSFREE: | ||
2010 | case CAM_SEQUENCE_FAIL: | ||
2011 | case CAM_CCB_LEN_ERR: | ||
2012 | case CAM_PROVIDE_FAIL: | ||
2013 | case CAM_REQ_TERMIO: | ||
2014 | case CAM_UNREC_HBA_ERROR: | ||
2015 | case CAM_REQ_TOO_BIG: | ||
2016 | new_status = DID_ERROR; | ||
2017 | break; | ||
2018 | case CAM_REQUEUE_REQ: | ||
2019 | new_status = DID_REQUEUE; | ||
2020 | break; | 2014 | break; |
2021 | default: | 2015 | default: |
2022 | /* We should never get here */ | ||
2023 | new_status = DID_ERROR; | ||
2024 | break; | 2016 | break; |
2025 | } | 2017 | } |
2026 | 2018 | break; | |
2027 | ahd_cmd_set_transaction_status(cmd, new_status); | 2019 | case CAM_REQ_ABORTED: |
2020 | new_status = DID_ABORT; | ||
2021 | break; | ||
2022 | case CAM_BUSY: | ||
2023 | new_status = DID_BUS_BUSY; | ||
2024 | break; | ||
2025 | case CAM_REQ_INVALID: | ||
2026 | case CAM_PATH_INVALID: | ||
2027 | new_status = DID_BAD_TARGET; | ||
2028 | break; | ||
2029 | case CAM_SEL_TIMEOUT: | ||
2030 | new_status = DID_NO_CONNECT; | ||
2031 | break; | ||
2032 | case CAM_SCSI_BUS_RESET: | ||
2033 | case CAM_BDR_SENT: | ||
2034 | new_status = DID_RESET; | ||
2035 | break; | ||
2036 | case CAM_UNCOR_PARITY: | ||
2037 | new_status = DID_PARITY; | ||
2038 | do_fallback = 1; | ||
2039 | break; | ||
2040 | case CAM_CMD_TIMEOUT: | ||
2041 | new_status = DID_TIME_OUT; | ||
2042 | do_fallback = 1; | ||
2043 | break; | ||
2044 | case CAM_REQ_CMP_ERR: | ||
2045 | case CAM_UNEXP_BUSFREE: | ||
2046 | case CAM_DATA_RUN_ERR: | ||
2047 | new_status = DID_ERROR; | ||
2048 | do_fallback = 1; | ||
2049 | break; | ||
2050 | case CAM_UA_ABORT: | ||
2051 | case CAM_NO_HBA: | ||
2052 | case CAM_SEQUENCE_FAIL: | ||
2053 | case CAM_CCB_LEN_ERR: | ||
2054 | case CAM_PROVIDE_FAIL: | ||
2055 | case CAM_REQ_TERMIO: | ||
2056 | case CAM_UNREC_HBA_ERROR: | ||
2057 | case CAM_REQ_TOO_BIG: | ||
2058 | new_status = DID_ERROR; | ||
2059 | break; | ||
2060 | case CAM_REQUEUE_REQ: | ||
2061 | new_status = DID_REQUEUE; | ||
2062 | break; | ||
2063 | default: | ||
2064 | /* We should never get here */ | ||
2065 | new_status = DID_ERROR; | ||
2066 | break; | ||
2028 | } | 2067 | } |
2029 | 2068 | ||
2030 | cmd->scsi_done(cmd); | 2069 | if (do_fallback) { |
2031 | } | 2070 | printf("%s: device overrun (status %x) on %d:%d:%d\n", |
2032 | 2071 | ahd_name(ahd), status, cmd->device->channel, | |
2033 | static void | 2072 | cmd->device->id, cmd->device->lun); |
2034 | ahd_linux_sem_timeout(u_long arg) | 2073 | } |
2035 | { | ||
2036 | struct ahd_softc *ahd; | ||
2037 | u_long s; | ||
2038 | 2074 | ||
2039 | ahd = (struct ahd_softc *)arg; | 2075 | ahd_cmd_set_transaction_status(cmd, new_status); |
2040 | 2076 | ||
2041 | ahd_lock(ahd, &s); | 2077 | cmd->scsi_done(cmd); |
2042 | if ((ahd->platform_data->flags & AHD_SCB_UP_EH_SEM) != 0) { | ||
2043 | ahd->platform_data->flags &= ~AHD_SCB_UP_EH_SEM; | ||
2044 | up(&ahd->platform_data->eh_sem); | ||
2045 | } | ||
2046 | ahd_unlock(ahd, &s); | ||
2047 | } | 2078 | } |
2048 | 2079 | ||
2049 | void | 2080 | void |
2050 | ahd_freeze_simq(struct ahd_softc *ahd) | 2081 | ahd_freeze_simq(struct ahd_softc *ahd) |
2051 | { | 2082 | { |
2052 | unsigned long s; | 2083 | scsi_block_requests(ahd->platform_data->host); |
2053 | |||
2054 | ahd_lock(ahd, &s); | ||
2055 | ahd->platform_data->qfrozen++; | ||
2056 | if (ahd->platform_data->qfrozen == 1) { | ||
2057 | scsi_block_requests(ahd->platform_data->host); | ||
2058 | ahd_platform_abort_scbs(ahd, CAM_TARGET_WILDCARD, ALL_CHANNELS, | ||
2059 | CAM_LUN_WILDCARD, SCB_LIST_NULL, | ||
2060 | ROLE_INITIATOR, CAM_REQUEUE_REQ); | ||
2061 | } | ||
2062 | ahd_unlock(ahd, &s); | ||
2063 | } | 2084 | } |
2064 | 2085 | ||
2065 | void | 2086 | void |
2066 | ahd_release_simq(struct ahd_softc *ahd) | 2087 | ahd_release_simq(struct ahd_softc *ahd) |
2067 | { | 2088 | { |
2068 | u_long s; | 2089 | scsi_unblock_requests(ahd->platform_data->host); |
2069 | int unblock_reqs; | ||
2070 | |||
2071 | unblock_reqs = 0; | ||
2072 | ahd_lock(ahd, &s); | ||
2073 | if (ahd->platform_data->qfrozen > 0) | ||
2074 | ahd->platform_data->qfrozen--; | ||
2075 | if (ahd->platform_data->qfrozen == 0) { | ||
2076 | unblock_reqs = 1; | ||
2077 | } | ||
2078 | ahd_unlock(ahd, &s); | ||
2079 | /* | ||
2080 | * There is still a race here. The mid-layer | ||
2081 | * should keep its own freeze count and use | ||
2082 | * a bottom half handler to run the queues | ||
2083 | * so we can unblock with our own lock held. | ||
2084 | */ | ||
2085 | if (unblock_reqs) | ||
2086 | scsi_unblock_requests(ahd->platform_data->host); | ||
2087 | } | 2090 | } |
2088 | 2091 | ||
2089 | static int | 2092 | static int |
2090 | ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) | 2093 | ahd_linux_queue_abort_cmd(struct scsi_cmnd *cmd) |
2091 | { | 2094 | { |
2092 | struct ahd_softc *ahd; | 2095 | struct ahd_softc *ahd; |
2093 | struct ahd_linux_device *dev; | 2096 | struct ahd_linux_device *dev; |
@@ -2102,7 +2105,6 @@ ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) | |||
2102 | int paused; | 2105 | int paused; |
2103 | int wait; | 2106 | int wait; |
2104 | int disconnected; | 2107 | int disconnected; |
2105 | int found; | ||
2106 | ahd_mode_state saved_modes; | 2108 | ahd_mode_state saved_modes; |
2107 | unsigned long flags; | 2109 | unsigned long flags; |
2108 | 2110 | ||
@@ -2112,8 +2114,7 @@ ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) | |||
2112 | ahd = *(struct ahd_softc **)cmd->device->host->hostdata; | 2114 | ahd = *(struct ahd_softc **)cmd->device->host->hostdata; |
2113 | 2115 | ||
2114 | scmd_printk(KERN_INFO, cmd, | 2116 | scmd_printk(KERN_INFO, cmd, |
2115 | "Attempting to queue a%s message:", | 2117 | "Attempting to queue an ABORT message:"); |
2116 | flag == SCB_ABORT ? "n ABORT" : " TARGET RESET"); | ||
2117 | 2118 | ||
2118 | printf("CDB:"); | 2119 | printf("CDB:"); |
2119 | for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++) | 2120 | for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++) |
@@ -2149,19 +2150,6 @@ ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) | |||
2149 | break; | 2150 | break; |
2150 | } | 2151 | } |
2151 | 2152 | ||
2152 | if (pending_scb == NULL && flag == SCB_DEVICE_RESET) { | ||
2153 | |||
2154 | /* Any SCB for this device will do for a target reset */ | ||
2155 | LIST_FOREACH(pending_scb, &ahd->pending_scbs, pending_links) { | ||
2156 | if (ahd_match_scb(ahd, pending_scb, | ||
2157 | scmd_id(cmd), | ||
2158 | scmd_channel(cmd) + 'A', | ||
2159 | CAM_LUN_WILDCARD, | ||
2160 | SCB_LIST_NULL, ROLE_INITIATOR)) | ||
2161 | break; | ||
2162 | } | ||
2163 | } | ||
2164 | |||
2165 | if (pending_scb == NULL) { | 2153 | if (pending_scb == NULL) { |
2166 | scmd_printk(KERN_INFO, cmd, "Command not found\n"); | 2154 | scmd_printk(KERN_INFO, cmd, "Command not found\n"); |
2167 | goto no_cmd; | 2155 | goto no_cmd; |
@@ -2195,25 +2183,17 @@ ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) | |||
2195 | ahd_dump_card_state(ahd); | 2183 | ahd_dump_card_state(ahd); |
2196 | 2184 | ||
2197 | disconnected = TRUE; | 2185 | disconnected = TRUE; |
2198 | if (flag == SCB_ABORT) { | 2186 | if (ahd_search_qinfifo(ahd, cmd->device->id, |
2199 | if (ahd_search_qinfifo(ahd, cmd->device->id, | 2187 | cmd->device->channel + 'A', |
2200 | cmd->device->channel + 'A', | 2188 | cmd->device->lun, |
2201 | cmd->device->lun, | 2189 | pending_scb->hscb->tag, |
2202 | pending_scb->hscb->tag, | 2190 | ROLE_INITIATOR, CAM_REQ_ABORTED, |
2203 | ROLE_INITIATOR, CAM_REQ_ABORTED, | 2191 | SEARCH_COMPLETE) > 0) { |
2204 | SEARCH_COMPLETE) > 0) { | 2192 | printf("%s:%d:%d:%d: Cmd aborted from QINFIFO\n", |
2205 | printf("%s:%d:%d:%d: Cmd aborted from QINFIFO\n", | 2193 | ahd_name(ahd), cmd->device->channel, |
2206 | ahd_name(ahd), cmd->device->channel, | 2194 | cmd->device->id, cmd->device->lun); |
2207 | cmd->device->id, cmd->device->lun); | 2195 | retval = SUCCESS; |
2208 | retval = SUCCESS; | 2196 | goto done; |
2209 | goto done; | ||
2210 | } | ||
2211 | } else if (ahd_search_qinfifo(ahd, cmd->device->id, | ||
2212 | cmd->device->channel + 'A', | ||
2213 | cmd->device->lun, pending_scb->hscb->tag, | ||
2214 | ROLE_INITIATOR, /*status*/0, | ||
2215 | SEARCH_COUNT) > 0) { | ||
2216 | disconnected = FALSE; | ||
2217 | } | 2197 | } |
2218 | 2198 | ||
2219 | saved_modes = ahd_save_modes(ahd); | 2199 | saved_modes = ahd_save_modes(ahd); |
@@ -2221,17 +2201,12 @@ ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) | |||
2221 | last_phase = ahd_inb(ahd, LASTPHASE); | 2201 | last_phase = ahd_inb(ahd, LASTPHASE); |
2222 | saved_scbptr = ahd_get_scbptr(ahd); | 2202 | saved_scbptr = ahd_get_scbptr(ahd); |
2223 | active_scbptr = saved_scbptr; | 2203 | active_scbptr = saved_scbptr; |
2224 | if (disconnected && ((last_phase != P_BUSFREE) || | 2204 | if (disconnected && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) == 0) { |
2225 | (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) == 0)) { | ||
2226 | struct scb *bus_scb; | 2205 | struct scb *bus_scb; |
2227 | 2206 | ||
2228 | bus_scb = ahd_lookup_scb(ahd, active_scbptr); | 2207 | bus_scb = ahd_lookup_scb(ahd, active_scbptr); |
2229 | if (bus_scb == pending_scb) | 2208 | if (bus_scb == pending_scb) |
2230 | disconnected = FALSE; | 2209 | disconnected = FALSE; |
2231 | else if (flag != SCB_ABORT | ||
2232 | && ahd_inb(ahd, SAVED_SCSIID) == pending_scb->hscb->scsiid | ||
2233 | && ahd_inb(ahd, SAVED_LUN) == SCB_GET_LUN(pending_scb)) | ||
2234 | disconnected = FALSE; | ||
2235 | } | 2210 | } |
2236 | 2211 | ||
2237 | /* | 2212 | /* |
@@ -2240,41 +2215,26 @@ ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) | |||
2240 | * bus or is in the disconnected state. | 2215 | * bus or is in the disconnected state. |
2241 | */ | 2216 | */ |
2242 | saved_scsiid = ahd_inb(ahd, SAVED_SCSIID); | 2217 | saved_scsiid = ahd_inb(ahd, SAVED_SCSIID); |
2243 | if (SCB_GET_TAG(pending_scb) == active_scbptr | 2218 | if (last_phase != P_BUSFREE |
2244 | || (flag == SCB_DEVICE_RESET | 2219 | && SCB_GET_TAG(pending_scb) == active_scbptr) { |
2245 | && SCSIID_TARGET(ahd, saved_scsiid) == scmd_id(cmd))) { | ||
2246 | 2220 | ||
2247 | /* | 2221 | /* |
2248 | * We're active on the bus, so assert ATN | 2222 | * We're active on the bus, so assert ATN |
2249 | * and hope that the target responds. | 2223 | * and hope that the target responds. |
2250 | */ | 2224 | */ |
2251 | pending_scb = ahd_lookup_scb(ahd, active_scbptr); | 2225 | pending_scb = ahd_lookup_scb(ahd, active_scbptr); |
2252 | pending_scb->flags |= SCB_RECOVERY_SCB|SCB_DEVICE_RESET; | 2226 | pending_scb->flags |= SCB_RECOVERY_SCB|SCB_ABORT; |
2253 | ahd_outb(ahd, MSG_OUT, HOST_MSG); | 2227 | ahd_outb(ahd, MSG_OUT, HOST_MSG); |
2254 | ahd_outb(ahd, SCSISIGO, last_phase|ATNO); | 2228 | ahd_outb(ahd, SCSISIGO, last_phase|ATNO); |
2255 | scmd_printk(KERN_INFO, cmd, "BDR message in message buffer\n"); | 2229 | scmd_printk(KERN_INFO, cmd, "Device is active, asserting ATN\n"); |
2256 | wait = TRUE; | 2230 | wait = TRUE; |
2257 | } else if (last_phase != P_BUSFREE | ||
2258 | && ahd_inb(ahd, SCSIPHASE) == 0) { | ||
2259 | /* | ||
2260 | * SCB is not identified, there | ||
2261 | * is no pending REQ, and the sequencer | ||
2262 | * has not seen a busfree. Looks like | ||
2263 | * a stuck connection waiting to | ||
2264 | * go busfree. Reset the bus. | ||
2265 | */ | ||
2266 | found = ahd_reset_channel(ahd, cmd->device->channel + 'A', | ||
2267 | /*Initiate Reset*/TRUE); | ||
2268 | printf("%s: Issued Channel %c Bus Reset. " | ||
2269 | "%d SCBs aborted\n", ahd_name(ahd), | ||
2270 | cmd->device->channel + 'A', found); | ||
2271 | } else if (disconnected) { | 2231 | } else if (disconnected) { |
2272 | 2232 | ||
2273 | /* | 2233 | /* |
2274 | * Actually re-queue this SCB in an attempt | 2234 | * Actually re-queue this SCB in an attempt |
2275 | * to select the device before it reconnects. | 2235 | * to select the device before it reconnects. |
2276 | */ | 2236 | */ |
2277 | pending_scb->flags |= SCB_RECOVERY_SCB|flag; | 2237 | pending_scb->flags |= SCB_RECOVERY_SCB|SCB_ABORT; |
2278 | ahd_set_scbptr(ahd, SCB_GET_TAG(pending_scb)); | 2238 | ahd_set_scbptr(ahd, SCB_GET_TAG(pending_scb)); |
2279 | pending_scb->hscb->cdb_len = 0; | 2239 | pending_scb->hscb->cdb_len = 0; |
2280 | pending_scb->hscb->task_attribute = 0; | 2240 | pending_scb->hscb->task_attribute = 0; |
@@ -2344,30 +2304,29 @@ done: | |||
2344 | if (paused) | 2304 | if (paused) |
2345 | ahd_unpause(ahd); | 2305 | ahd_unpause(ahd); |
2346 | if (wait) { | 2306 | if (wait) { |
2347 | struct timer_list timer; | 2307 | DECLARE_COMPLETION(done); |
2348 | int ret; | ||
2349 | 2308 | ||
2350 | ahd->platform_data->flags |= AHD_SCB_UP_EH_SEM; | 2309 | ahd->platform_data->eh_done = &done; |
2351 | ahd_unlock(ahd, &flags); | 2310 | ahd_unlock(ahd, &flags); |
2352 | 2311 | ||
2353 | init_timer(&timer); | ||
2354 | timer.data = (u_long)ahd; | ||
2355 | timer.expires = jiffies + (5 * HZ); | ||
2356 | timer.function = ahd_linux_sem_timeout; | ||
2357 | add_timer(&timer); | ||
2358 | printf("%s: Recovery code sleeping\n", ahd_name(ahd)); | 2312 | printf("%s: Recovery code sleeping\n", ahd_name(ahd)); |
2359 | down(&ahd->platform_data->eh_sem); | 2313 | if (!wait_for_completion_timeout(&done, 5 * HZ)) { |
2360 | printf("%s: Recovery code awake\n", ahd_name(ahd)); | 2314 | ahd_lock(ahd, &flags); |
2361 | ret = del_timer_sync(&timer); | 2315 | ahd->platform_data->eh_done = NULL; |
2362 | if (ret == 0) { | 2316 | ahd_unlock(ahd, &flags); |
2363 | printf("%s: Timer Expired (active %d)\n", | 2317 | printf("%s: Timer Expired (active %d)\n", |
2364 | ahd_name(ahd), dev->active); | 2318 | ahd_name(ahd), dev->active); |
2365 | retval = FAILED; | 2319 | retval = FAILED; |
2366 | } | 2320 | } |
2321 | printf("Recovery code awake\n"); | ||
2367 | } else | 2322 | } else |
2368 | ahd_unlock(ahd, &flags); | 2323 | ahd_unlock(ahd, &flags); |
2369 | 2324 | ||
2370 | return (retval); | 2325 | if (retval != SUCCESS) |
2326 | printf("%s: Command abort returning 0x%x\n", | ||
2327 | ahd_name(ahd), retval); | ||
2328 | |||
2329 | return retval; | ||
2371 | } | 2330 | } |
2372 | 2331 | ||
2373 | static void ahd_linux_set_width(struct scsi_target *starget, int width) | 2332 | static void ahd_linux_set_width(struct scsi_target *starget, int width) |