|
@@ -430,7 +430,6 @@ static void ahc_linux_queue_cmd_complete(struct ahc_softc *ahc,
|
|
|
static void ahc_linux_sem_timeout(u_long arg);
|
|
|
static void ahc_linux_freeze_simq(struct ahc_softc *ahc);
|
|
|
static void ahc_linux_release_simq(u_long arg);
|
|
|
-static void ahc_linux_dev_timed_unfreeze(u_long arg);
|
|
|
static int ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag);
|
|
|
static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc);
|
|
|
static u_int ahc_linux_user_tagdepth(struct ahc_softc *ahc,
|
|
@@ -457,7 +456,7 @@ static int ahc_linux_next_unit(void);
|
|
|
/********************************* Inlines ************************************/
|
|
|
static __inline struct ahc_linux_device*
|
|
|
ahc_linux_get_device(struct ahc_softc *ahc, u_int channel,
|
|
|
- u_int target, u_int lun, int alloc);
|
|
|
+ u_int target, u_int lun);
|
|
|
static __inline void ahc_linux_unmap_scb(struct ahc_softc*, struct scb*);
|
|
|
|
|
|
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,
|
|
|
|
|
|
static __inline struct ahc_linux_device*
|
|
|
ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, u_int target,
|
|
|
- u_int lun, int alloc)
|
|
|
+ u_int lun)
|
|
|
{
|
|
|
struct ahc_linux_target *targ;
|
|
|
struct ahc_linux_device *dev;
|
|
@@ -476,18 +475,9 @@ ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, u_int target,
|
|
|
if (channel != 0)
|
|
|
target_offset += 8;
|
|
|
targ = ahc->platform_data->targets[target_offset];
|
|
|
- if (targ == NULL) {
|
|
|
- if (alloc != 0) {
|
|
|
- targ = ahc_linux_alloc_target(ahc, channel, target);
|
|
|
- if (targ == NULL)
|
|
|
- return (NULL);
|
|
|
- } else
|
|
|
- return (NULL);
|
|
|
- }
|
|
|
+ BUG_ON(targ == NULL);
|
|
|
dev = targ->devices[lun];
|
|
|
- if (dev == NULL && alloc != 0)
|
|
|
- dev = ahc_linux_alloc_device(ahc, targ, lun);
|
|
|
- return (dev);
|
|
|
+ return dev;
|
|
|
}
|
|
|
|
|
|
static __inline void
|
|
@@ -640,7 +630,7 @@ ahc_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *))
|
|
|
return SCSI_MLQUEUE_HOST_BUSY;
|
|
|
|
|
|
dev = ahc_linux_get_device(ahc, cmd->device->channel, cmd->device->id,
|
|
|
- cmd->device->lun, /*alloc*/TRUE);
|
|
|
+ cmd->device->lun);
|
|
|
BUG_ON(dev == NULL);
|
|
|
|
|
|
cmd->result = CAM_REQ_INPROG << 16;
|
|
@@ -652,11 +642,69 @@ static int
|
|
|
ahc_linux_slave_alloc(struct scsi_device *device)
|
|
|
{
|
|
|
struct ahc_softc *ahc;
|
|
|
+ struct ahc_linux_target *targ;
|
|
|
+ struct scsi_target *starget = device->sdev_target;
|
|
|
+ struct ahc_linux_device *dev;
|
|
|
+ u_int target_offset;
|
|
|
+
|
|
|
+ target_offset = starget->id;
|
|
|
+ if (starget->channel != 0)
|
|
|
+ target_offset += 8;
|
|
|
|
|
|
ahc = *((struct ahc_softc **)device->host->hostdata);
|
|
|
if (bootverbose)
|
|
|
printf("%s: Slave Alloc %d\n", ahc_name(ahc), device->id);
|
|
|
- return (0);
|
|
|
+ targ = ahc->platform_data->targets[target_offset];
|
|
|
+ if (targ == NULL) {
|
|
|
+ targ = ahc_linux_alloc_target(ahc, starget->channel, starget->id);
|
|
|
+ struct seeprom_config *sc = ahc->seep_config;
|
|
|
+ if (targ == NULL)
|
|
|
+ return -ENOMEM;
|
|
|
+ if (sc) {
|
|
|
+ unsigned short scsirate;
|
|
|
+ struct ahc_devinfo devinfo;
|
|
|
+ struct ahc_initiator_tinfo *tinfo;
|
|
|
+ struct ahc_tmode_tstate *tstate;
|
|
|
+ char channel = starget->channel + 'A';
|
|
|
+ unsigned int our_id = ahc->our_id;
|
|
|
+
|
|
|
+ if (starget->channel)
|
|
|
+ our_id = ahc->our_id_b;
|
|
|
+
|
|
|
+ if ((ahc->features & AHC_ULTRA2) != 0) {
|
|
|
+ scsirate = sc->device_flags[target_offset] & CFXFER;
|
|
|
+ } else {
|
|
|
+ scsirate = (sc->device_flags[target_offset] & CFXFER) << 4;
|
|
|
+ if (sc->device_flags[target_offset] & CFSYNCH)
|
|
|
+ scsirate |= SOFS;
|
|
|
+ }
|
|
|
+ if (sc->device_flags[target_offset] & CFWIDEB) {
|
|
|
+ scsirate |= WIDEXFER;
|
|
|
+ spi_max_width(starget) = 1;
|
|
|
+ } else
|
|
|
+ spi_max_width(starget) = 0;
|
|
|
+ spi_min_period(starget) =
|
|
|
+ ahc_find_period(ahc, scsirate, AHC_SYNCRATE_DT);
|
|
|
+ tinfo = ahc_fetch_transinfo(ahc, channel, ahc->our_id,
|
|
|
+ targ->target, &tstate);
|
|
|
+ ahc_compile_devinfo(&devinfo, our_id, targ->target,
|
|
|
+ CAM_LUN_WILDCARD, channel,
|
|
|
+ ROLE_INITIATOR);
|
|
|
+ ahc_set_syncrate(ahc, &devinfo, NULL, 0, 0, 0,
|
|
|
+ AHC_TRANS_GOAL, /*paused*/FALSE);
|
|
|
+ ahc_set_width(ahc, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
|
|
|
+ AHC_TRANS_GOAL, /*paused*/FALSE);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ dev = targ->devices[device->lun];
|
|
|
+ if (dev == NULL) {
|
|
|
+ dev = ahc_linux_alloc_device(ahc, targ, device->lun);
|
|
|
+ if (dev == NULL)
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
static int
|
|
@@ -666,27 +714,20 @@ ahc_linux_slave_configure(struct scsi_device *device)
|
|
|
struct ahc_linux_device *dev;
|
|
|
|
|
|
ahc = *((struct ahc_softc **)device->host->hostdata);
|
|
|
+
|
|
|
if (bootverbose)
|
|
|
printf("%s: Slave Configure %d\n", ahc_name(ahc), device->id);
|
|
|
- /*
|
|
|
- * Since Linux has attached to the device, configure
|
|
|
- * it so we don't free and allocate the device
|
|
|
- * structure on every command.
|
|
|
- */
|
|
|
- dev = ahc_linux_get_device(ahc, device->channel,
|
|
|
- device->id, device->lun,
|
|
|
- /*alloc*/TRUE);
|
|
|
- if (dev != NULL) {
|
|
|
- dev->flags &= ~AHC_DEV_UNCONFIGURED;
|
|
|
- dev->scsi_device = device;
|
|
|
- ahc_linux_device_queue_depth(ahc, dev);
|
|
|
- }
|
|
|
+
|
|
|
+ dev = ahc_linux_get_device(ahc, device->channel, device->id,
|
|
|
+ device->lun);
|
|
|
+ dev->scsi_device = device;
|
|
|
+ ahc_linux_device_queue_depth(ahc, dev);
|
|
|
|
|
|
/* Initial Domain Validation */
|
|
|
if (!spi_initial_dv(device->sdev_target))
|
|
|
spi_dv_device(device);
|
|
|
|
|
|
- return (0);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
static void
|
|
@@ -699,22 +740,11 @@ ahc_linux_slave_destroy(struct scsi_device *device)
|
|
|
if (bootverbose)
|
|
|
printf("%s: Slave Destroy %d\n", ahc_name(ahc), device->id);
|
|
|
dev = ahc_linux_get_device(ahc, device->channel,
|
|
|
- device->id, device->lun,
|
|
|
- /*alloc*/FALSE);
|
|
|
- /*
|
|
|
- * Filter out "silly" deletions of real devices by only
|
|
|
- * deleting devices that have had slave_configure()
|
|
|
- * called on them. All other devices that have not
|
|
|
- * been configured will automatically be deleted by
|
|
|
- * the refcounting process.
|
|
|
- */
|
|
|
- if (dev != NULL
|
|
|
- && (dev->flags & AHC_DEV_SLAVE_CONFIGURED) != 0) {
|
|
|
- dev->flags |= AHC_DEV_UNCONFIGURED;
|
|
|
- if (dev->active == 0
|
|
|
- && (dev->flags & AHC_DEV_TIMER_ACTIVE) == 0)
|
|
|
- ahc_linux_free_device(ahc, dev);
|
|
|
- }
|
|
|
+ device->id, device->lun);
|
|
|
+
|
|
|
+ BUG_ON(dev->active);
|
|
|
+
|
|
|
+ ahc_linux_free_device(ahc, dev);
|
|
|
}
|
|
|
|
|
|
#if defined(__i386__)
|
|
@@ -1361,7 +1391,7 @@ ahc_platform_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
|
|
|
|
|
|
dev = ahc_linux_get_device(ahc, devinfo->channel - 'A',
|
|
|
devinfo->target,
|
|
|
- devinfo->lun, /*alloc*/FALSE);
|
|
|
+ devinfo->lun);
|
|
|
if (dev == NULL)
|
|
|
return;
|
|
|
was_queuing = dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED);
|
|
@@ -1793,8 +1823,6 @@ ahc_linux_alloc_device(struct ahc_softc *ahc,
|
|
|
if (dev == NULL)
|
|
|
return (NULL);
|
|
|
memset(dev, 0, sizeof(*dev));
|
|
|
- init_timer(&dev->timer);
|
|
|
- dev->flags = AHC_DEV_UNCONFIGURED;
|
|
|
dev->lun = lun;
|
|
|
dev->target = targ;
|
|
|
|
|
@@ -1817,7 +1845,7 @@ ahc_linux_alloc_device(struct ahc_softc *ahc,
|
|
|
}
|
|
|
|
|
|
static void
|
|
|
-__ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev)
|
|
|
+ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev)
|
|
|
{
|
|
|
struct ahc_linux_target *targ;
|
|
|
|
|
@@ -1829,13 +1857,6 @@ __ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev)
|
|
|
ahc_linux_free_target(ahc, targ);
|
|
|
}
|
|
|
|
|
|
-static void
|
|
|
-ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev)
|
|
|
-{
|
|
|
- del_timer_sync(&dev->timer);
|
|
|
- __ahc_linux_free_device(ahc, dev);
|
|
|
-}
|
|
|
-
|
|
|
void
|
|
|
ahc_send_async(struct ahc_softc *ahc, char channel,
|
|
|
u_int target, u_int lun, ac_code code, void *arg)
|
|
@@ -2008,8 +2029,6 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb)
|
|
|
}
|
|
|
} else if (ahc_get_transaction_status(scb) == CAM_SCSI_STATUS_ERROR) {
|
|
|
ahc_linux_handle_scsi_status(ahc, dev, scb);
|
|
|
- } else if (ahc_get_transaction_status(scb) == CAM_SEL_TIMEOUT) {
|
|
|
- dev->flags |= AHC_DEV_UNCONFIGURED;
|
|
|
}
|
|
|
|
|
|
if (dev->openings == 1
|
|
@@ -2031,11 +2050,6 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb)
|
|
|
if (dev->active == 0)
|
|
|
dev->commands_since_idle_or_otag = 0;
|
|
|
|
|
|
- if ((dev->flags & AHC_DEV_UNCONFIGURED) != 0
|
|
|
- && dev->active == 0
|
|
|
- && (dev->flags & AHC_DEV_TIMER_ACTIVE) == 0)
|
|
|
- ahc_linux_free_device(ahc, dev);
|
|
|
-
|
|
|
if ((scb->flags & SCB_RECOVERY_SCB) != 0) {
|
|
|
printf("Recovery SCB completes\n");
|
|
|
if (ahc_get_transaction_status(scb) == CAM_BDR_SENT
|
|
@@ -2174,27 +2188,6 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc,
|
|
|
ahc_platform_set_tags(ahc, &devinfo,
|
|
|
(dev->flags & AHC_DEV_Q_BASIC)
|
|
|
? AHC_QUEUE_BASIC : AHC_QUEUE_TAGGED);
|
|
|
- /* FALLTHROUGH */
|
|
|
- }
|
|
|
- case SCSI_STATUS_BUSY:
|
|
|
- {
|
|
|
- /*
|
|
|
- * Set a short timer to defer sending commands for
|
|
|
- * a bit since Linux will not delay in this case.
|
|
|
- */
|
|
|
- if ((dev->flags & AHC_DEV_TIMER_ACTIVE) != 0) {
|
|
|
- printf("%s:%c:%d: Device Timer still active during "
|
|
|
- "busy processing\n", ahc_name(ahc),
|
|
|
- dev->target->channel, dev->target->target);
|
|
|
- break;
|
|
|
- }
|
|
|
- dev->flags |= AHC_DEV_TIMER_ACTIVE;
|
|
|
- dev->qfrozen++;
|
|
|
- init_timer(&dev->timer);
|
|
|
- dev->timer.data = (u_long)dev;
|
|
|
- dev->timer.expires = jiffies + (HZ/2);
|
|
|
- dev->timer.function = ahc_linux_dev_timed_unfreeze;
|
|
|
- add_timer(&dev->timer);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
@@ -2326,24 +2319,6 @@ ahc_linux_release_simq(u_long arg)
|
|
|
scsi_unblock_requests(ahc->platform_data->host);
|
|
|
}
|
|
|
|
|
|
-static void
|
|
|
-ahc_linux_dev_timed_unfreeze(u_long arg)
|
|
|
-{
|
|
|
- struct ahc_linux_device *dev;
|
|
|
- struct ahc_softc *ahc;
|
|
|
- u_long s;
|
|
|
-
|
|
|
- dev = (struct ahc_linux_device *)arg;
|
|
|
- ahc = dev->target->ahc;
|
|
|
- ahc_lock(ahc, &s);
|
|
|
- dev->flags &= ~AHC_DEV_TIMER_ACTIVE;
|
|
|
- if (dev->qfrozen > 0)
|
|
|
- dev->qfrozen--;
|
|
|
- if (dev->active == 0)
|
|
|
- __ahc_linux_free_device(ahc, dev);
|
|
|
- ahc_unlock(ahc, &s);
|
|
|
-}
|
|
|
-
|
|
|
static int
|
|
|
ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
|
|
|
{
|
|
@@ -2384,7 +2359,7 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
|
|
|
* command, return success.
|
|
|
*/
|
|
|
dev = ahc_linux_get_device(ahc, cmd->device->channel, cmd->device->id,
|
|
|
- cmd->device->lun, /*alloc*/FALSE);
|
|
|
+ cmd->device->lun);
|
|
|
|
|
|
if (dev == NULL) {
|
|
|
/*
|