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,
/********************************* 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,
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;
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
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;
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
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
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__)
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);
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;
}
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;
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)
}
} 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
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
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;
}
}
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)
{
* 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) {
/*