aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@steeleye.com>2005-05-17 19:07:34 -0400
committerJames Bottomley <jejb@titanic.(none)>2005-05-20 16:54:42 -0400
commitc7525233d2df39b95552f6f49c6b390a9c4d2e80 (patch)
tree6a2336435ea1a2bf1ae6b445d6b1109e0599a2a3
parent8e45ebcc661069bfb002c56dd942aedf43ba9239 (diff)
[SCSI] aic7xxx: make correct use of slave_alloc/destroy and remove the per device timer
The allocation of all of our components should be done in slave alloc. Currently it's rather fancifully refcounted in the queuecommand callback. This patch moves allocation and destroy to their correct places in slave_alloc/slave_destory. Now we can guarantee that everywhere a device is requested, it's actually been allocated, so don't check for this anymore. Additionally, the per device busy timer was the only source of potential use after free. It's been deleted because Linux does the correct thing with busy returns, so there's no need to implement a separate timer in the driver. Finally, implement code that forces all the device parameters to zero (i.e. async and narrow) in the slave alloc, inform the spi class of the bios recorded maximums and wait until slave configure before trying anything more adventurous. Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.c183
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.h8
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,
430static void ahc_linux_sem_timeout(u_long arg); 430static void ahc_linux_sem_timeout(u_long arg);
431static void ahc_linux_freeze_simq(struct ahc_softc *ahc); 431static void ahc_linux_freeze_simq(struct ahc_softc *ahc);
432static void ahc_linux_release_simq(u_long arg); 432static void ahc_linux_release_simq(u_long arg);
433static void ahc_linux_dev_timed_unfreeze(u_long arg);
434static int ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag); 433static int ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag);
435static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc); 434static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc);
436static u_int ahc_linux_user_tagdepth(struct ahc_softc *ahc, 435static 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 ************************************/
458static __inline struct ahc_linux_device* 457static __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);
461static __inline void ahc_linux_unmap_scb(struct ahc_softc*, struct scb*); 460static __inline void ahc_linux_unmap_scb(struct ahc_softc*, struct scb*);
462 461
463static __inline int ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb, 462static __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
467static __inline struct ahc_linux_device* 466static __inline struct ahc_linux_device*
468ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, u_int target, 467ahc_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
493static __inline void 483static __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
652ahc_linux_slave_alloc(struct scsi_device *device) 642ahc_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
662static int 710static 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
692static void 733static 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
1819static void 1847static void
1820__ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev) 1848ahc_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
1832static void
1833ahc_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
1839void 1860void
1840ahc_send_async(struct ahc_softc *ahc, char channel, 1861ahc_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
2329static void
2330ahc_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
2347static int 2322static int
2348ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) 2323ahc_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 */
323TAILQ_HEAD(ahc_busyq, ahc_cmd); 323TAILQ_HEAD(ahc_busyq, ahc_cmd);
324typedef enum { 324typedef 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
334struct ahc_linux_target; 331struct 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;