diff options
Diffstat (limited to 'drivers/scsi/aic7xxx')
-rw-r--r-- | drivers/scsi/aic7xxx/aic7xxx_osm.c | 183 | ||||
-rw-r--r-- | drivers/scsi/aic7xxx/aic7xxx_osm.h | 8 |
2 files changed, 79 insertions, 112 deletions
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index ca796b9d737b..c03f29486071 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c | |||
@@ -430,7 +430,6 @@ static void ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, | |||
430 | static void ahc_linux_sem_timeout(u_long arg); | 430 | static void ahc_linux_sem_timeout(u_long arg); |
431 | static void ahc_linux_freeze_simq(struct ahc_softc *ahc); | 431 | static void ahc_linux_freeze_simq(struct ahc_softc *ahc); |
432 | static void ahc_linux_release_simq(u_long arg); | 432 | static void ahc_linux_release_simq(u_long arg); |
433 | static void ahc_linux_dev_timed_unfreeze(u_long arg); | ||
434 | static int ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag); | 433 | static int ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag); |
435 | static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc); | 434 | static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc); |
436 | static u_int ahc_linux_user_tagdepth(struct ahc_softc *ahc, | 435 | static u_int ahc_linux_user_tagdepth(struct ahc_softc *ahc, |
@@ -457,7 +456,7 @@ static int ahc_linux_next_unit(void); | |||
457 | /********************************* Inlines ************************************/ | 456 | /********************************* Inlines ************************************/ |
458 | static __inline struct ahc_linux_device* | 457 | static __inline struct ahc_linux_device* |
459 | ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, | 458 | ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, |
460 | u_int target, u_int lun, int alloc); | 459 | u_int target, u_int lun); |
461 | static __inline void ahc_linux_unmap_scb(struct ahc_softc*, struct scb*); | 460 | static __inline void ahc_linux_unmap_scb(struct ahc_softc*, struct scb*); |
462 | 461 | ||
463 | static __inline int ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb, | 462 | static __inline int ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb, |
@@ -466,7 +465,7 @@ static __inline int ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb, | |||
466 | 465 | ||
467 | static __inline struct ahc_linux_device* | 466 | static __inline struct ahc_linux_device* |
468 | ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, u_int target, | 467 | ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, u_int target, |
469 | u_int lun, int alloc) | 468 | u_int lun) |
470 | { | 469 | { |
471 | struct ahc_linux_target *targ; | 470 | struct ahc_linux_target *targ; |
472 | struct ahc_linux_device *dev; | 471 | struct ahc_linux_device *dev; |
@@ -476,18 +475,9 @@ ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, u_int target, | |||
476 | if (channel != 0) | 475 | if (channel != 0) |
477 | target_offset += 8; | 476 | target_offset += 8; |
478 | targ = ahc->platform_data->targets[target_offset]; | 477 | targ = ahc->platform_data->targets[target_offset]; |
479 | if (targ == NULL) { | 478 | BUG_ON(targ == NULL); |
480 | if (alloc != 0) { | ||
481 | targ = ahc_linux_alloc_target(ahc, channel, target); | ||
482 | if (targ == NULL) | ||
483 | return (NULL); | ||
484 | } else | ||
485 | return (NULL); | ||
486 | } | ||
487 | dev = targ->devices[lun]; | 479 | dev = targ->devices[lun]; |
488 | if (dev == NULL && alloc != 0) | 480 | return dev; |
489 | dev = ahc_linux_alloc_device(ahc, targ, lun); | ||
490 | return (dev); | ||
491 | } | 481 | } |
492 | 482 | ||
493 | static __inline void | 483 | static __inline void |
@@ -640,7 +630,7 @@ ahc_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *)) | |||
640 | return SCSI_MLQUEUE_HOST_BUSY; | 630 | return SCSI_MLQUEUE_HOST_BUSY; |
641 | 631 | ||
642 | dev = ahc_linux_get_device(ahc, cmd->device->channel, cmd->device->id, | 632 | dev = ahc_linux_get_device(ahc, cmd->device->channel, cmd->device->id, |
643 | cmd->device->lun, /*alloc*/TRUE); | 633 | cmd->device->lun); |
644 | BUG_ON(dev == NULL); | 634 | BUG_ON(dev == NULL); |
645 | 635 | ||
646 | cmd->result = CAM_REQ_INPROG << 16; | 636 | cmd->result = CAM_REQ_INPROG << 16; |
@@ -652,11 +642,69 @@ static int | |||
652 | ahc_linux_slave_alloc(struct scsi_device *device) | 642 | ahc_linux_slave_alloc(struct scsi_device *device) |
653 | { | 643 | { |
654 | struct ahc_softc *ahc; | 644 | struct ahc_softc *ahc; |
645 | struct ahc_linux_target *targ; | ||
646 | struct scsi_target *starget = device->sdev_target; | ||
647 | struct ahc_linux_device *dev; | ||
648 | u_int target_offset; | ||
649 | |||
650 | target_offset = starget->id; | ||
651 | if (starget->channel != 0) | ||
652 | target_offset += 8; | ||
655 | 653 | ||
656 | ahc = *((struct ahc_softc **)device->host->hostdata); | 654 | ahc = *((struct ahc_softc **)device->host->hostdata); |
657 | if (bootverbose) | 655 | if (bootverbose) |
658 | printf("%s: Slave Alloc %d\n", ahc_name(ahc), device->id); | 656 | printf("%s: Slave Alloc %d\n", ahc_name(ahc), device->id); |
659 | return (0); | 657 | targ = ahc->platform_data->targets[target_offset]; |
658 | if (targ == NULL) { | ||
659 | targ = ahc_linux_alloc_target(ahc, starget->channel, starget->id); | ||
660 | struct seeprom_config *sc = ahc->seep_config; | ||
661 | if (targ == NULL) | ||
662 | return -ENOMEM; | ||
663 | if (sc) { | ||
664 | unsigned short scsirate; | ||
665 | struct ahc_devinfo devinfo; | ||
666 | struct ahc_initiator_tinfo *tinfo; | ||
667 | struct ahc_tmode_tstate *tstate; | ||
668 | char channel = starget->channel + 'A'; | ||
669 | unsigned int our_id = ahc->our_id; | ||
670 | |||
671 | if (starget->channel) | ||
672 | our_id = ahc->our_id_b; | ||
673 | |||
674 | if ((ahc->features & AHC_ULTRA2) != 0) { | ||
675 | scsirate = sc->device_flags[target_offset] & CFXFER; | ||
676 | } else { | ||
677 | scsirate = (sc->device_flags[target_offset] & CFXFER) << 4; | ||
678 | if (sc->device_flags[target_offset] & CFSYNCH) | ||
679 | scsirate |= SOFS; | ||
680 | } | ||
681 | if (sc->device_flags[target_offset] & CFWIDEB) { | ||
682 | scsirate |= WIDEXFER; | ||
683 | spi_max_width(starget) = 1; | ||
684 | } else | ||
685 | spi_max_width(starget) = 0; | ||
686 | spi_min_period(starget) = | ||
687 | ahc_find_period(ahc, scsirate, AHC_SYNCRATE_DT); | ||
688 | tinfo = ahc_fetch_transinfo(ahc, channel, ahc->our_id, | ||
689 | targ->target, &tstate); | ||
690 | ahc_compile_devinfo(&devinfo, our_id, targ->target, | ||
691 | CAM_LUN_WILDCARD, channel, | ||
692 | ROLE_INITIATOR); | ||
693 | ahc_set_syncrate(ahc, &devinfo, NULL, 0, 0, 0, | ||
694 | AHC_TRANS_GOAL, /*paused*/FALSE); | ||
695 | ahc_set_width(ahc, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, | ||
696 | AHC_TRANS_GOAL, /*paused*/FALSE); | ||
697 | } | ||
698 | |||
699 | } | ||
700 | dev = targ->devices[device->lun]; | ||
701 | if (dev == NULL) { | ||
702 | dev = ahc_linux_alloc_device(ahc, targ, device->lun); | ||
703 | if (dev == NULL) | ||
704 | return -ENOMEM; | ||
705 | } | ||
706 | |||
707 | return 0; | ||
660 | } | 708 | } |
661 | 709 | ||
662 | static int | 710 | static int |
@@ -666,27 +714,20 @@ ahc_linux_slave_configure(struct scsi_device *device) | |||
666 | struct ahc_linux_device *dev; | 714 | struct ahc_linux_device *dev; |
667 | 715 | ||
668 | ahc = *((struct ahc_softc **)device->host->hostdata); | 716 | ahc = *((struct ahc_softc **)device->host->hostdata); |
717 | |||
669 | if (bootverbose) | 718 | if (bootverbose) |
670 | printf("%s: Slave Configure %d\n", ahc_name(ahc), device->id); | 719 | printf("%s: Slave Configure %d\n", ahc_name(ahc), device->id); |
671 | /* | 720 | |
672 | * Since Linux has attached to the device, configure | 721 | dev = ahc_linux_get_device(ahc, device->channel, device->id, |
673 | * it so we don't free and allocate the device | 722 | device->lun); |
674 | * structure on every command. | 723 | dev->scsi_device = device; |
675 | */ | 724 | ahc_linux_device_queue_depth(ahc, dev); |
676 | dev = ahc_linux_get_device(ahc, device->channel, | ||
677 | device->id, device->lun, | ||
678 | /*alloc*/TRUE); | ||
679 | if (dev != NULL) { | ||
680 | dev->flags &= ~AHC_DEV_UNCONFIGURED; | ||
681 | dev->scsi_device = device; | ||
682 | ahc_linux_device_queue_depth(ahc, dev); | ||
683 | } | ||
684 | 725 | ||
685 | /* Initial Domain Validation */ | 726 | /* Initial Domain Validation */ |
686 | if (!spi_initial_dv(device->sdev_target)) | 727 | if (!spi_initial_dv(device->sdev_target)) |
687 | spi_dv_device(device); | 728 | spi_dv_device(device); |
688 | 729 | ||
689 | return (0); | 730 | return 0; |
690 | } | 731 | } |
691 | 732 | ||
692 | static void | 733 | static void |
@@ -699,22 +740,11 @@ ahc_linux_slave_destroy(struct scsi_device *device) | |||
699 | if (bootverbose) | 740 | if (bootverbose) |
700 | printf("%s: Slave Destroy %d\n", ahc_name(ahc), device->id); | 741 | printf("%s: Slave Destroy %d\n", ahc_name(ahc), device->id); |
701 | dev = ahc_linux_get_device(ahc, device->channel, | 742 | dev = ahc_linux_get_device(ahc, device->channel, |
702 | device->id, device->lun, | 743 | device->id, device->lun); |
703 | /*alloc*/FALSE); | 744 | |
704 | /* | 745 | BUG_ON(dev->active); |
705 | * Filter out "silly" deletions of real devices by only | 746 | |
706 | * deleting devices that have had slave_configure() | 747 | ahc_linux_free_device(ahc, dev); |
707 | * called on them. All other devices that have not | ||
708 | * been configured will automatically be deleted by | ||
709 | * the refcounting process. | ||
710 | */ | ||
711 | if (dev != NULL | ||
712 | && (dev->flags & AHC_DEV_SLAVE_CONFIGURED) != 0) { | ||
713 | dev->flags |= AHC_DEV_UNCONFIGURED; | ||
714 | if (dev->active == 0 | ||
715 | && (dev->flags & AHC_DEV_TIMER_ACTIVE) == 0) | ||
716 | ahc_linux_free_device(ahc, dev); | ||
717 | } | ||
718 | } | 748 | } |
719 | 749 | ||
720 | #if defined(__i386__) | 750 | #if defined(__i386__) |
@@ -1361,7 +1391,7 @@ ahc_platform_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, | |||
1361 | 1391 | ||
1362 | dev = ahc_linux_get_device(ahc, devinfo->channel - 'A', | 1392 | dev = ahc_linux_get_device(ahc, devinfo->channel - 'A', |
1363 | devinfo->target, | 1393 | devinfo->target, |
1364 | devinfo->lun, /*alloc*/FALSE); | 1394 | devinfo->lun); |
1365 | if (dev == NULL) | 1395 | if (dev == NULL) |
1366 | return; | 1396 | return; |
1367 | was_queuing = dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED); | 1397 | was_queuing = dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED); |
@@ -1793,8 +1823,6 @@ ahc_linux_alloc_device(struct ahc_softc *ahc, | |||
1793 | if (dev == NULL) | 1823 | if (dev == NULL) |
1794 | return (NULL); | 1824 | return (NULL); |
1795 | memset(dev, 0, sizeof(*dev)); | 1825 | memset(dev, 0, sizeof(*dev)); |
1796 | init_timer(&dev->timer); | ||
1797 | dev->flags = AHC_DEV_UNCONFIGURED; | ||
1798 | dev->lun = lun; | 1826 | dev->lun = lun; |
1799 | dev->target = targ; | 1827 | dev->target = targ; |
1800 | 1828 | ||
@@ -1817,7 +1845,7 @@ ahc_linux_alloc_device(struct ahc_softc *ahc, | |||
1817 | } | 1845 | } |
1818 | 1846 | ||
1819 | static void | 1847 | static void |
1820 | __ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev) | 1848 | ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev) |
1821 | { | 1849 | { |
1822 | struct ahc_linux_target *targ; | 1850 | struct ahc_linux_target *targ; |
1823 | 1851 | ||
@@ -1829,13 +1857,6 @@ __ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev) | |||
1829 | ahc_linux_free_target(ahc, targ); | 1857 | ahc_linux_free_target(ahc, targ); |
1830 | } | 1858 | } |
1831 | 1859 | ||
1832 | static void | ||
1833 | ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev) | ||
1834 | { | ||
1835 | del_timer_sync(&dev->timer); | ||
1836 | __ahc_linux_free_device(ahc, dev); | ||
1837 | } | ||
1838 | |||
1839 | void | 1860 | void |
1840 | ahc_send_async(struct ahc_softc *ahc, char channel, | 1861 | ahc_send_async(struct ahc_softc *ahc, char channel, |
1841 | u_int target, u_int lun, ac_code code, void *arg) | 1862 | u_int target, u_int lun, ac_code code, void *arg) |
@@ -2008,8 +2029,6 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb) | |||
2008 | } | 2029 | } |
2009 | } else if (ahc_get_transaction_status(scb) == CAM_SCSI_STATUS_ERROR) { | 2030 | } else if (ahc_get_transaction_status(scb) == CAM_SCSI_STATUS_ERROR) { |
2010 | ahc_linux_handle_scsi_status(ahc, dev, scb); | 2031 | ahc_linux_handle_scsi_status(ahc, dev, scb); |
2011 | } else if (ahc_get_transaction_status(scb) == CAM_SEL_TIMEOUT) { | ||
2012 | dev->flags |= AHC_DEV_UNCONFIGURED; | ||
2013 | } | 2032 | } |
2014 | 2033 | ||
2015 | if (dev->openings == 1 | 2034 | if (dev->openings == 1 |
@@ -2031,11 +2050,6 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb) | |||
2031 | if (dev->active == 0) | 2050 | if (dev->active == 0) |
2032 | dev->commands_since_idle_or_otag = 0; | 2051 | dev->commands_since_idle_or_otag = 0; |
2033 | 2052 | ||
2034 | if ((dev->flags & AHC_DEV_UNCONFIGURED) != 0 | ||
2035 | && dev->active == 0 | ||
2036 | && (dev->flags & AHC_DEV_TIMER_ACTIVE) == 0) | ||
2037 | ahc_linux_free_device(ahc, dev); | ||
2038 | |||
2039 | if ((scb->flags & SCB_RECOVERY_SCB) != 0) { | 2053 | if ((scb->flags & SCB_RECOVERY_SCB) != 0) { |
2040 | printf("Recovery SCB completes\n"); | 2054 | printf("Recovery SCB completes\n"); |
2041 | if (ahc_get_transaction_status(scb) == CAM_BDR_SENT | 2055 | if (ahc_get_transaction_status(scb) == CAM_BDR_SENT |
@@ -2174,27 +2188,6 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc, | |||
2174 | ahc_platform_set_tags(ahc, &devinfo, | 2188 | ahc_platform_set_tags(ahc, &devinfo, |
2175 | (dev->flags & AHC_DEV_Q_BASIC) | 2189 | (dev->flags & AHC_DEV_Q_BASIC) |
2176 | ? AHC_QUEUE_BASIC : AHC_QUEUE_TAGGED); | 2190 | ? AHC_QUEUE_BASIC : AHC_QUEUE_TAGGED); |
2177 | /* FALLTHROUGH */ | ||
2178 | } | ||
2179 | case SCSI_STATUS_BUSY: | ||
2180 | { | ||
2181 | /* | ||
2182 | * Set a short timer to defer sending commands for | ||
2183 | * a bit since Linux will not delay in this case. | ||
2184 | */ | ||
2185 | if ((dev->flags & AHC_DEV_TIMER_ACTIVE) != 0) { | ||
2186 | printf("%s:%c:%d: Device Timer still active during " | ||
2187 | "busy processing\n", ahc_name(ahc), | ||
2188 | dev->target->channel, dev->target->target); | ||
2189 | break; | ||
2190 | } | ||
2191 | dev->flags |= AHC_DEV_TIMER_ACTIVE; | ||
2192 | dev->qfrozen++; | ||
2193 | init_timer(&dev->timer); | ||
2194 | dev->timer.data = (u_long)dev; | ||
2195 | dev->timer.expires = jiffies + (HZ/2); | ||
2196 | dev->timer.function = ahc_linux_dev_timed_unfreeze; | ||
2197 | add_timer(&dev->timer); | ||
2198 | break; | 2191 | break; |
2199 | } | 2192 | } |
2200 | } | 2193 | } |
@@ -2326,24 +2319,6 @@ ahc_linux_release_simq(u_long arg) | |||
2326 | scsi_unblock_requests(ahc->platform_data->host); | 2319 | scsi_unblock_requests(ahc->platform_data->host); |
2327 | } | 2320 | } |
2328 | 2321 | ||
2329 | static void | ||
2330 | ahc_linux_dev_timed_unfreeze(u_long arg) | ||
2331 | { | ||
2332 | struct ahc_linux_device *dev; | ||
2333 | struct ahc_softc *ahc; | ||
2334 | u_long s; | ||
2335 | |||
2336 | dev = (struct ahc_linux_device *)arg; | ||
2337 | ahc = dev->target->ahc; | ||
2338 | ahc_lock(ahc, &s); | ||
2339 | dev->flags &= ~AHC_DEV_TIMER_ACTIVE; | ||
2340 | if (dev->qfrozen > 0) | ||
2341 | dev->qfrozen--; | ||
2342 | if (dev->active == 0) | ||
2343 | __ahc_linux_free_device(ahc, dev); | ||
2344 | ahc_unlock(ahc, &s); | ||
2345 | } | ||
2346 | |||
2347 | static int | 2322 | static int |
2348 | ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) | 2323 | ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) |
2349 | { | 2324 | { |
@@ -2384,7 +2359,7 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) | |||
2384 | * command, return success. | 2359 | * command, return success. |
2385 | */ | 2360 | */ |
2386 | dev = ahc_linux_get_device(ahc, cmd->device->channel, cmd->device->id, | 2361 | dev = ahc_linux_get_device(ahc, cmd->device->channel, cmd->device->id, |
2387 | cmd->device->lun, /*alloc*/FALSE); | 2362 | cmd->device->lun); |
2388 | 2363 | ||
2389 | if (dev == NULL) { | 2364 | if (dev == NULL) { |
2390 | /* | 2365 | /* |
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h index e70c1fa47db2..30c200d5bcd5 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.h +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h | |||
@@ -322,13 +322,10 @@ struct ahc_cmd { | |||
322 | */ | 322 | */ |
323 | TAILQ_HEAD(ahc_busyq, ahc_cmd); | 323 | TAILQ_HEAD(ahc_busyq, ahc_cmd); |
324 | typedef enum { | 324 | typedef enum { |
325 | AHC_DEV_UNCONFIGURED = 0x01, | ||
326 | AHC_DEV_FREEZE_TIL_EMPTY = 0x02, /* Freeze queue until active == 0 */ | 325 | AHC_DEV_FREEZE_TIL_EMPTY = 0x02, /* Freeze queue until active == 0 */ |
327 | AHC_DEV_TIMER_ACTIVE = 0x04, /* Our timer is active */ | ||
328 | AHC_DEV_Q_BASIC = 0x10, /* Allow basic device queuing */ | 326 | AHC_DEV_Q_BASIC = 0x10, /* Allow basic device queuing */ |
329 | AHC_DEV_Q_TAGGED = 0x20, /* Allow full SCSI2 command queueing */ | 327 | AHC_DEV_Q_TAGGED = 0x20, /* Allow full SCSI2 command queueing */ |
330 | AHC_DEV_PERIODIC_OTAG = 0x40, /* Send OTAG to prevent starvation */ | 328 | AHC_DEV_PERIODIC_OTAG = 0x40, /* Send OTAG to prevent starvation */ |
331 | AHC_DEV_SLAVE_CONFIGURED = 0x80 /* slave_configure() has been called */ | ||
332 | } ahc_linux_dev_flags; | 329 | } ahc_linux_dev_flags; |
333 | 330 | ||
334 | struct ahc_linux_target; | 331 | struct ahc_linux_target; |
@@ -374,11 +371,6 @@ struct ahc_linux_device { | |||
374 | ahc_linux_dev_flags flags; | 371 | ahc_linux_dev_flags flags; |
375 | 372 | ||
376 | /* | 373 | /* |
377 | * Per device timer. | ||
378 | */ | ||
379 | struct timer_list timer; | ||
380 | |||
381 | /* | ||
382 | * The high limit for the tags variable. | 374 | * The high limit for the tags variable. |
383 | */ | 375 | */ |
384 | u_int maxtags; | 376 | u_int maxtags; |