forked from Minki/linux
[SCSI] aic7xxx: remove separate target and device allocations
Since the aic driver is now taught to speak in terms of the generic linux devices, we can now also dispense with the transport class get routines (since we update the parameters when the driver sees they change) and also plumb it into the spi transport transfer agreement reporting infrastructure. Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
This commit is contained in:
parent
153b1e1fd9
commit
b1abb4d67f
@ -122,8 +122,6 @@
|
||||
#include "aic7xxx_osm.h"
|
||||
#include "aic7xxx_inline.h"
|
||||
#include <scsi/scsicam.h>
|
||||
#include <scsi/scsi_transport.h>
|
||||
#include <scsi/scsi_transport_spi.h>
|
||||
|
||||
static struct scsi_transport_template *ahc_linux_transport_template = NULL;
|
||||
|
||||
@ -423,7 +421,7 @@ MODULE_PARM_DESC(aic7xxx,
|
||||
);
|
||||
|
||||
static void ahc_linux_handle_scsi_status(struct ahc_softc *,
|
||||
struct ahc_linux_device *,
|
||||
struct scsi_device *,
|
||||
struct scb *);
|
||||
static void ahc_linux_queue_cmd_complete(struct ahc_softc *ahc,
|
||||
struct scsi_cmnd *cmd);
|
||||
@ -434,17 +432,7 @@ 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,
|
||||
struct ahc_devinfo *devinfo);
|
||||
static void ahc_linux_device_queue_depth(struct ahc_softc *ahc,
|
||||
struct ahc_linux_device *dev);
|
||||
static struct ahc_linux_target* ahc_linux_alloc_target(struct ahc_softc*,
|
||||
u_int, u_int);
|
||||
static void ahc_linux_free_target(struct ahc_softc*,
|
||||
struct ahc_linux_target*);
|
||||
static struct ahc_linux_device* ahc_linux_alloc_device(struct ahc_softc*,
|
||||
struct ahc_linux_target*,
|
||||
u_int);
|
||||
static void ahc_linux_free_device(struct ahc_softc*,
|
||||
struct ahc_linux_device*);
|
||||
static void ahc_linux_device_queue_depth(struct scsi_device *);
|
||||
static int ahc_linux_run_command(struct ahc_softc*,
|
||||
struct ahc_linux_device *,
|
||||
struct scsi_cmnd *);
|
||||
@ -454,32 +442,12 @@ static int aic7xxx_setup(char *s);
|
||||
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);
|
||||
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,
|
||||
struct ahc_dma_seg *sg,
|
||||
dma_addr_t addr, bus_size_t len);
|
||||
|
||||
static __inline struct ahc_linux_device*
|
||||
ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, u_int target,
|
||||
u_int lun)
|
||||
{
|
||||
struct ahc_linux_target *targ;
|
||||
struct ahc_linux_device *dev;
|
||||
u_int target_offset;
|
||||
|
||||
target_offset = target;
|
||||
if (channel != 0)
|
||||
target_offset += 8;
|
||||
targ = ahc->platform_data->targets[target_offset];
|
||||
BUG_ON(targ == NULL);
|
||||
dev = targ->devices[lun];
|
||||
return dev;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_linux_unmap_scb(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
@ -611,7 +579,7 @@ static int
|
||||
ahc_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *))
|
||||
{
|
||||
struct ahc_softc *ahc;
|
||||
struct ahc_linux_device *dev;
|
||||
struct ahc_linux_device *dev = scsi_transport_device_data(cmd->device);
|
||||
|
||||
ahc = *(struct ahc_softc **)cmd->device->host->hostdata;
|
||||
|
||||
@ -629,132 +597,162 @@ ahc_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *))
|
||||
if (ahc->platform_data->qfrozen != 0)
|
||||
return SCSI_MLQUEUE_HOST_BUSY;
|
||||
|
||||
dev = ahc_linux_get_device(ahc, cmd->device->channel, cmd->device->id,
|
||||
cmd->device->lun);
|
||||
BUG_ON(dev == NULL);
|
||||
|
||||
cmd->result = CAM_REQ_INPROG << 16;
|
||||
|
||||
return ahc_linux_run_command(ahc, dev, cmd);
|
||||
}
|
||||
|
||||
static int
|
||||
ahc_linux_slave_alloc(struct scsi_device *device)
|
||||
static inline struct scsi_target **
|
||||
ahc_linux_target_in_softc(struct scsi_target *starget)
|
||||
{
|
||||
struct ahc_softc *ahc;
|
||||
struct ahc_linux_target *targ;
|
||||
struct scsi_target *starget = device->sdev_target;
|
||||
struct ahc_linux_device *dev;
|
||||
struct ahc_softc *ahc =
|
||||
*((struct ahc_softc **)dev_to_shost(&starget->dev)->hostdata);
|
||||
unsigned int target_offset;
|
||||
unsigned long flags;
|
||||
int retval = -ENOMEM;
|
||||
|
||||
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);
|
||||
ahc_lock(ahc, &flags);
|
||||
targ = ahc->platform_data->targets[target_offset];
|
||||
if (targ == NULL) {
|
||||
struct seeprom_config *sc;
|
||||
|
||||
targ = ahc_linux_alloc_target(ahc, starget->channel,
|
||||
starget->id);
|
||||
sc = ahc->seep_config;
|
||||
if (targ == NULL)
|
||||
goto out;
|
||||
|
||||
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)
|
||||
goto out;
|
||||
}
|
||||
retval = 0;
|
||||
|
||||
out:
|
||||
ahc_unlock(ahc, &flags);
|
||||
return retval;
|
||||
return &ahc->platform_data->starget[target_offset];
|
||||
}
|
||||
|
||||
static int
|
||||
ahc_linux_slave_configure(struct scsi_device *device)
|
||||
ahc_linux_target_alloc(struct scsi_target *starget)
|
||||
{
|
||||
struct ahc_softc *ahc;
|
||||
struct ahc_linux_device *dev;
|
||||
struct ahc_softc *ahc =
|
||||
*((struct ahc_softc **)dev_to_shost(&starget->dev)->hostdata);
|
||||
struct seeprom_config *sc = ahc->seep_config;
|
||||
unsigned long flags;
|
||||
struct scsi_target **ahc_targp = ahc_linux_target_in_softc(starget);
|
||||
struct ahc_linux_target *targ = scsi_transport_target_data(starget);
|
||||
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;
|
||||
unsigned int target_offset;
|
||||
|
||||
ahc = *((struct ahc_softc **)device->host->hostdata);
|
||||
target_offset = starget->id;
|
||||
if (starget->channel != 0)
|
||||
target_offset += 8;
|
||||
|
||||
if (starget->channel)
|
||||
our_id = ahc->our_id_b;
|
||||
|
||||
if (bootverbose)
|
||||
printf("%s: Slave Configure %d\n", ahc_name(ahc), device->id);
|
||||
ahc_lock(ahc, &flags);
|
||||
|
||||
dev = ahc_linux_get_device(ahc, device->channel, device->id,
|
||||
device->lun);
|
||||
dev->scsi_device = device;
|
||||
ahc_linux_device_queue_depth(ahc, dev);
|
||||
BUG_ON(*ahc_targp != NULL);
|
||||
|
||||
/* Initial Domain Validation */
|
||||
if (!spi_initial_dv(device->sdev_target))
|
||||
spi_dv_device(device);
|
||||
*ahc_targp = starget;
|
||||
memset(targ, 0, sizeof(*targ));
|
||||
|
||||
if (sc) {
|
||||
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,
|
||||
starget->id, &tstate);
|
||||
}
|
||||
ahc_compile_devinfo(&devinfo, our_id, starget->id,
|
||||
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);
|
||||
ahc_unlock(ahc, &flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ahc_linux_slave_destroy(struct scsi_device *device)
|
||||
ahc_linux_target_destroy(struct scsi_target *starget)
|
||||
{
|
||||
struct scsi_target **ahc_targp = ahc_linux_target_in_softc(starget);
|
||||
|
||||
*ahc_targp = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
ahc_linux_slave_alloc(struct scsi_device *sdev)
|
||||
{
|
||||
struct ahc_softc *ahc =
|
||||
*((struct ahc_softc **)sdev->host->hostdata);
|
||||
struct scsi_target *starget = sdev->sdev_target;
|
||||
struct ahc_linux_target *targ = scsi_transport_target_data(starget);
|
||||
struct ahc_linux_device *dev;
|
||||
|
||||
if (bootverbose)
|
||||
printf("%s: Slave Alloc %d\n", ahc_name(ahc), sdev->id);
|
||||
|
||||
BUG_ON(targ->sdev[sdev->lun] != NULL);
|
||||
|
||||
dev = scsi_transport_device_data(sdev);
|
||||
memset(dev, 0, sizeof(*dev));
|
||||
|
||||
/*
|
||||
* We start out life using untagged
|
||||
* transactions of which we allow one.
|
||||
*/
|
||||
dev->openings = 1;
|
||||
|
||||
/*
|
||||
* Set maxtags to 0. This will be changed if we
|
||||
* later determine that we are dealing with
|
||||
* a tagged queuing capable device.
|
||||
*/
|
||||
dev->maxtags = 0;
|
||||
|
||||
targ->sdev[sdev->lun] = sdev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ahc_linux_slave_configure(struct scsi_device *sdev)
|
||||
{
|
||||
struct ahc_softc *ahc;
|
||||
struct ahc_linux_device *dev;
|
||||
|
||||
ahc = *((struct ahc_softc **)device->host->hostdata);
|
||||
ahc = *((struct ahc_softc **)sdev->host->hostdata);
|
||||
|
||||
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);
|
||||
printf("%s: Slave Configure %d\n", ahc_name(ahc), sdev->id);
|
||||
|
||||
ahc_linux_device_queue_depth(sdev);
|
||||
|
||||
/* Initial Domain Validation */
|
||||
if (!spi_initial_dv(sdev->sdev_target))
|
||||
spi_dv_device(sdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ahc_linux_slave_destroy(struct scsi_device *sdev)
|
||||
{
|
||||
struct ahc_softc *ahc;
|
||||
struct ahc_linux_device *dev = scsi_transport_device_data(sdev);
|
||||
struct ahc_linux_target *targ = scsi_transport_target_data(sdev->sdev_target);
|
||||
|
||||
ahc = *((struct ahc_softc **)sdev->host->hostdata);
|
||||
if (bootverbose)
|
||||
printf("%s: Slave Destroy %d\n", ahc_name(ahc), sdev->id);
|
||||
|
||||
BUG_ON(dev->active);
|
||||
|
||||
ahc_linux_free_device(ahc, dev);
|
||||
targ->sdev[sdev->lun] = NULL;
|
||||
}
|
||||
|
||||
#if defined(__i386__)
|
||||
@ -874,6 +872,8 @@ struct scsi_host_template aic7xxx_driver_template = {
|
||||
.slave_alloc = ahc_linux_slave_alloc,
|
||||
.slave_configure = ahc_linux_slave_configure,
|
||||
.slave_destroy = ahc_linux_slave_destroy,
|
||||
.target_alloc = ahc_linux_target_alloc,
|
||||
.target_destroy = ahc_linux_target_destroy,
|
||||
};
|
||||
|
||||
/**************************** Tasklet Handler *********************************/
|
||||
@ -1335,8 +1335,7 @@ ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg)
|
||||
void
|
||||
ahc_platform_free(struct ahc_softc *ahc)
|
||||
{
|
||||
struct ahc_linux_target *targ;
|
||||
struct ahc_linux_device *dev;
|
||||
struct scsi_target *starget;
|
||||
int i, j;
|
||||
|
||||
if (ahc->platform_data != NULL) {
|
||||
@ -1347,22 +1346,17 @@ ahc_platform_free(struct ahc_softc *ahc)
|
||||
|
||||
/* destroy all of the device and target objects */
|
||||
for (i = 0; i < AHC_NUM_TARGETS; i++) {
|
||||
targ = ahc->platform_data->targets[i];
|
||||
if (targ != NULL) {
|
||||
/* Keep target around through the loop. */
|
||||
targ->refcount++;
|
||||
starget = ahc->platform_data->starget[i];
|
||||
if (starget != NULL) {
|
||||
for (j = 0; j < AHC_NUM_LUNS; j++) {
|
||||
struct ahc_linux_target *targ =
|
||||
scsi_transport_target_data(starget);
|
||||
|
||||
if (targ->devices[j] == NULL)
|
||||
if (targ->sdev[j] == NULL)
|
||||
continue;
|
||||
dev = targ->devices[j];
|
||||
ahc_linux_free_device(ahc, dev);
|
||||
targ->sdev[j] = NULL;
|
||||
}
|
||||
/*
|
||||
* Forcibly free the target now that
|
||||
* all devices are gone.
|
||||
*/
|
||||
ahc_linux_free_target(ahc, targ);
|
||||
ahc->platform_data->starget[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1395,15 +1389,25 @@ void
|
||||
ahc_platform_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
|
||||
ahc_queue_alg alg)
|
||||
{
|
||||
struct scsi_target *starget;
|
||||
struct ahc_linux_target *targ;
|
||||
struct ahc_linux_device *dev;
|
||||
struct scsi_device *sdev;
|
||||
u_int target_offset;
|
||||
int was_queuing;
|
||||
int now_queuing;
|
||||
|
||||
dev = ahc_linux_get_device(ahc, devinfo->channel - 'A',
|
||||
devinfo->target,
|
||||
devinfo->lun);
|
||||
if (dev == NULL)
|
||||
target_offset = devinfo->target;
|
||||
if (devinfo->channel != 'A')
|
||||
target_offset += 8;
|
||||
starget = ahc->platform_data->starget[target_offset];
|
||||
targ = scsi_transport_target_data(starget);
|
||||
BUG_ON(targ == NULL);
|
||||
sdev = targ->sdev[devinfo->lun];
|
||||
if (sdev == NULL)
|
||||
return;
|
||||
dev = scsi_transport_device_data(sdev);
|
||||
|
||||
was_queuing = dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED);
|
||||
switch (alg) {
|
||||
default:
|
||||
@ -1454,30 +1458,28 @@ ahc_platform_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
|
||||
dev->maxtags = 0;
|
||||
dev->openings = 1 - dev->active;
|
||||
}
|
||||
if (dev->scsi_device != NULL) {
|
||||
switch ((dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED))) {
|
||||
case AHC_DEV_Q_BASIC:
|
||||
scsi_adjust_queue_depth(dev->scsi_device,
|
||||
MSG_SIMPLE_TASK,
|
||||
dev->openings + dev->active);
|
||||
break;
|
||||
case AHC_DEV_Q_TAGGED:
|
||||
scsi_adjust_queue_depth(dev->scsi_device,
|
||||
MSG_ORDERED_TASK,
|
||||
dev->openings + dev->active);
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* We allow the OS to queue 2 untagged transactions to
|
||||
* us at any time even though we can only execute them
|
||||
* serially on the controller/device. This should
|
||||
* remove some latency.
|
||||
*/
|
||||
scsi_adjust_queue_depth(dev->scsi_device,
|
||||
/*NON-TAGGED*/0,
|
||||
/*queue depth*/2);
|
||||
break;
|
||||
}
|
||||
switch ((dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED))) {
|
||||
case AHC_DEV_Q_BASIC:
|
||||
scsi_adjust_queue_depth(sdev,
|
||||
MSG_SIMPLE_TASK,
|
||||
dev->openings + dev->active);
|
||||
break;
|
||||
case AHC_DEV_Q_TAGGED:
|
||||
scsi_adjust_queue_depth(sdev,
|
||||
MSG_ORDERED_TASK,
|
||||
dev->openings + dev->active);
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* We allow the OS to queue 2 untagged transactions to
|
||||
* us at any time even though we can only execute them
|
||||
* serially on the controller/device. This should
|
||||
* remove some latency.
|
||||
*/
|
||||
scsi_adjust_queue_depth(sdev,
|
||||
/*NON-TAGGED*/0,
|
||||
/*queue depth*/2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1523,22 +1525,20 @@ ahc_linux_user_tagdepth(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
|
||||
* Determines the queue depth for a given device.
|
||||
*/
|
||||
static void
|
||||
ahc_linux_device_queue_depth(struct ahc_softc *ahc,
|
||||
struct ahc_linux_device *dev)
|
||||
ahc_linux_device_queue_depth(struct scsi_device *sdev)
|
||||
{
|
||||
struct ahc_devinfo devinfo;
|
||||
u_int tags;
|
||||
struct ahc_softc *ahc = *((struct ahc_softc **)sdev->host->hostdata);
|
||||
|
||||
ahc_compile_devinfo(&devinfo,
|
||||
dev->target->channel == 0
|
||||
sdev->sdev_target->channel == 0
|
||||
? ahc->our_id : ahc->our_id_b,
|
||||
dev->target->target, dev->lun,
|
||||
dev->target->channel == 0 ? 'A' : 'B',
|
||||
sdev->sdev_target->id, sdev->lun,
|
||||
sdev->sdev_target->channel == 0 ? 'A' : 'B',
|
||||
ROLE_INITIATOR);
|
||||
tags = ahc_linux_user_tagdepth(ahc, &devinfo);
|
||||
if (tags != 0
|
||||
&& dev->scsi_device != NULL
|
||||
&& dev->scsi_device->tagged_supported != 0) {
|
||||
if (tags != 0 && sdev->tagged_supported != 0) {
|
||||
|
||||
ahc_set_tags(ahc, &devinfo, AHC_QUEUE_TAGGED);
|
||||
ahc_print_devinfo(ahc, &devinfo);
|
||||
@ -1767,106 +1767,6 @@ ahc_platform_flushwork(struct ahc_softc *ahc)
|
||||
|
||||
}
|
||||
|
||||
static struct ahc_linux_target*
|
||||
ahc_linux_alloc_target(struct ahc_softc *ahc, u_int channel, u_int target)
|
||||
{
|
||||
struct ahc_linux_target *targ;
|
||||
u_int target_offset;
|
||||
|
||||
target_offset = target;
|
||||
if (channel != 0)
|
||||
target_offset += 8;
|
||||
|
||||
targ = malloc(sizeof(*targ), M_DEVBUG, M_NOWAIT);
|
||||
if (targ == NULL)
|
||||
return (NULL);
|
||||
memset(targ, 0, sizeof(*targ));
|
||||
targ->channel = channel;
|
||||
targ->target = target;
|
||||
targ->ahc = ahc;
|
||||
ahc->platform_data->targets[target_offset] = targ;
|
||||
return (targ);
|
||||
}
|
||||
|
||||
static void
|
||||
ahc_linux_free_target(struct ahc_softc *ahc, struct ahc_linux_target *targ)
|
||||
{
|
||||
struct ahc_devinfo devinfo;
|
||||
struct ahc_initiator_tinfo *tinfo;
|
||||
struct ahc_tmode_tstate *tstate;
|
||||
u_int our_id;
|
||||
u_int target_offset;
|
||||
char channel;
|
||||
|
||||
/*
|
||||
* Force a negotiation to async/narrow on any
|
||||
* future command to this device unless a bus
|
||||
* reset occurs between now and that command.
|
||||
*/
|
||||
channel = 'A' + targ->channel;
|
||||
our_id = ahc->our_id;
|
||||
target_offset = targ->target;
|
||||
if (targ->channel != 0) {
|
||||
target_offset += 8;
|
||||
our_id = ahc->our_id_b;
|
||||
}
|
||||
tinfo = ahc_fetch_transinfo(ahc, channel, 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);
|
||||
ahc_update_neg_request(ahc, &devinfo, tstate, tinfo, AHC_NEG_ALWAYS);
|
||||
ahc->platform_data->targets[target_offset] = NULL;
|
||||
free(targ, M_DEVBUF);
|
||||
}
|
||||
|
||||
static struct ahc_linux_device*
|
||||
ahc_linux_alloc_device(struct ahc_softc *ahc,
|
||||
struct ahc_linux_target *targ, u_int lun)
|
||||
{
|
||||
struct ahc_linux_device *dev;
|
||||
|
||||
dev = malloc(sizeof(*dev), M_DEVBUG, M_NOWAIT);
|
||||
if (dev == NULL)
|
||||
return (NULL);
|
||||
memset(dev, 0, sizeof(*dev));
|
||||
dev->lun = lun;
|
||||
dev->target = targ;
|
||||
|
||||
/*
|
||||
* We start out life using untagged
|
||||
* transactions of which we allow one.
|
||||
*/
|
||||
dev->openings = 1;
|
||||
|
||||
/*
|
||||
* Set maxtags to 0. This will be changed if we
|
||||
* later determine that we are dealing with
|
||||
* a tagged queuing capable device.
|
||||
*/
|
||||
dev->maxtags = 0;
|
||||
|
||||
targ->refcount++;
|
||||
targ->devices[lun] = dev;
|
||||
return (dev);
|
||||
}
|
||||
|
||||
static void
|
||||
ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev)
|
||||
{
|
||||
struct ahc_linux_target *targ;
|
||||
|
||||
targ = dev->target;
|
||||
targ->devices[dev->lun] = NULL;
|
||||
free(dev, M_DEVBUF);
|
||||
targ->refcount--;
|
||||
if (targ->refcount == 0)
|
||||
ahc_linux_free_target(ahc, targ);
|
||||
}
|
||||
|
||||
void
|
||||
ahc_send_async(struct ahc_softc *ahc, char channel,
|
||||
u_int target, u_int lun, ac_code code, void *arg)
|
||||
@ -1875,11 +1775,15 @@ ahc_send_async(struct ahc_softc *ahc, char channel,
|
||||
case AC_TRANSFER_NEG:
|
||||
{
|
||||
char buf[80];
|
||||
struct scsi_target *starget;
|
||||
struct ahc_linux_target *targ;
|
||||
struct info_str info;
|
||||
struct ahc_initiator_tinfo *tinfo;
|
||||
struct ahc_tmode_tstate *tstate;
|
||||
int target_offset;
|
||||
unsigned int target_ppr_options;
|
||||
|
||||
BUG_ON(target == CAM_TARGET_WILDCARD);
|
||||
|
||||
info.buffer = buf;
|
||||
info.length = sizeof(buf);
|
||||
@ -1908,32 +1812,30 @@ ahc_send_async(struct ahc_softc *ahc, char channel,
|
||||
target_offset = target;
|
||||
if (channel == 'B')
|
||||
target_offset += 8;
|
||||
targ = ahc->platform_data->targets[target_offset];
|
||||
starget = ahc->platform_data->starget[target_offset];
|
||||
targ = scsi_transport_target_data(starget);
|
||||
if (targ == NULL)
|
||||
break;
|
||||
if (tinfo->curr.period == targ->last_tinfo.period
|
||||
&& tinfo->curr.width == targ->last_tinfo.width
|
||||
&& tinfo->curr.offset == targ->last_tinfo.offset
|
||||
&& tinfo->curr.ppr_options == targ->last_tinfo.ppr_options)
|
||||
|
||||
target_ppr_options =
|
||||
(spi_dt(starget) ? MSG_EXT_PPR_DT_REQ : 0)
|
||||
+ (spi_qas(starget) ? MSG_EXT_PPR_QAS_REQ : 0)
|
||||
+ (spi_iu(starget) ? MSG_EXT_PPR_IU_REQ : 0);
|
||||
|
||||
if (tinfo->curr.period == spi_period(starget)
|
||||
&& tinfo->curr.width == spi_width(starget)
|
||||
&& tinfo->curr.offset == spi_offset(starget)
|
||||
&& tinfo->curr.ppr_options == target_ppr_options)
|
||||
if (bootverbose == 0)
|
||||
break;
|
||||
|
||||
targ->last_tinfo.period = tinfo->curr.period;
|
||||
targ->last_tinfo.width = tinfo->curr.width;
|
||||
targ->last_tinfo.offset = tinfo->curr.offset;
|
||||
targ->last_tinfo.ppr_options = tinfo->curr.ppr_options;
|
||||
|
||||
printf("(%s:%c:", ahc_name(ahc), channel);
|
||||
if (target == CAM_TARGET_WILDCARD)
|
||||
printf("*): ");
|
||||
else
|
||||
printf("%d): ", target);
|
||||
ahc_format_transinfo(&info, &tinfo->curr);
|
||||
if (info.pos < info.length)
|
||||
*info.buffer = '\0';
|
||||
else
|
||||
buf[info.length - 1] = '\0';
|
||||
printf("%s", buf);
|
||||
spi_period(starget) = tinfo->curr.period;
|
||||
spi_width(starget) = tinfo->curr.width;
|
||||
spi_offset(starget) = tinfo->curr.offset;
|
||||
spi_dt(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_DT_REQ;
|
||||
spi_qas(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_QAS_REQ;
|
||||
spi_iu(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ;
|
||||
spi_display_xfer_agreement(starget);
|
||||
break;
|
||||
}
|
||||
case AC_SENT_BDR:
|
||||
@ -2038,7 +1940,7 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb)
|
||||
ahc_set_transaction_status(scb, CAM_REQ_CMP);
|
||||
}
|
||||
} else if (ahc_get_transaction_status(scb) == CAM_SCSI_STATUS_ERROR) {
|
||||
ahc_linux_handle_scsi_status(ahc, dev, scb);
|
||||
ahc_linux_handle_scsi_status(ahc, cmd->device, scb);
|
||||
}
|
||||
|
||||
if (dev->openings == 1
|
||||
@ -2077,14 +1979,15 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb)
|
||||
|
||||
static void
|
||||
ahc_linux_handle_scsi_status(struct ahc_softc *ahc,
|
||||
struct ahc_linux_device *dev, struct scb *scb)
|
||||
struct scsi_device *sdev, struct scb *scb)
|
||||
{
|
||||
struct ahc_devinfo devinfo;
|
||||
struct ahc_linux_device *dev = scsi_transport_device_data(sdev);
|
||||
|
||||
ahc_compile_devinfo(&devinfo,
|
||||
ahc->our_id,
|
||||
dev->target->target, dev->lun,
|
||||
dev->target->channel == 0 ? 'A' : 'B',
|
||||
sdev->sdev_target->id, sdev->lun,
|
||||
sdev->sdev_target->channel == 0 ? 'A' : 'B',
|
||||
ROLE_INITIATOR);
|
||||
|
||||
/*
|
||||
@ -2368,8 +2271,7 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
|
||||
* at all, and the system wanted us to just abort the
|
||||
* command, return success.
|
||||
*/
|
||||
dev = ahc_linux_get_device(ahc, cmd->device->channel, cmd->device->id,
|
||||
cmd->device->lun);
|
||||
dev = scsi_transport_device_data(cmd->device);
|
||||
|
||||
if (dev == NULL) {
|
||||
/*
|
||||
@ -2626,18 +2528,6 @@ ahc_platform_dump_card_state(struct ahc_softc *ahc)
|
||||
|
||||
static void ahc_linux_exit(void);
|
||||
|
||||
static void ahc_linux_get_width(struct scsi_target *starget)
|
||||
{
|
||||
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
|
||||
struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
|
||||
struct ahc_tmode_tstate *tstate;
|
||||
struct ahc_initiator_tinfo *tinfo
|
||||
= ahc_fetch_transinfo(ahc,
|
||||
starget->channel + 'A',
|
||||
shost->this_id, starget->id, &tstate);
|
||||
spi_width(starget) = tinfo->curr.width;
|
||||
}
|
||||
|
||||
static void ahc_linux_set_width(struct scsi_target *starget, int width)
|
||||
{
|
||||
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
|
||||
@ -2652,18 +2542,6 @@ static void ahc_linux_set_width(struct scsi_target *starget, int width)
|
||||
ahc_unlock(ahc, &flags);
|
||||
}
|
||||
|
||||
static void ahc_linux_get_period(struct scsi_target *starget)
|
||||
{
|
||||
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
|
||||
struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
|
||||
struct ahc_tmode_tstate *tstate;
|
||||
struct ahc_initiator_tinfo *tinfo
|
||||
= ahc_fetch_transinfo(ahc,
|
||||
starget->channel + 'A',
|
||||
shost->this_id, starget->id, &tstate);
|
||||
spi_period(starget) = tinfo->curr.period;
|
||||
}
|
||||
|
||||
static void ahc_linux_set_period(struct scsi_target *starget, int period)
|
||||
{
|
||||
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
|
||||
@ -2692,7 +2570,6 @@ static void ahc_linux_set_period(struct scsi_target *starget, int period)
|
||||
|
||||
/* all PPR requests apart from QAS require wide transfers */
|
||||
if (ppr_options & ~MSG_EXT_PPR_QAS_REQ) {
|
||||
ahc_linux_get_width(starget);
|
||||
if (spi_width(starget) == 0)
|
||||
ppr_options &= MSG_EXT_PPR_QAS_REQ;
|
||||
}
|
||||
@ -2704,18 +2581,6 @@ static void ahc_linux_set_period(struct scsi_target *starget, int period)
|
||||
ahc_unlock(ahc, &flags);
|
||||
}
|
||||
|
||||
static void ahc_linux_get_offset(struct scsi_target *starget)
|
||||
{
|
||||
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
|
||||
struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
|
||||
struct ahc_tmode_tstate *tstate;
|
||||
struct ahc_initiator_tinfo *tinfo
|
||||
= ahc_fetch_transinfo(ahc,
|
||||
starget->channel + 'A',
|
||||
shost->this_id, starget->id, &tstate);
|
||||
spi_offset(starget) = tinfo->curr.offset;
|
||||
}
|
||||
|
||||
static void ahc_linux_set_offset(struct scsi_target *starget, int offset)
|
||||
{
|
||||
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
|
||||
@ -2744,18 +2609,6 @@ static void ahc_linux_set_offset(struct scsi_target *starget, int offset)
|
||||
ahc_unlock(ahc, &flags);
|
||||
}
|
||||
|
||||
static void ahc_linux_get_dt(struct scsi_target *starget)
|
||||
{
|
||||
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
|
||||
struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
|
||||
struct ahc_tmode_tstate *tstate;
|
||||
struct ahc_initiator_tinfo *tinfo
|
||||
= ahc_fetch_transinfo(ahc,
|
||||
starget->channel + 'A',
|
||||
shost->this_id, starget->id, &tstate);
|
||||
spi_dt(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_DT_REQ;
|
||||
}
|
||||
|
||||
static void ahc_linux_set_dt(struct scsi_target *starget, int dt)
|
||||
{
|
||||
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
|
||||
@ -2787,18 +2640,6 @@ static void ahc_linux_set_dt(struct scsi_target *starget, int dt)
|
||||
ahc_unlock(ahc, &flags);
|
||||
}
|
||||
|
||||
static void ahc_linux_get_qas(struct scsi_target *starget)
|
||||
{
|
||||
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
|
||||
struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
|
||||
struct ahc_tmode_tstate *tstate;
|
||||
struct ahc_initiator_tinfo *tinfo
|
||||
= ahc_fetch_transinfo(ahc,
|
||||
starget->channel + 'A',
|
||||
shost->this_id, starget->id, &tstate);
|
||||
spi_dt(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_QAS_REQ;
|
||||
}
|
||||
|
||||
static void ahc_linux_set_qas(struct scsi_target *starget, int qas)
|
||||
{
|
||||
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
|
||||
@ -2827,18 +2668,6 @@ static void ahc_linux_set_qas(struct scsi_target *starget, int qas)
|
||||
ahc_unlock(ahc, &flags);
|
||||
}
|
||||
|
||||
static void ahc_linux_get_iu(struct scsi_target *starget)
|
||||
{
|
||||
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
|
||||
struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata);
|
||||
struct ahc_tmode_tstate *tstate;
|
||||
struct ahc_initiator_tinfo *tinfo
|
||||
= ahc_fetch_transinfo(ahc,
|
||||
starget->channel + 'A',
|
||||
shost->this_id, starget->id, &tstate);
|
||||
spi_dt(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ;
|
||||
}
|
||||
|
||||
static void ahc_linux_set_iu(struct scsi_target *starget, int iu)
|
||||
{
|
||||
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
|
||||
@ -2868,22 +2697,16 @@ static void ahc_linux_set_iu(struct scsi_target *starget, int iu)
|
||||
}
|
||||
|
||||
static struct spi_function_template ahc_linux_transport_functions = {
|
||||
.get_offset = ahc_linux_get_offset,
|
||||
.set_offset = ahc_linux_set_offset,
|
||||
.show_offset = 1,
|
||||
.get_period = ahc_linux_get_period,
|
||||
.set_period = ahc_linux_set_period,
|
||||
.show_period = 1,
|
||||
.get_width = ahc_linux_get_width,
|
||||
.set_width = ahc_linux_set_width,
|
||||
.show_width = 1,
|
||||
.get_dt = ahc_linux_get_dt,
|
||||
.set_dt = ahc_linux_set_dt,
|
||||
.show_dt = 1,
|
||||
.get_iu = ahc_linux_get_iu,
|
||||
.set_iu = ahc_linux_set_iu,
|
||||
.show_iu = 1,
|
||||
.get_qas = ahc_linux_get_qas,
|
||||
.set_qas = ahc_linux_set_qas,
|
||||
.show_qas = 1,
|
||||
};
|
||||
@ -2896,6 +2719,10 @@ ahc_linux_init(void)
|
||||
ahc_linux_transport_template = spi_attach_transport(&ahc_linux_transport_functions);
|
||||
if (!ahc_linux_transport_template)
|
||||
return -ENODEV;
|
||||
scsi_transport_reserve_target(ahc_linux_transport_template,
|
||||
sizeof(struct ahc_linux_target));
|
||||
scsi_transport_reserve_device(ahc_linux_transport_template,
|
||||
sizeof(struct ahc_linux_device));
|
||||
if (ahc_linux_detect(&aic7xxx_driver_template))
|
||||
return 0;
|
||||
spi_release_transport(ahc_linux_transport_template);
|
||||
|
@ -79,6 +79,8 @@
|
||||
#include <scsi/scsi_device.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
#include <scsi/scsi_tcq.h>
|
||||
#include <scsi/scsi_transport.h>
|
||||
#include <scsi/scsi_transport_spi.h>
|
||||
|
||||
/* Core SCSI definitions */
|
||||
#define AIC_LIB_PREFIX ahc
|
||||
@ -330,8 +332,6 @@ typedef enum {
|
||||
|
||||
struct ahc_linux_target;
|
||||
struct ahc_linux_device {
|
||||
TAILQ_ENTRY(ahc_linux_device) links;
|
||||
|
||||
/*
|
||||
* The number of transactions currently
|
||||
* queued to the device.
|
||||
@ -401,17 +401,10 @@ struct ahc_linux_device {
|
||||
*/
|
||||
u_int commands_since_idle_or_otag;
|
||||
#define AHC_OTAG_THRESH 500
|
||||
|
||||
int lun;
|
||||
struct scsi_device *scsi_device;
|
||||
struct ahc_linux_target *target;
|
||||
};
|
||||
|
||||
struct ahc_linux_target {
|
||||
struct ahc_linux_device *devices[AHC_NUM_LUNS];
|
||||
int channel;
|
||||
int target;
|
||||
int refcount;
|
||||
struct scsi_device *sdev[AHC_NUM_LUNS];
|
||||
struct ahc_transinfo last_tinfo;
|
||||
struct ahc_softc *ahc;
|
||||
};
|
||||
@ -445,7 +438,7 @@ struct ahc_platform_data {
|
||||
/*
|
||||
* Fields accessed from interrupt context.
|
||||
*/
|
||||
struct ahc_linux_target *targets[AHC_NUM_TARGETS];
|
||||
struct scsi_target *starget[AHC_NUM_TARGETS];
|
||||
|
||||
spinlock_t spin_lock;
|
||||
u_int qfrozen;
|
||||
|
@ -50,7 +50,7 @@ static void ahc_dump_target_state(struct ahc_softc *ahc,
|
||||
u_int our_id, char channel,
|
||||
u_int target_id, u_int target_offset);
|
||||
static void ahc_dump_device_state(struct info_str *info,
|
||||
struct ahc_linux_device *dev);
|
||||
struct scsi_device *dev);
|
||||
static int ahc_proc_write_seeprom(struct ahc_softc *ahc,
|
||||
char *buffer, int length);
|
||||
|
||||
@ -142,6 +142,7 @@ ahc_dump_target_state(struct ahc_softc *ahc, struct info_str *info,
|
||||
u_int target_offset)
|
||||
{
|
||||
struct ahc_linux_target *targ;
|
||||
struct scsi_target *starget;
|
||||
struct ahc_initiator_tinfo *tinfo;
|
||||
struct ahc_tmode_tstate *tstate;
|
||||
int lun;
|
||||
@ -153,7 +154,8 @@ ahc_dump_target_state(struct ahc_softc *ahc, struct info_str *info,
|
||||
copy_info(info, "Target %d Negotiation Settings\n", target_id);
|
||||
copy_info(info, "\tUser: ");
|
||||
ahc_format_transinfo(info, &tinfo->user);
|
||||
targ = ahc->platform_data->targets[target_offset];
|
||||
starget = ahc->platform_data->starget[target_offset];
|
||||
targ = scsi_transport_target_data(starget);
|
||||
if (targ == NULL)
|
||||
return;
|
||||
|
||||
@ -163,22 +165,25 @@ ahc_dump_target_state(struct ahc_softc *ahc, struct info_str *info,
|
||||
ahc_format_transinfo(info, &tinfo->curr);
|
||||
|
||||
for (lun = 0; lun < AHC_NUM_LUNS; lun++) {
|
||||
struct ahc_linux_device *dev;
|
||||
struct scsi_device *sdev;
|
||||
|
||||
dev = targ->devices[lun];
|
||||
sdev = targ->sdev[lun];
|
||||
|
||||
if (dev == NULL)
|
||||
if (sdev == NULL)
|
||||
continue;
|
||||
|
||||
ahc_dump_device_state(info, dev);
|
||||
ahc_dump_device_state(info, sdev);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ahc_dump_device_state(struct info_str *info, struct ahc_linux_device *dev)
|
||||
ahc_dump_device_state(struct info_str *info, struct scsi_device *sdev)
|
||||
{
|
||||
struct ahc_linux_device *dev = scsi_transport_device_data(sdev);
|
||||
|
||||
copy_info(info, "\tChannel %c Target %d Lun %d Settings\n",
|
||||
dev->target->channel + 'A', dev->target->target, dev->lun);
|
||||
sdev->sdev_target->channel + 'A',
|
||||
sdev->sdev_target->id, sdev->lun);
|
||||
|
||||
copy_info(info, "\t\tCommands Queued %ld\n", dev->commands_issued);
|
||||
copy_info(info, "\t\tCommands Active %d\n", dev->active);
|
||||
|
Loading…
Reference in New Issue
Block a user