mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-08 15:04:45 +00:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (40 commits) [SCSI] jazz_esp, sgiwd93, sni_53c710, sun3x_esp: fix platform driver hotplug/coldplug [SCSI] aic7xxx: add const [SCSI] aic7xxx: add static [SCSI] aic7xxx: Update _shipped files [SCSI] aic7xxx: teach aicasm to not emit unused debug code/data [SCSI] qla2xxx: Update version number to 8.02.01-k2. [SCSI] qla2xxx: Correct regression in relogin code. [SCSI] qla2xxx: Correct misc. endian and byte-ordering issues. [SCSI] qla2xxx: make qla2x00_issue_iocb_timeout() static [SCSI] qla2xxx: qla_os.c, make 2 functions static [SCSI] qla2xxx: Re-register FDMI information after a LIP. [SCSI] qla2xxx: Correct SRB usage-after-completion/free issues. [SCSI] qla2xxx: Correct ISP84XX verify-chip response handling. [SCSI] qla2xxx: Wakeup DPC thread to process any deferred-work requests. [SCSI] qla2xxx: Collapse RISC-RAM retrieval code during a firmware-dump. [SCSI] m68k: new mac_esp scsi driver [SCSI] zfcp: Add some statistics provided by the FCP adapter to the sysfs [SCSI] zfcp: Print some messages only during ERP [SCSI] zfcp: Wait for free SBAL during exchange config [SCSI] scsi_transport_fc: fc_user_scan correction ...
This commit is contained in:
commit
064922a805
43
block/bsg.c
43
block/bsg.c
@ -699,14 +699,26 @@ static struct bsg_device *bsg_alloc_device(void)
|
||||
return bd;
|
||||
}
|
||||
|
||||
static void bsg_kref_release_function(struct kref *kref)
|
||||
{
|
||||
struct bsg_class_device *bcd =
|
||||
container_of(kref, struct bsg_class_device, ref);
|
||||
|
||||
if (bcd->release)
|
||||
bcd->release(bcd->parent);
|
||||
|
||||
put_device(bcd->parent);
|
||||
}
|
||||
|
||||
static int bsg_put_device(struct bsg_device *bd)
|
||||
{
|
||||
int ret = 0;
|
||||
struct device *dev = bd->queue->bsg_dev.dev;
|
||||
int ret = 0, do_free;
|
||||
struct request_queue *q = bd->queue;
|
||||
|
||||
mutex_lock(&bsg_mutex);
|
||||
|
||||
if (!atomic_dec_and_test(&bd->ref_count))
|
||||
do_free = atomic_dec_and_test(&bd->ref_count);
|
||||
if (!do_free)
|
||||
goto out;
|
||||
|
||||
dprintk("%s: tearing down\n", bd->name);
|
||||
@ -723,12 +735,13 @@ static int bsg_put_device(struct bsg_device *bd)
|
||||
*/
|
||||
ret = bsg_complete_all_commands(bd);
|
||||
|
||||
blk_put_queue(bd->queue);
|
||||
hlist_del(&bd->dev_list);
|
||||
kfree(bd);
|
||||
out:
|
||||
mutex_unlock(&bsg_mutex);
|
||||
put_device(dev);
|
||||
kref_put(&q->bsg_dev.ref, bsg_kref_release_function);
|
||||
if (do_free)
|
||||
blk_put_queue(q);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -796,7 +809,7 @@ static struct bsg_device *bsg_get_device(struct inode *inode, struct file *file)
|
||||
mutex_lock(&bsg_mutex);
|
||||
bcd = idr_find(&bsg_minor_idr, iminor(inode));
|
||||
if (bcd)
|
||||
get_device(bcd->dev);
|
||||
kref_get(&bcd->ref);
|
||||
mutex_unlock(&bsg_mutex);
|
||||
|
||||
if (!bcd)
|
||||
@ -808,7 +821,7 @@ static struct bsg_device *bsg_get_device(struct inode *inode, struct file *file)
|
||||
|
||||
bd = bsg_add_device(inode, bcd->queue, file);
|
||||
if (IS_ERR(bd))
|
||||
put_device(bcd->dev);
|
||||
kref_put(&bcd->ref, bsg_kref_release_function);
|
||||
|
||||
return bd;
|
||||
}
|
||||
@ -947,14 +960,14 @@ void bsg_unregister_queue(struct request_queue *q)
|
||||
idr_remove(&bsg_minor_idr, bcd->minor);
|
||||
sysfs_remove_link(&q->kobj, "bsg");
|
||||
device_unregister(bcd->class_dev);
|
||||
put_device(bcd->dev);
|
||||
bcd->class_dev = NULL;
|
||||
kref_put(&bcd->ref, bsg_kref_release_function);
|
||||
mutex_unlock(&bsg_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bsg_unregister_queue);
|
||||
|
||||
int bsg_register_queue(struct request_queue *q, struct device *gdev,
|
||||
const char *name)
|
||||
int bsg_register_queue(struct request_queue *q, struct device *parent,
|
||||
const char *name, void (*release)(struct device *))
|
||||
{
|
||||
struct bsg_class_device *bcd;
|
||||
dev_t dev;
|
||||
@ -965,7 +978,7 @@ int bsg_register_queue(struct request_queue *q, struct device *gdev,
|
||||
if (name)
|
||||
devname = name;
|
||||
else
|
||||
devname = gdev->bus_id;
|
||||
devname = parent->bus_id;
|
||||
|
||||
/*
|
||||
* we need a proper transport to send commands, not a stacked device
|
||||
@ -996,9 +1009,11 @@ int bsg_register_queue(struct request_queue *q, struct device *gdev,
|
||||
|
||||
bcd->minor = minor;
|
||||
bcd->queue = q;
|
||||
bcd->dev = get_device(gdev);
|
||||
bcd->parent = get_device(parent);
|
||||
bcd->release = release;
|
||||
kref_init(&bcd->ref);
|
||||
dev = MKDEV(bsg_major, bcd->minor);
|
||||
class_dev = device_create(bsg_class, gdev, dev, "%s", devname);
|
||||
class_dev = device_create(bsg_class, parent, dev, "%s", devname);
|
||||
if (IS_ERR(class_dev)) {
|
||||
ret = PTR_ERR(class_dev);
|
||||
goto put_dev;
|
||||
@ -1017,7 +1032,7 @@ int bsg_register_queue(struct request_queue *q, struct device *gdev,
|
||||
unregister_class_dev:
|
||||
device_unregister(class_dev);
|
||||
put_dev:
|
||||
put_device(gdev);
|
||||
put_device(parent);
|
||||
remove_idr:
|
||||
idr_remove(&bsg_minor_idr, minor);
|
||||
unlock:
|
||||
|
@ -31,7 +31,6 @@
|
||||
static LIST_HEAD(container_list);
|
||||
static DEFINE_MUTEX(container_list_lock);
|
||||
static struct class enclosure_class;
|
||||
static struct class enclosure_component_class;
|
||||
|
||||
/**
|
||||
* enclosure_find - find an enclosure given a device
|
||||
@ -166,6 +165,40 @@ void enclosure_unregister(struct enclosure_device *edev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(enclosure_unregister);
|
||||
|
||||
#define ENCLOSURE_NAME_SIZE 64
|
||||
|
||||
static void enclosure_link_name(struct enclosure_component *cdev, char *name)
|
||||
{
|
||||
strcpy(name, "enclosure_device:");
|
||||
strcat(name, cdev->cdev.bus_id);
|
||||
}
|
||||
|
||||
static void enclosure_remove_links(struct enclosure_component *cdev)
|
||||
{
|
||||
char name[ENCLOSURE_NAME_SIZE];
|
||||
|
||||
enclosure_link_name(cdev, name);
|
||||
sysfs_remove_link(&cdev->dev->kobj, name);
|
||||
sysfs_remove_link(&cdev->cdev.kobj, "device");
|
||||
}
|
||||
|
||||
static int enclosure_add_links(struct enclosure_component *cdev)
|
||||
{
|
||||
int error;
|
||||
char name[ENCLOSURE_NAME_SIZE];
|
||||
|
||||
error = sysfs_create_link(&cdev->cdev.kobj, &cdev->dev->kobj, "device");
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
enclosure_link_name(cdev, name);
|
||||
error = sysfs_create_link(&cdev->dev->kobj, &cdev->cdev.kobj, name);
|
||||
if (error)
|
||||
sysfs_remove_link(&cdev->cdev.kobj, "device");
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static void enclosure_release(struct device *cdev)
|
||||
{
|
||||
struct enclosure_device *edev = to_enclosure_device(cdev);
|
||||
@ -178,10 +211,15 @@ static void enclosure_component_release(struct device *dev)
|
||||
{
|
||||
struct enclosure_component *cdev = to_enclosure_component(dev);
|
||||
|
||||
put_device(cdev->dev);
|
||||
if (cdev->dev) {
|
||||
enclosure_remove_links(cdev);
|
||||
put_device(cdev->dev);
|
||||
}
|
||||
put_device(dev->parent);
|
||||
}
|
||||
|
||||
static struct attribute_group *enclosure_groups[];
|
||||
|
||||
/**
|
||||
* enclosure_component_register - add a particular component to an enclosure
|
||||
* @edev: the enclosure to add the component
|
||||
@ -217,12 +255,14 @@ enclosure_component_register(struct enclosure_device *edev,
|
||||
ecomp->number = number;
|
||||
cdev = &ecomp->cdev;
|
||||
cdev->parent = get_device(&edev->edev);
|
||||
cdev->class = &enclosure_component_class;
|
||||
if (name)
|
||||
snprintf(cdev->bus_id, BUS_ID_SIZE, "%s", name);
|
||||
else
|
||||
snprintf(cdev->bus_id, BUS_ID_SIZE, "%u", number);
|
||||
|
||||
cdev->release = enclosure_component_release;
|
||||
cdev->groups = enclosure_groups;
|
||||
|
||||
err = device_register(cdev);
|
||||
if (err)
|
||||
ERR_PTR(err);
|
||||
@ -255,10 +295,12 @@ int enclosure_add_device(struct enclosure_device *edev, int component,
|
||||
|
||||
cdev = &edev->component[component];
|
||||
|
||||
device_del(&cdev->cdev);
|
||||
if (cdev->dev)
|
||||
enclosure_remove_links(cdev);
|
||||
|
||||
put_device(cdev->dev);
|
||||
cdev->dev = get_device(dev);
|
||||
return device_add(&cdev->cdev);
|
||||
return enclosure_add_links(cdev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(enclosure_add_device);
|
||||
|
||||
@ -442,24 +484,32 @@ static ssize_t get_component_type(struct device *cdev,
|
||||
}
|
||||
|
||||
|
||||
static struct device_attribute enclosure_component_attrs[] = {
|
||||
__ATTR(fault, S_IRUGO | S_IWUSR, get_component_fault,
|
||||
set_component_fault),
|
||||
__ATTR(status, S_IRUGO | S_IWUSR, get_component_status,
|
||||
set_component_status),
|
||||
__ATTR(active, S_IRUGO | S_IWUSR, get_component_active,
|
||||
set_component_active),
|
||||
__ATTR(locate, S_IRUGO | S_IWUSR, get_component_locate,
|
||||
set_component_locate),
|
||||
__ATTR(type, S_IRUGO, get_component_type, NULL),
|
||||
__ATTR_NULL
|
||||
static DEVICE_ATTR(fault, S_IRUGO | S_IWUSR, get_component_fault,
|
||||
set_component_fault);
|
||||
static DEVICE_ATTR(status, S_IRUGO | S_IWUSR, get_component_status,
|
||||
set_component_status);
|
||||
static DEVICE_ATTR(active, S_IRUGO | S_IWUSR, get_component_active,
|
||||
set_component_active);
|
||||
static DEVICE_ATTR(locate, S_IRUGO | S_IWUSR, get_component_locate,
|
||||
set_component_locate);
|
||||
static DEVICE_ATTR(type, S_IRUGO, get_component_type, NULL);
|
||||
|
||||
static struct attribute *enclosure_component_attrs[] = {
|
||||
&dev_attr_fault.attr,
|
||||
&dev_attr_status.attr,
|
||||
&dev_attr_active.attr,
|
||||
&dev_attr_locate.attr,
|
||||
&dev_attr_type.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct class enclosure_component_class = {
|
||||
.name = "enclosure_component",
|
||||
.owner = THIS_MODULE,
|
||||
.dev_attrs = enclosure_component_attrs,
|
||||
.dev_release = enclosure_component_release,
|
||||
static struct attribute_group enclosure_group = {
|
||||
.attrs = enclosure_component_attrs,
|
||||
};
|
||||
|
||||
static struct attribute_group *enclosure_groups[] = {
|
||||
&enclosure_group,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int __init enclosure_init(void)
|
||||
@ -469,20 +519,12 @@ static int __init enclosure_init(void)
|
||||
err = class_register(&enclosure_class);
|
||||
if (err)
|
||||
return err;
|
||||
err = class_register(&enclosure_component_class);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
return 0;
|
||||
err_out:
|
||||
class_unregister(&enclosure_class);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit enclosure_exit(void)
|
||||
{
|
||||
class_unregister(&enclosure_component_class);
|
||||
class_unregister(&enclosure_class);
|
||||
}
|
||||
|
||||
|
@ -1927,7 +1927,8 @@ zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter,
|
||||
|
||||
/* setup new FSF request */
|
||||
retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA,
|
||||
0, NULL, &lock_flags, &fsf_req);
|
||||
ZFCP_WAIT_FOR_SBAL, NULL, &lock_flags,
|
||||
&fsf_req);
|
||||
if (retval) {
|
||||
ZFCP_LOG_INFO("error: Could not create exchange configuration "
|
||||
"data request for adapter %s.\n",
|
||||
@ -2035,21 +2036,21 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
|
||||
min(FC_SERIAL_NUMBER_SIZE, 17));
|
||||
}
|
||||
|
||||
ZFCP_LOG_NORMAL("The adapter %s reported the following "
|
||||
"characteristics:\n"
|
||||
"WWNN 0x%016Lx, "
|
||||
"WWPN 0x%016Lx, "
|
||||
"S_ID 0x%06x,\n"
|
||||
"adapter version 0x%x, "
|
||||
"LIC version 0x%x, "
|
||||
"FC link speed %d Gb/s\n",
|
||||
zfcp_get_busid_by_adapter(adapter),
|
||||
(wwn_t) fc_host_node_name(shost),
|
||||
(wwn_t) fc_host_port_name(shost),
|
||||
fc_host_port_id(shost),
|
||||
adapter->hydra_version,
|
||||
adapter->fsf_lic_version,
|
||||
fc_host_speed(shost));
|
||||
if (fsf_req->erp_action)
|
||||
ZFCP_LOG_NORMAL("The adapter %s reported the following "
|
||||
"characteristics:\n"
|
||||
"WWNN 0x%016Lx, WWPN 0x%016Lx, "
|
||||
"S_ID 0x%06x,\n"
|
||||
"adapter version 0x%x, "
|
||||
"LIC version 0x%x, "
|
||||
"FC link speed %d Gb/s\n",
|
||||
zfcp_get_busid_by_adapter(adapter),
|
||||
(wwn_t) fc_host_node_name(shost),
|
||||
(wwn_t) fc_host_port_name(shost),
|
||||
fc_host_port_id(shost),
|
||||
adapter->hydra_version,
|
||||
adapter->fsf_lic_version,
|
||||
fc_host_speed(shost));
|
||||
if (ZFCP_QTCB_VERSION < bottom->low_qtcb_version) {
|
||||
ZFCP_LOG_NORMAL("error: the adapter %s "
|
||||
"only supports newer control block "
|
||||
@ -2114,8 +2115,10 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
|
||||
zfcp_erp_adapter_shutdown(adapter, 0, 127, fsf_req);
|
||||
return -EIO;
|
||||
case FC_PORTTYPE_NPORT:
|
||||
ZFCP_LOG_NORMAL("Switched fabric fibrechannel "
|
||||
"network detected at adapter %s.\n",
|
||||
if (fsf_req->erp_action)
|
||||
ZFCP_LOG_NORMAL("Switched fabric fibrechannel "
|
||||
"network detected at adapter "
|
||||
"%s.\n",
|
||||
zfcp_get_busid_by_adapter(adapter));
|
||||
break;
|
||||
default:
|
||||
|
@ -213,6 +213,7 @@
|
||||
#define FSF_FEATURE_HBAAPI_MANAGEMENT 0x00000010
|
||||
#define FSF_FEATURE_ELS_CT_CHAINED_SBALS 0x00000020
|
||||
#define FSF_FEATURE_UPDATE_ALERT 0x00000100
|
||||
#define FSF_FEATURE_MEASUREMENT_DATA 0x00000200
|
||||
|
||||
/* host connection features */
|
||||
#define FSF_FEATURE_NPIV_MODE 0x00000001
|
||||
@ -340,6 +341,15 @@ struct fsf_qtcb_prefix {
|
||||
u8 res1[20];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct fsf_statistics_info {
|
||||
u64 input_req;
|
||||
u64 output_req;
|
||||
u64 control_req;
|
||||
u64 input_mb;
|
||||
u64 output_mb;
|
||||
u64 seconds_act;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
union fsf_status_qual {
|
||||
u8 byte[FSF_STATUS_QUALIFIER_SIZE];
|
||||
u16 halfword[FSF_STATUS_QUALIFIER_SIZE / sizeof (u16)];
|
||||
@ -436,7 +446,8 @@ struct fsf_qtcb_bottom_config {
|
||||
u32 hardware_version;
|
||||
u8 serial_number[32];
|
||||
struct fsf_nport_serv_param plogi_payload;
|
||||
u8 res4[160];
|
||||
struct fsf_statistics_info stat_info;
|
||||
u8 res4[112];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct fsf_qtcb_bottom_port {
|
||||
@ -469,7 +480,10 @@ struct fsf_qtcb_bottom_port {
|
||||
u64 control_requests;
|
||||
u64 input_mb; /* where 1 MByte == 1.000.000 Bytes */
|
||||
u64 output_mb; /* where 1 MByte == 1.000.000 Bytes */
|
||||
u8 res2[256];
|
||||
u8 cp_util;
|
||||
u8 cb_util;
|
||||
u8 a_util;
|
||||
u8 res2[253];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
union fsf_qtcb_bottom {
|
||||
|
@ -40,6 +40,7 @@ static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *, int,
|
||||
unsigned int, unsigned int);
|
||||
|
||||
static struct device_attribute *zfcp_sysfs_sdev_attrs[];
|
||||
static struct device_attribute *zfcp_a_stats_attrs[];
|
||||
|
||||
struct zfcp_data zfcp_data = {
|
||||
.scsi_host_template = {
|
||||
@ -61,6 +62,7 @@ struct zfcp_data zfcp_data = {
|
||||
.use_clustering = 1,
|
||||
.sdev_attrs = zfcp_sysfs_sdev_attrs,
|
||||
.max_sectors = ZFCP_MAX_SECTORS,
|
||||
.shost_attrs = zfcp_a_stats_attrs,
|
||||
},
|
||||
.driver_version = ZFCP_VERSION,
|
||||
};
|
||||
@ -809,4 +811,116 @@ static struct device_attribute *zfcp_sysfs_sdev_attrs[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static ssize_t zfcp_sysfs_adapter_util_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct Scsi_Host *scsi_host = dev_to_shost(dev);
|
||||
struct fsf_qtcb_bottom_port *qtcb_port;
|
||||
int retval;
|
||||
struct zfcp_adapter *adapter;
|
||||
|
||||
adapter = (struct zfcp_adapter *) scsi_host->hostdata[0];
|
||||
if (!(adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
qtcb_port = kzalloc(sizeof(struct fsf_qtcb_bottom_port), GFP_KERNEL);
|
||||
if (!qtcb_port)
|
||||
return -ENOMEM;
|
||||
|
||||
retval = zfcp_fsf_exchange_port_data_sync(adapter, qtcb_port);
|
||||
if (!retval)
|
||||
retval = sprintf(buf, "%u %u %u\n", qtcb_port->cp_util,
|
||||
qtcb_port->cb_util, qtcb_port->a_util);
|
||||
kfree(qtcb_port);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int zfcp_sysfs_adapter_ex_config(struct device *dev,
|
||||
struct fsf_statistics_info *stat_inf)
|
||||
{
|
||||
int retval;
|
||||
struct fsf_qtcb_bottom_config *qtcb_config;
|
||||
struct Scsi_Host *scsi_host = dev_to_shost(dev);
|
||||
struct zfcp_adapter *adapter;
|
||||
|
||||
adapter = (struct zfcp_adapter *) scsi_host->hostdata[0];
|
||||
if (!(adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
qtcb_config = kzalloc(sizeof(struct fsf_qtcb_bottom_config),
|
||||
GFP_KERNEL);
|
||||
if (!qtcb_config)
|
||||
return -ENOMEM;
|
||||
|
||||
retval = zfcp_fsf_exchange_config_data_sync(adapter, qtcb_config);
|
||||
if (!retval)
|
||||
*stat_inf = qtcb_config->stat_info;
|
||||
|
||||
kfree(qtcb_config);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static ssize_t zfcp_sysfs_adapter_request_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct fsf_statistics_info stat_info;
|
||||
int retval;
|
||||
|
||||
retval = zfcp_sysfs_adapter_ex_config(dev, &stat_info);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
return sprintf(buf, "%llu %llu %llu\n",
|
||||
(unsigned long long) stat_info.input_req,
|
||||
(unsigned long long) stat_info.output_req,
|
||||
(unsigned long long) stat_info.control_req);
|
||||
}
|
||||
|
||||
static ssize_t zfcp_sysfs_adapter_mb_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct fsf_statistics_info stat_info;
|
||||
int retval;
|
||||
|
||||
retval = zfcp_sysfs_adapter_ex_config(dev, &stat_info);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
return sprintf(buf, "%llu %llu\n",
|
||||
(unsigned long long) stat_info.input_mb,
|
||||
(unsigned long long) stat_info.output_mb);
|
||||
}
|
||||
|
||||
static ssize_t zfcp_sysfs_adapter_sec_active_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct fsf_statistics_info stat_info;
|
||||
int retval;
|
||||
|
||||
retval = zfcp_sysfs_adapter_ex_config(dev, &stat_info);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
return sprintf(buf, "%llu\n",
|
||||
(unsigned long long) stat_info.seconds_act);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(utilization, S_IRUGO, zfcp_sysfs_adapter_util_show, NULL);
|
||||
static DEVICE_ATTR(requests, S_IRUGO, zfcp_sysfs_adapter_request_show, NULL);
|
||||
static DEVICE_ATTR(megabytes, S_IRUGO, zfcp_sysfs_adapter_mb_show, NULL);
|
||||
static DEVICE_ATTR(seconds_active, S_IRUGO,
|
||||
zfcp_sysfs_adapter_sec_active_show, NULL);
|
||||
|
||||
static struct device_attribute *zfcp_a_stats_attrs[] = {
|
||||
&dev_attr_utilization,
|
||||
&dev_attr_requests,
|
||||
&dev_attr_megabytes,
|
||||
&dev_attr_seconds_active,
|
||||
NULL
|
||||
};
|
||||
|
||||
#undef ZFCP_LOG_AREA
|
||||
|
@ -1499,7 +1499,7 @@ static void FlashPoint_StartCCB(unsigned long pCurrCard, struct sccb *p_Sccb)
|
||||
thisCard = ((struct sccb_card *)pCurrCard)->cardIndex;
|
||||
ioport = ((struct sccb_card *)pCurrCard)->ioPort;
|
||||
|
||||
if ((p_Sccb->TargID > MAX_SCSI_TAR) || (p_Sccb->Lun > MAX_LUN)) {
|
||||
if ((p_Sccb->TargID >= MAX_SCSI_TAR) || (p_Sccb->Lun >= MAX_LUN)) {
|
||||
|
||||
p_Sccb->HostStatus = SCCB_COMPLETE;
|
||||
p_Sccb->SccbStatus = SCCB_ERROR;
|
||||
|
@ -1677,6 +1677,16 @@ config MAC_SCSI
|
||||
SCSI-HOWTO, available from
|
||||
<http://www.tldp.org/docs.html#howto>.
|
||||
|
||||
config SCSI_MAC_ESP
|
||||
tristate "Macintosh NCR53c9[46] SCSI"
|
||||
depends on MAC && SCSI
|
||||
help
|
||||
This is the NCR 53c9x SCSI controller found on most of the 68040
|
||||
based Macintoshes.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called mac_esp.
|
||||
|
||||
config MVME147_SCSI
|
||||
bool "WD33C93 SCSI driver for MVME147"
|
||||
depends on MVME147 && SCSI=y
|
||||
|
@ -46,6 +46,7 @@ obj-$(CONFIG_MVME147_SCSI) += mvme147.o wd33c93.o
|
||||
obj-$(CONFIG_SGIWD93_SCSI) += sgiwd93.o wd33c93.o
|
||||
obj-$(CONFIG_ATARI_SCSI) += atari_scsi.o
|
||||
obj-$(CONFIG_MAC_SCSI) += mac_scsi.o
|
||||
obj-$(CONFIG_SCSI_MAC_ESP) += esp_scsi.o mac_esp.o
|
||||
obj-$(CONFIG_SUN3_SCSI) += sun3_scsi.o sun3_scsi_vme.o
|
||||
obj-$(CONFIG_MVME16x_SCSI) += 53c700.o mvme16x_scsi.o
|
||||
obj-$(CONFIG_BVME6000_SCSI) += 53c700.o bvme6000_scsi.o
|
||||
|
@ -1432,15 +1432,10 @@ static void run(struct work_struct *work)
|
||||
*/
|
||||
static irqreturn_t intr(int irqno, void *dev_id)
|
||||
{
|
||||
struct Scsi_Host *shpnt = (struct Scsi_Host *)dev_id;
|
||||
struct Scsi_Host *shpnt = dev_id;
|
||||
unsigned long flags;
|
||||
unsigned char rev, dmacntrl0;
|
||||
|
||||
if (!shpnt) {
|
||||
printk(KERN_ERR "aha152x: catched interrupt %d for unknown controller.\n", irqno);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a couple of registers that are known to not be all 1's. If
|
||||
* we read all 1's (-1), that means that either:
|
||||
|
@ -153,8 +153,6 @@ struct aha1542_hostdata {
|
||||
|
||||
#define HOSTDATA(host) ((struct aha1542_hostdata *) &host->hostdata)
|
||||
|
||||
static struct Scsi_Host *aha_host[7]; /* One for each IRQ level (9-15) */
|
||||
|
||||
static DEFINE_SPINLOCK(aha1542_lock);
|
||||
|
||||
|
||||
@ -163,8 +161,7 @@ static DEFINE_SPINLOCK(aha1542_lock);
|
||||
|
||||
static void setup_mailboxes(int base_io, struct Scsi_Host *shpnt);
|
||||
static int aha1542_restart(struct Scsi_Host *shost);
|
||||
static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id);
|
||||
static irqreturn_t do_aha1542_intr_handle(int irq, void *dev_id);
|
||||
static void aha1542_intr_handle(struct Scsi_Host *shost);
|
||||
|
||||
#define aha1542_intr_reset(base) outb(IRST, CONTROL(base))
|
||||
|
||||
@ -404,23 +401,19 @@ static int __init aha1542_test_port(int bse, struct Scsi_Host *shpnt)
|
||||
}
|
||||
|
||||
/* A quick wrapper for do_aha1542_intr_handle to grab the spin lock */
|
||||
static irqreturn_t do_aha1542_intr_handle(int irq, void *dev_id)
|
||||
static irqreturn_t do_aha1542_intr_handle(int dummy, void *dev_id)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct Scsi_Host *shost;
|
||||
|
||||
shost = aha_host[irq - 9];
|
||||
if (!shost)
|
||||
panic("Splunge!");
|
||||
struct Scsi_Host *shost = dev_id;
|
||||
|
||||
spin_lock_irqsave(shost->host_lock, flags);
|
||||
aha1542_intr_handle(shost, dev_id);
|
||||
aha1542_intr_handle(shost);
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* A "high" level interrupt handler */
|
||||
static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id)
|
||||
static void aha1542_intr_handle(struct Scsi_Host *shost)
|
||||
{
|
||||
void (*my_done) (Scsi_Cmnd *) = NULL;
|
||||
int errstatus, mbi, mbo, mbistatus;
|
||||
@ -1197,7 +1190,8 @@ static int __init aha1542_detect(struct scsi_host_template * tpnt)
|
||||
|
||||
DEB(printk("aha1542_detect: enable interrupt channel %d\n", irq_level));
|
||||
spin_lock_irqsave(&aha1542_lock, flags);
|
||||
if (request_irq(irq_level, do_aha1542_intr_handle, 0, "aha1542", NULL)) {
|
||||
if (request_irq(irq_level, do_aha1542_intr_handle, 0,
|
||||
"aha1542", shpnt)) {
|
||||
printk(KERN_ERR "Unable to allocate IRQ for adaptec controller.\n");
|
||||
spin_unlock_irqrestore(&aha1542_lock, flags);
|
||||
goto unregister;
|
||||
@ -1205,7 +1199,7 @@ static int __init aha1542_detect(struct scsi_host_template * tpnt)
|
||||
if (dma_chan != 0xFF) {
|
||||
if (request_dma(dma_chan, "aha1542")) {
|
||||
printk(KERN_ERR "Unable to allocate DMA channel for Adaptec.\n");
|
||||
free_irq(irq_level, NULL);
|
||||
free_irq(irq_level, shpnt);
|
||||
spin_unlock_irqrestore(&aha1542_lock, flags);
|
||||
goto unregister;
|
||||
}
|
||||
@ -1214,7 +1208,7 @@ static int __init aha1542_detect(struct scsi_host_template * tpnt)
|
||||
enable_dma(dma_chan);
|
||||
}
|
||||
}
|
||||
aha_host[irq_level - 9] = shpnt;
|
||||
|
||||
shpnt->this_id = scsi_id;
|
||||
shpnt->unique_id = base_io;
|
||||
shpnt->io_port = base_io;
|
||||
@ -1276,7 +1270,7 @@ static int __init aha1542_detect(struct scsi_host_template * tpnt)
|
||||
static int aha1542_release(struct Scsi_Host *shost)
|
||||
{
|
||||
if (shost->irq)
|
||||
free_irq(shost->irq, NULL);
|
||||
free_irq(shost->irq, shost);
|
||||
if (shost->dma_channel != 0xff)
|
||||
free_dma(shost->dma_channel);
|
||||
if (shost->io_port && shost->n_io_port)
|
||||
|
@ -815,7 +815,7 @@ struct ahd_tmode_tstate {
|
||||
struct ahd_phase_table_entry {
|
||||
uint8_t phase;
|
||||
uint8_t mesg_out; /* Message response to parity errors */
|
||||
char *phasemsg;
|
||||
const char *phasemsg;
|
||||
};
|
||||
|
||||
/************************** Serial EEPROM Format ******************************/
|
||||
@ -1314,7 +1314,7 @@ typedef int (ahd_device_setup_t)(struct ahd_softc *);
|
||||
struct ahd_pci_identity {
|
||||
uint64_t full_id;
|
||||
uint64_t id_mask;
|
||||
char *name;
|
||||
const char *name;
|
||||
ahd_device_setup_t *setup;
|
||||
};
|
||||
|
||||
@ -1322,7 +1322,7 @@ struct ahd_pci_identity {
|
||||
struct aic7770_identity {
|
||||
uint32_t full_id;
|
||||
uint32_t id_mask;
|
||||
char *name;
|
||||
const char *name;
|
||||
ahd_device_setup_t *setup;
|
||||
};
|
||||
extern struct aic7770_identity aic7770_ident_table [];
|
||||
@ -1333,12 +1333,11 @@ extern const int ahd_num_aic7770_devs;
|
||||
|
||||
/*************************** Function Declarations ****************************/
|
||||
/******************************************************************************/
|
||||
void ahd_reset_cmds_pending(struct ahd_softc *ahd);
|
||||
|
||||
/***************************** PCI Front End *********************************/
|
||||
struct ahd_pci_identity *ahd_find_pci_device(ahd_dev_softc_t);
|
||||
const struct ahd_pci_identity *ahd_find_pci_device(ahd_dev_softc_t);
|
||||
int ahd_pci_config(struct ahd_softc *,
|
||||
struct ahd_pci_identity *);
|
||||
const struct ahd_pci_identity *);
|
||||
int ahd_pci_test_register_access(struct ahd_softc *);
|
||||
#ifdef CONFIG_PM
|
||||
void ahd_pci_suspend(struct ahd_softc *);
|
||||
@ -1376,16 +1375,6 @@ int ahd_write_flexport(struct ahd_softc *ahd,
|
||||
int ahd_read_flexport(struct ahd_softc *ahd, u_int addr,
|
||||
uint8_t *value);
|
||||
|
||||
/*************************** Interrupt Services *******************************/
|
||||
void ahd_run_qoutfifo(struct ahd_softc *ahd);
|
||||
#ifdef AHD_TARGET_MODE
|
||||
void ahd_run_tqinfifo(struct ahd_softc *ahd, int paused);
|
||||
#endif
|
||||
void ahd_handle_hwerrint(struct ahd_softc *ahd);
|
||||
void ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat);
|
||||
void ahd_handle_scsiint(struct ahd_softc *ahd,
|
||||
u_int intstat);
|
||||
|
||||
/***************************** Error Recovery *********************************/
|
||||
typedef enum {
|
||||
SEARCH_COMPLETE,
|
||||
@ -1479,7 +1468,7 @@ extern uint32_t ahd_debug;
|
||||
void ahd_print_devinfo(struct ahd_softc *ahd,
|
||||
struct ahd_devinfo *devinfo);
|
||||
void ahd_dump_card_state(struct ahd_softc *ahd);
|
||||
int ahd_print_register(ahd_reg_parse_entry_t *table,
|
||||
int ahd_print_register(const ahd_reg_parse_entry_t *table,
|
||||
u_int num_entries,
|
||||
const char *name,
|
||||
u_int address,
|
||||
|
@ -198,6 +198,7 @@ register SEQINTCODE {
|
||||
register CLRINT {
|
||||
address 0x003
|
||||
access_mode WO
|
||||
count 19
|
||||
field CLRHWERRINT 0x80 /* Rev B or greater */
|
||||
field CLRBRKADRINT 0x40
|
||||
field CLRSWTMINT 0x20
|
||||
@ -245,6 +246,7 @@ register CLRERR {
|
||||
register HCNTRL {
|
||||
address 0x005
|
||||
access_mode RW
|
||||
count 12
|
||||
field SEQ_RESET 0x80 /* Rev B or greater */
|
||||
field POWRDN 0x40
|
||||
field SWINT 0x10
|
||||
@ -262,6 +264,7 @@ register HNSCB_QOFF {
|
||||
address 0x006
|
||||
access_mode RW
|
||||
size 2
|
||||
count 2
|
||||
}
|
||||
|
||||
/*
|
||||
@ -270,6 +273,7 @@ register HNSCB_QOFF {
|
||||
register HESCB_QOFF {
|
||||
address 0x008
|
||||
access_mode RW
|
||||
count 2
|
||||
}
|
||||
|
||||
/*
|
||||
@ -287,6 +291,7 @@ register HS_MAILBOX {
|
||||
*/
|
||||
register SEQINTSTAT {
|
||||
address 0x00C
|
||||
count 1
|
||||
access_mode RO
|
||||
field SEQ_SWTMRTO 0x10
|
||||
field SEQ_SEQINT 0x08
|
||||
@ -332,6 +337,7 @@ register SNSCB_QOFF {
|
||||
*/
|
||||
register SESCB_QOFF {
|
||||
address 0x012
|
||||
count 2
|
||||
access_mode RW
|
||||
modes M_CCHAN
|
||||
}
|
||||
@ -397,6 +403,7 @@ register DFCNTRL {
|
||||
address 0x019
|
||||
access_mode RW
|
||||
modes M_DFF0, M_DFF1
|
||||
count 11
|
||||
field PRELOADEN 0x80
|
||||
field SCSIENWRDIS 0x40 /* Rev B only. */
|
||||
field SCSIEN 0x20
|
||||
@ -415,6 +422,7 @@ register DFCNTRL {
|
||||
*/
|
||||
register DSCOMMAND0 {
|
||||
address 0x019
|
||||
count 1
|
||||
access_mode RW
|
||||
modes M_CFG
|
||||
field CACHETHEN 0x80 /* Cache Threshold enable */
|
||||
@ -580,6 +588,7 @@ register DFF_THRSH {
|
||||
address 0x088
|
||||
access_mode RW
|
||||
modes M_CFG
|
||||
count 1
|
||||
field WR_DFTHRSH 0x70 {
|
||||
WR_DFTHRSH_MIN,
|
||||
WR_DFTHRSH_25,
|
||||
@ -800,6 +809,7 @@ register PCIXCTL {
|
||||
address 0x093
|
||||
access_mode RW
|
||||
modes M_CFG
|
||||
count 1
|
||||
field SERRPULSE 0x80
|
||||
field UNEXPSCIEN 0x20
|
||||
field SPLTSMADIS 0x10
|
||||
@ -844,6 +854,7 @@ register DCHSPLTSTAT0 {
|
||||
address 0x096
|
||||
access_mode RW
|
||||
modes M_DFF0, M_DFF1
|
||||
count 2
|
||||
field STAETERM 0x80
|
||||
field SCBCERR 0x40
|
||||
field SCADERR 0x20
|
||||
@ -895,6 +906,7 @@ register DCHSPLTSTAT1 {
|
||||
address 0x097
|
||||
access_mode RW
|
||||
modes M_DFF0, M_DFF1
|
||||
count 2
|
||||
field RXDATABUCKET 0x01
|
||||
}
|
||||
|
||||
@ -1048,6 +1060,7 @@ register SGSPLTSTAT0 {
|
||||
address 0x09E
|
||||
access_mode RW
|
||||
modes M_DFF0, M_DFF1
|
||||
count 2
|
||||
field STAETERM 0x80
|
||||
field SCBCERR 0x40
|
||||
field SCADERR 0x20
|
||||
@ -1065,6 +1078,7 @@ register SGSPLTSTAT1 {
|
||||
address 0x09F
|
||||
access_mode RW
|
||||
modes M_DFF0, M_DFF1
|
||||
count 2
|
||||
field RXDATABUCKET 0x01
|
||||
}
|
||||
|
||||
@ -1086,6 +1100,7 @@ register DF0PCISTAT {
|
||||
address 0x0A0
|
||||
access_mode RW
|
||||
modes M_CFG
|
||||
count 1
|
||||
field DPE 0x80
|
||||
field SSE 0x40
|
||||
field RMA 0x20
|
||||
@ -1184,6 +1199,7 @@ register TARGPCISTAT {
|
||||
address 0x0A7
|
||||
access_mode RW
|
||||
modes M_CFG
|
||||
count 5
|
||||
field DPE 0x80
|
||||
field SSE 0x40
|
||||
field STA 0x08
|
||||
@ -1198,6 +1214,7 @@ register LQIN {
|
||||
address 0x020
|
||||
access_mode RW
|
||||
size 20
|
||||
count 2
|
||||
modes M_DFF0, M_DFF1, M_SCSI
|
||||
}
|
||||
|
||||
@ -1229,6 +1246,7 @@ register LUNPTR {
|
||||
address 0x022
|
||||
access_mode RW
|
||||
modes M_CFG
|
||||
count 2
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1259,6 +1277,7 @@ register CMDLENPTR {
|
||||
address 0x025
|
||||
access_mode RW
|
||||
modes M_CFG
|
||||
count 1
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1270,6 +1289,7 @@ register ATTRPTR {
|
||||
address 0x026
|
||||
access_mode RW
|
||||
modes M_CFG
|
||||
count 1
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1281,6 +1301,7 @@ register FLAGPTR {
|
||||
address 0x027
|
||||
access_mode RW
|
||||
modes M_CFG
|
||||
count 1
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1291,6 +1312,7 @@ register CMDPTR {
|
||||
address 0x028
|
||||
access_mode RW
|
||||
modes M_CFG
|
||||
count 1
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1301,6 +1323,7 @@ register QNEXTPTR {
|
||||
address 0x029
|
||||
access_mode RW
|
||||
modes M_CFG
|
||||
count 1
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1323,6 +1346,7 @@ register ABRTBYTEPTR {
|
||||
address 0x02B
|
||||
access_mode RW
|
||||
modes M_CFG
|
||||
count 1
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1333,6 +1357,7 @@ register ABRTBITPTR {
|
||||
address 0x02C
|
||||
access_mode RW
|
||||
modes M_CFG
|
||||
count 1
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1370,6 +1395,7 @@ register LUNLEN {
|
||||
address 0x030
|
||||
access_mode RW
|
||||
modes M_CFG
|
||||
count 2
|
||||
mask ILUNLEN 0x0F
|
||||
mask TLUNLEN 0xF0
|
||||
}
|
||||
@ -1383,6 +1409,7 @@ register CDBLIMIT {
|
||||
address 0x031
|
||||
access_mode RW
|
||||
modes M_CFG
|
||||
count 1
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1394,6 +1421,7 @@ register MAXCMD {
|
||||
address 0x032
|
||||
access_mode RW
|
||||
modes M_CFG
|
||||
count 9
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1458,6 +1486,7 @@ register LQCTL1 {
|
||||
address 0x038
|
||||
access_mode RW
|
||||
modes M_DFF0, M_DFF1, M_SCSI
|
||||
count 2
|
||||
field PCI2PCI 0x04
|
||||
field SINGLECMD 0x02
|
||||
field ABORTPENDING 0x01
|
||||
@ -1470,6 +1499,7 @@ register LQCTL2 {
|
||||
address 0x039
|
||||
access_mode RW
|
||||
modes M_DFF0, M_DFF1, M_SCSI
|
||||
count 5
|
||||
field LQIRETRY 0x80
|
||||
field LQICONTINUE 0x40
|
||||
field LQITOIDLE 0x20
|
||||
@ -1528,6 +1558,7 @@ register SCSISEQ1 {
|
||||
address 0x03B
|
||||
access_mode RW
|
||||
modes M_DFF0, M_DFF1, M_SCSI
|
||||
count 8
|
||||
field MANUALCTL 0x40
|
||||
field ENSELI 0x20
|
||||
field ENRSELI 0x10
|
||||
@ -1667,6 +1698,9 @@ register SCSISIGO {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* SCSI Control Signal In
|
||||
*/
|
||||
register SCSISIGI {
|
||||
address 0x041
|
||||
access_mode RO
|
||||
@ -1703,6 +1737,7 @@ register MULTARGID {
|
||||
access_mode RW
|
||||
modes M_CFG
|
||||
size 2
|
||||
count 2
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1758,6 +1793,7 @@ register TARGIDIN {
|
||||
address 0x048
|
||||
access_mode RO
|
||||
modes M_DFF0, M_DFF1, M_SCSI
|
||||
count 2
|
||||
field CLKOUT 0x80
|
||||
field TARGID 0x0F
|
||||
}
|
||||
@ -1798,6 +1834,7 @@ register OPTIONMODE {
|
||||
address 0x04A
|
||||
access_mode RW
|
||||
modes M_CFG
|
||||
count 4
|
||||
field BIOSCANCTL 0x80
|
||||
field AUTOACKEN 0x40
|
||||
field BIASCANCTL 0x20
|
||||
@ -1850,6 +1887,7 @@ register SIMODE0 {
|
||||
address 0x04B
|
||||
access_mode RW
|
||||
modes M_CFG
|
||||
count 8
|
||||
field ENSELDO 0x40
|
||||
field ENSELDI 0x20
|
||||
field ENSELINGO 0x10
|
||||
@ -1945,6 +1983,7 @@ register PERRDIAG {
|
||||
address 0x04E
|
||||
access_mode RO
|
||||
modes M_DFF0, M_DFF1, M_SCSI
|
||||
count 3
|
||||
field HIZERO 0x80
|
||||
field HIPERR 0x40
|
||||
field PREVPHASE 0x20
|
||||
@ -1962,6 +2001,7 @@ register LQISTATE {
|
||||
address 0x04E
|
||||
access_mode RO
|
||||
modes M_CFG
|
||||
count 6
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1971,6 +2011,7 @@ register SOFFCNT {
|
||||
address 0x04F
|
||||
access_mode RO
|
||||
modes M_DFF0, M_DFF1, M_SCSI
|
||||
count 1
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1980,6 +2021,7 @@ register LQOSTATE {
|
||||
address 0x04F
|
||||
access_mode RO
|
||||
modes M_CFG
|
||||
count 2
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1989,6 +2031,7 @@ register LQISTAT0 {
|
||||
address 0x050
|
||||
access_mode RO
|
||||
modes M_DFF0, M_DFF1, M_SCSI
|
||||
count 2
|
||||
field LQIATNQAS 0x20
|
||||
field LQICRCT1 0x10
|
||||
field LQICRCT2 0x08
|
||||
@ -2004,6 +2047,7 @@ register CLRLQIINT0 {
|
||||
address 0x050
|
||||
access_mode WO
|
||||
modes M_DFF0, M_DFF1, M_SCSI
|
||||
count 1
|
||||
field CLRLQIATNQAS 0x20
|
||||
field CLRLQICRCT1 0x10
|
||||
field CLRLQICRCT2 0x08
|
||||
@ -2019,6 +2063,7 @@ register LQIMODE0 {
|
||||
address 0x050
|
||||
access_mode RW
|
||||
modes M_CFG
|
||||
count 3
|
||||
field ENLQIATNQASK 0x20
|
||||
field ENLQICRCT1 0x10
|
||||
field ENLQICRCT2 0x08
|
||||
@ -2034,6 +2079,7 @@ register LQISTAT1 {
|
||||
address 0x051
|
||||
access_mode RO
|
||||
modes M_DFF0, M_DFF1, M_SCSI
|
||||
count 3
|
||||
field LQIPHASE_LQ 0x80
|
||||
field LQIPHASE_NLQ 0x40
|
||||
field LQIABORT 0x20
|
||||
@ -2051,6 +2097,7 @@ register CLRLQIINT1 {
|
||||
address 0x051
|
||||
access_mode WO
|
||||
modes M_DFF0, M_DFF1, M_SCSI
|
||||
count 4
|
||||
field CLRLQIPHASE_LQ 0x80
|
||||
field CLRLQIPHASE_NLQ 0x40
|
||||
field CLRLIQABORT 0x20
|
||||
@ -2068,6 +2115,7 @@ register LQIMODE1 {
|
||||
address 0x051
|
||||
access_mode RW
|
||||
modes M_CFG
|
||||
count 4
|
||||
field ENLQIPHASE_LQ 0x80 /* LQIPHASE1 */
|
||||
field ENLQIPHASE_NLQ 0x40 /* LQIPHASE2 */
|
||||
field ENLIQABORT 0x20
|
||||
@ -2102,6 +2150,7 @@ register SSTAT3 {
|
||||
address 0x053
|
||||
access_mode RO
|
||||
modes M_DFF0, M_DFF1, M_SCSI
|
||||
count 3
|
||||
field NTRAMPERR 0x02
|
||||
field OSRAMPERR 0x01
|
||||
}
|
||||
@ -2113,6 +2162,7 @@ register CLRSINT3 {
|
||||
address 0x053
|
||||
access_mode WO
|
||||
modes M_DFF0, M_DFF1, M_SCSI
|
||||
count 3
|
||||
field CLRNTRAMPERR 0x02
|
||||
field CLROSRAMPERR 0x01
|
||||
}
|
||||
@ -2124,6 +2174,7 @@ register SIMODE3 {
|
||||
address 0x053
|
||||
access_mode RW
|
||||
modes M_CFG
|
||||
count 4
|
||||
field ENNTRAMPERR 0x02
|
||||
field ENOSRAMPERR 0x01
|
||||
}
|
||||
@ -2135,6 +2186,7 @@ register LQOSTAT0 {
|
||||
address 0x054
|
||||
access_mode RO
|
||||
modes M_DFF0, M_DFF1, M_SCSI
|
||||
count 2
|
||||
field LQOTARGSCBPERR 0x10
|
||||
field LQOSTOPT2 0x08
|
||||
field LQOATNLQ 0x04
|
||||
@ -2149,6 +2201,7 @@ register CLRLQOINT0 {
|
||||
address 0x054
|
||||
access_mode WO
|
||||
modes M_DFF0, M_DFF1, M_SCSI
|
||||
count 3
|
||||
field CLRLQOTARGSCBPERR 0x10
|
||||
field CLRLQOSTOPT2 0x08
|
||||
field CLRLQOATNLQ 0x04
|
||||
@ -2163,6 +2216,7 @@ register LQOMODE0 {
|
||||
address 0x054
|
||||
access_mode RW
|
||||
modes M_CFG
|
||||
count 4
|
||||
field ENLQOTARGSCBPERR 0x10
|
||||
field ENLQOSTOPT2 0x08
|
||||
field ENLQOATNLQ 0x04
|
||||
@ -2191,6 +2245,7 @@ register CLRLQOINT1 {
|
||||
address 0x055
|
||||
access_mode WO
|
||||
modes M_DFF0, M_DFF1, M_SCSI
|
||||
count 7
|
||||
field CLRLQOINITSCBPERR 0x10
|
||||
field CLRLQOSTOPI2 0x08
|
||||
field CLRLQOBADQAS 0x04
|
||||
@ -2205,6 +2260,7 @@ register LQOMODE1 {
|
||||
address 0x055
|
||||
access_mode RW
|
||||
modes M_CFG
|
||||
count 4
|
||||
field ENLQOINITSCBPERR 0x10
|
||||
field ENLQOSTOPI2 0x08
|
||||
field ENLQOBADQAS 0x04
|
||||
@ -2232,6 +2288,7 @@ register OS_SPACE_CNT {
|
||||
address 0x056
|
||||
access_mode RO
|
||||
modes M_CFG
|
||||
count 2
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2286,13 +2343,19 @@ register NEXTSCB {
|
||||
modes M_SCSI
|
||||
}
|
||||
|
||||
/* Rev B only. */
|
||||
/*
|
||||
* LQO SCSI Control
|
||||
* (Rev B only.)
|
||||
*/
|
||||
register LQOSCSCTL {
|
||||
address 0x05A
|
||||
access_mode RW
|
||||
size 1
|
||||
modes M_CFG
|
||||
count 1
|
||||
field LQOH2A_VERSION 0x80
|
||||
field LQOBUSETDLY 0x40
|
||||
field LQONOHOLDLACK 0x02
|
||||
field LQONOCHKOVER 0x01
|
||||
}
|
||||
|
||||
@ -2459,6 +2522,7 @@ register NEGPERIOD {
|
||||
address 0x061
|
||||
access_mode RW
|
||||
modes M_SCSI
|
||||
count 1
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2478,6 +2542,7 @@ register NEGOFFSET {
|
||||
address 0x062
|
||||
access_mode RW
|
||||
modes M_SCSI
|
||||
count 1
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2487,6 +2552,7 @@ register NEGPPROPTS {
|
||||
address 0x063
|
||||
access_mode RW
|
||||
modes M_SCSI
|
||||
count 1
|
||||
field PPROPT_PACE 0x08
|
||||
field PPROPT_QAS 0x04
|
||||
field PPROPT_DT 0x02
|
||||
@ -2516,12 +2582,19 @@ register ANNEXCOL {
|
||||
address 0x065
|
||||
access_mode RW
|
||||
modes M_SCSI
|
||||
count 7
|
||||
}
|
||||
|
||||
/*
|
||||
* SCSI Check
|
||||
* (Rev. B only)
|
||||
*/
|
||||
register SCSCHKN {
|
||||
address 0x066
|
||||
access_mode RW
|
||||
modes M_CFG
|
||||
count 1
|
||||
field BIDICHKDIS 0x80
|
||||
field STSELSKIDDIS 0x40
|
||||
field CURRFIFODEF 0x20
|
||||
field WIDERESEN 0x10
|
||||
@ -2561,6 +2634,7 @@ register ANNEXDAT {
|
||||
address 0x066
|
||||
access_mode RW
|
||||
modes M_SCSI
|
||||
count 3
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2596,6 +2670,7 @@ register TOWNID {
|
||||
address 0x069
|
||||
access_mode RW
|
||||
modes M_SCSI
|
||||
count 2
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2737,6 +2812,7 @@ register SCBAUTOPTR {
|
||||
address 0x0AB
|
||||
access_mode RW
|
||||
modes M_CFG
|
||||
count 1
|
||||
field AUSCBPTR_EN 0x80
|
||||
field SCBPTR_ADDR 0x38
|
||||
field SCBPTR_OFF 0x07
|
||||
@ -2881,6 +2957,7 @@ register BRDDAT {
|
||||
address 0x0B8
|
||||
access_mode RW
|
||||
modes M_SCSI
|
||||
count 2
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2890,6 +2967,7 @@ register BRDCTL {
|
||||
address 0x0B9
|
||||
access_mode RW
|
||||
modes M_SCSI
|
||||
count 7
|
||||
field FLXARBACK 0x80
|
||||
field FLXARBREQ 0x40
|
||||
field BRDADDR 0x38
|
||||
@ -2905,6 +2983,7 @@ register SEEADR {
|
||||
address 0x0BA
|
||||
access_mode RW
|
||||
modes M_SCSI
|
||||
count 4
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2915,6 +2994,7 @@ register SEEDAT {
|
||||
access_mode RW
|
||||
size 2
|
||||
modes M_SCSI
|
||||
count 4
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2924,6 +3004,7 @@ register SEESTAT {
|
||||
address 0x0BE
|
||||
access_mode RO
|
||||
modes M_SCSI
|
||||
count 1
|
||||
field INIT_DONE 0x80
|
||||
field SEEOPCODE 0x70
|
||||
field LDALTID_L 0x08
|
||||
@ -2939,6 +3020,7 @@ register SEECTL {
|
||||
address 0x0BE
|
||||
access_mode RW
|
||||
modes M_SCSI
|
||||
count 4
|
||||
field SEEOPCODE 0x70 {
|
||||
SEEOP_ERASE 0x70,
|
||||
SEEOP_READ 0x60,
|
||||
@ -3000,6 +3082,7 @@ register DSPDATACTL {
|
||||
address 0x0C1
|
||||
access_mode RW
|
||||
modes M_CFG
|
||||
count 3
|
||||
field BYPASSENAB 0x80
|
||||
field DESQDIS 0x10
|
||||
field RCVROFFSTDIS 0x04
|
||||
@ -3058,6 +3141,7 @@ register DSPSELECT {
|
||||
address 0x0C4
|
||||
access_mode RW
|
||||
modes M_CFG
|
||||
count 1
|
||||
field AUTOINCEN 0x80
|
||||
field DSPSEL 0x1F
|
||||
}
|
||||
@ -3071,6 +3155,7 @@ register WRTBIASCTL {
|
||||
address 0x0C5
|
||||
access_mode WO
|
||||
modes M_CFG
|
||||
count 3
|
||||
field AUTOXBCDIS 0x80
|
||||
field XMITMANVAL 0x3F
|
||||
}
|
||||
@ -3196,7 +3281,8 @@ register OVLYADDR {
|
||||
*/
|
||||
register SEQCTL0 {
|
||||
address 0x0D6
|
||||
access_mode RW
|
||||
access_mode RW
|
||||
count 11
|
||||
field PERRORDIS 0x80
|
||||
field PAUSEDIS 0x40
|
||||
field FAILDIS 0x20
|
||||
@ -3226,7 +3312,8 @@ register SEQCTL1 {
|
||||
*/
|
||||
register FLAGS {
|
||||
address 0x0D8
|
||||
access_mode RO
|
||||
access_mode RO
|
||||
count 23
|
||||
field ZERO 0x02
|
||||
field CARRY 0x01
|
||||
}
|
||||
@ -3255,7 +3342,8 @@ register SEQINTCTL {
|
||||
*/
|
||||
register SEQRAM {
|
||||
address 0x0DA
|
||||
access_mode RW
|
||||
access_mode RW
|
||||
count 2
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3266,6 +3354,7 @@ register PRGMCNT {
|
||||
address 0x0DE
|
||||
access_mode RW
|
||||
size 2
|
||||
count 5
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3273,7 +3362,7 @@ register PRGMCNT {
|
||||
*/
|
||||
register ACCUM {
|
||||
address 0x0E0
|
||||
access_mode RW
|
||||
access_mode RW
|
||||
accumulator
|
||||
}
|
||||
|
||||
@ -3401,6 +3490,7 @@ register INTVEC1_ADDR {
|
||||
access_mode RW
|
||||
size 2
|
||||
modes M_CFG
|
||||
count 1
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3412,6 +3502,7 @@ register CURADDR {
|
||||
access_mode RW
|
||||
size 2
|
||||
modes M_SCSI
|
||||
count 2
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3423,6 +3514,7 @@ register INTVEC2_ADDR {
|
||||
access_mode RW
|
||||
size 2
|
||||
modes M_CFG
|
||||
count 1
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3579,6 +3671,7 @@ scratch_ram {
|
||||
/* Parameters for DMA Logic */
|
||||
DMAPARAMS {
|
||||
size 1
|
||||
count 8
|
||||
field PRELOADEN 0x80
|
||||
field WIDEODD 0x40
|
||||
field SCSIEN 0x20
|
||||
@ -3648,9 +3741,11 @@ scratch_ram {
|
||||
*/
|
||||
KERNEL_TQINPOS {
|
||||
size 1
|
||||
count 1
|
||||
}
|
||||
TQINPOS {
|
||||
TQINPOS {
|
||||
size 1
|
||||
count 8
|
||||
}
|
||||
/*
|
||||
* Base address of our shared data with the kernel driver in host
|
||||
@ -3681,6 +3776,7 @@ scratch_ram {
|
||||
}
|
||||
ARG_2 {
|
||||
size 1
|
||||
count 1
|
||||
alias RETURN_2
|
||||
}
|
||||
|
||||
@ -3698,6 +3794,7 @@ scratch_ram {
|
||||
*/
|
||||
SCSISEQ_TEMPLATE {
|
||||
size 1
|
||||
count 7
|
||||
field MANUALCTL 0x40
|
||||
field ENSELI 0x20
|
||||
field ENRSELI 0x10
|
||||
@ -3711,6 +3808,7 @@ scratch_ram {
|
||||
*/
|
||||
INITIATOR_TAG {
|
||||
size 1
|
||||
count 1
|
||||
}
|
||||
|
||||
SEQ_FLAGS2 {
|
||||
@ -3777,6 +3875,7 @@ scratch_ram {
|
||||
*/
|
||||
CMDSIZE_TABLE {
|
||||
size 8
|
||||
count 8
|
||||
}
|
||||
/*
|
||||
* When an SCB with the MK_MESSAGE flag is
|
||||
@ -3803,8 +3902,8 @@ scratch_ram {
|
||||
/************************* Hardware SCB Definition ****************************/
|
||||
scb {
|
||||
address 0x180
|
||||
size 64
|
||||
modes 0, 1, 2, 3
|
||||
size 64
|
||||
modes 0, 1, 2, 3
|
||||
SCB_RESIDUAL_DATACNT {
|
||||
size 4
|
||||
alias SCB_CDB_STORE
|
||||
|
@ -52,7 +52,7 @@
|
||||
|
||||
|
||||
/***************************** Lookup Tables **********************************/
|
||||
static char *ahd_chip_names[] =
|
||||
static const char *const ahd_chip_names[] =
|
||||
{
|
||||
"NONE",
|
||||
"aic7901",
|
||||
@ -66,10 +66,10 @@ static const u_int num_chip_names = ARRAY_SIZE(ahd_chip_names);
|
||||
*/
|
||||
struct ahd_hard_error_entry {
|
||||
uint8_t errno;
|
||||
char *errmesg;
|
||||
const char *errmesg;
|
||||
};
|
||||
|
||||
static struct ahd_hard_error_entry ahd_hard_errors[] = {
|
||||
static const struct ahd_hard_error_entry ahd_hard_errors[] = {
|
||||
{ DSCTMOUT, "Discard Timer has timed out" },
|
||||
{ ILLOPCODE, "Illegal Opcode in sequencer program" },
|
||||
{ SQPARERR, "Sequencer Parity Error" },
|
||||
@ -79,7 +79,7 @@ static struct ahd_hard_error_entry ahd_hard_errors[] = {
|
||||
};
|
||||
static const u_int num_errors = ARRAY_SIZE(ahd_hard_errors);
|
||||
|
||||
static struct ahd_phase_table_entry ahd_phase_table[] =
|
||||
static const struct ahd_phase_table_entry ahd_phase_table[] =
|
||||
{
|
||||
{ P_DATAOUT, MSG_NOOP, "in Data-out phase" },
|
||||
{ P_DATAIN, MSG_INITIATOR_DET_ERR, "in Data-in phase" },
|
||||
@ -213,7 +213,7 @@ static void ahd_dumpseq(struct ahd_softc *ahd);
|
||||
#endif
|
||||
static void ahd_loadseq(struct ahd_softc *ahd);
|
||||
static int ahd_check_patch(struct ahd_softc *ahd,
|
||||
struct patch **start_patch,
|
||||
const struct patch **start_patch,
|
||||
u_int start_instr, u_int *skip_addr);
|
||||
static u_int ahd_resolve_seqaddr(struct ahd_softc *ahd,
|
||||
u_int address);
|
||||
@ -254,7 +254,7 @@ static void ahd_freeze_devq(struct ahd_softc *ahd,
|
||||
struct scb *scb);
|
||||
static void ahd_handle_scb_status(struct ahd_softc *ahd,
|
||||
struct scb *scb);
|
||||
static struct ahd_phase_table_entry* ahd_lookup_phase_entry(int phase);
|
||||
static const struct ahd_phase_table_entry* ahd_lookup_phase_entry(int phase);
|
||||
static void ahd_shutdown(void *arg);
|
||||
static void ahd_update_coalescing_values(struct ahd_softc *ahd,
|
||||
u_int timer,
|
||||
@ -266,8 +266,774 @@ static int ahd_match_scb(struct ahd_softc *ahd, struct scb *scb,
|
||||
int target, char channel, int lun,
|
||||
u_int tag, role_t role);
|
||||
|
||||
/******************************** Private Inlines *****************************/
|
||||
static void ahd_reset_cmds_pending(struct ahd_softc *ahd);
|
||||
|
||||
/*************************** Interrupt Services *******************************/
|
||||
static void ahd_run_qoutfifo(struct ahd_softc *ahd);
|
||||
#ifdef AHD_TARGET_MODE
|
||||
static void ahd_run_tqinfifo(struct ahd_softc *ahd, int paused);
|
||||
#endif
|
||||
static void ahd_handle_hwerrint(struct ahd_softc *ahd);
|
||||
static void ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat);
|
||||
static void ahd_handle_scsiint(struct ahd_softc *ahd,
|
||||
u_int intstat);
|
||||
|
||||
/************************ Sequencer Execution Control *************************/
|
||||
void
|
||||
ahd_set_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst)
|
||||
{
|
||||
if (ahd->src_mode == src && ahd->dst_mode == dst)
|
||||
return;
|
||||
#ifdef AHD_DEBUG
|
||||
if (ahd->src_mode == AHD_MODE_UNKNOWN
|
||||
|| ahd->dst_mode == AHD_MODE_UNKNOWN)
|
||||
panic("Setting mode prior to saving it.\n");
|
||||
if ((ahd_debug & AHD_SHOW_MODEPTR) != 0)
|
||||
printf("%s: Setting mode 0x%x\n", ahd_name(ahd),
|
||||
ahd_build_mode_state(ahd, src, dst));
|
||||
#endif
|
||||
ahd_outb(ahd, MODE_PTR, ahd_build_mode_state(ahd, src, dst));
|
||||
ahd->src_mode = src;
|
||||
ahd->dst_mode = dst;
|
||||
}
|
||||
|
||||
static void
|
||||
ahd_update_modes(struct ahd_softc *ahd)
|
||||
{
|
||||
ahd_mode_state mode_ptr;
|
||||
ahd_mode src;
|
||||
ahd_mode dst;
|
||||
|
||||
mode_ptr = ahd_inb(ahd, MODE_PTR);
|
||||
#ifdef AHD_DEBUG
|
||||
if ((ahd_debug & AHD_SHOW_MODEPTR) != 0)
|
||||
printf("Reading mode 0x%x\n", mode_ptr);
|
||||
#endif
|
||||
ahd_extract_mode_state(ahd, mode_ptr, &src, &dst);
|
||||
ahd_known_modes(ahd, src, dst);
|
||||
}
|
||||
|
||||
static void
|
||||
ahd_assert_modes(struct ahd_softc *ahd, ahd_mode srcmode,
|
||||
ahd_mode dstmode, const char *file, int line)
|
||||
{
|
||||
#ifdef AHD_DEBUG
|
||||
if ((srcmode & AHD_MK_MSK(ahd->src_mode)) == 0
|
||||
|| (dstmode & AHD_MK_MSK(ahd->dst_mode)) == 0) {
|
||||
panic("%s:%s:%d: Mode assertion failed.\n",
|
||||
ahd_name(ahd), file, line);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#define AHD_ASSERT_MODES(ahd, source, dest) \
|
||||
ahd_assert_modes(ahd, source, dest, __FILE__, __LINE__);
|
||||
|
||||
ahd_mode_state
|
||||
ahd_save_modes(struct ahd_softc *ahd)
|
||||
{
|
||||
if (ahd->src_mode == AHD_MODE_UNKNOWN
|
||||
|| ahd->dst_mode == AHD_MODE_UNKNOWN)
|
||||
ahd_update_modes(ahd);
|
||||
|
||||
return (ahd_build_mode_state(ahd, ahd->src_mode, ahd->dst_mode));
|
||||
}
|
||||
|
||||
void
|
||||
ahd_restore_modes(struct ahd_softc *ahd, ahd_mode_state state)
|
||||
{
|
||||
ahd_mode src;
|
||||
ahd_mode dst;
|
||||
|
||||
ahd_extract_mode_state(ahd, state, &src, &dst);
|
||||
ahd_set_modes(ahd, src, dst);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine whether the sequencer has halted code execution.
|
||||
* Returns non-zero status if the sequencer is stopped.
|
||||
*/
|
||||
int
|
||||
ahd_is_paused(struct ahd_softc *ahd)
|
||||
{
|
||||
return ((ahd_inb(ahd, HCNTRL) & PAUSE) != 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Request that the sequencer stop and wait, indefinitely, for it
|
||||
* to stop. The sequencer will only acknowledge that it is paused
|
||||
* once it has reached an instruction boundary and PAUSEDIS is
|
||||
* cleared in the SEQCTL register. The sequencer may use PAUSEDIS
|
||||
* for critical sections.
|
||||
*/
|
||||
void
|
||||
ahd_pause(struct ahd_softc *ahd)
|
||||
{
|
||||
ahd_outb(ahd, HCNTRL, ahd->pause);
|
||||
|
||||
/*
|
||||
* Since the sequencer can disable pausing in a critical section, we
|
||||
* must loop until it actually stops.
|
||||
*/
|
||||
while (ahd_is_paused(ahd) == 0)
|
||||
;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow the sequencer to continue program execution.
|
||||
* We check here to ensure that no additional interrupt
|
||||
* sources that would cause the sequencer to halt have been
|
||||
* asserted. If, for example, a SCSI bus reset is detected
|
||||
* while we are fielding a different, pausing, interrupt type,
|
||||
* we don't want to release the sequencer before going back
|
||||
* into our interrupt handler and dealing with this new
|
||||
* condition.
|
||||
*/
|
||||
void
|
||||
ahd_unpause(struct ahd_softc *ahd)
|
||||
{
|
||||
/*
|
||||
* Automatically restore our modes to those saved
|
||||
* prior to the first change of the mode.
|
||||
*/
|
||||
if (ahd->saved_src_mode != AHD_MODE_UNKNOWN
|
||||
&& ahd->saved_dst_mode != AHD_MODE_UNKNOWN) {
|
||||
if ((ahd->flags & AHD_UPDATE_PEND_CMDS) != 0)
|
||||
ahd_reset_cmds_pending(ahd);
|
||||
ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode);
|
||||
}
|
||||
|
||||
if ((ahd_inb(ahd, INTSTAT) & ~CMDCMPLT) == 0)
|
||||
ahd_outb(ahd, HCNTRL, ahd->unpause);
|
||||
|
||||
ahd_known_modes(ahd, AHD_MODE_UNKNOWN, AHD_MODE_UNKNOWN);
|
||||
}
|
||||
|
||||
/*********************** Scatter Gather List Handling *************************/
|
||||
void *
|
||||
ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb,
|
||||
void *sgptr, dma_addr_t addr, bus_size_t len, int last)
|
||||
{
|
||||
scb->sg_count++;
|
||||
if (sizeof(dma_addr_t) > 4
|
||||
&& (ahd->flags & AHD_64BIT_ADDRESSING) != 0) {
|
||||
struct ahd_dma64_seg *sg;
|
||||
|
||||
sg = (struct ahd_dma64_seg *)sgptr;
|
||||
sg->addr = ahd_htole64(addr);
|
||||
sg->len = ahd_htole32(len | (last ? AHD_DMA_LAST_SEG : 0));
|
||||
return (sg + 1);
|
||||
} else {
|
||||
struct ahd_dma_seg *sg;
|
||||
|
||||
sg = (struct ahd_dma_seg *)sgptr;
|
||||
sg->addr = ahd_htole32(addr & 0xFFFFFFFF);
|
||||
sg->len = ahd_htole32(len | ((addr >> 8) & 0x7F000000)
|
||||
| (last ? AHD_DMA_LAST_SEG : 0));
|
||||
return (sg + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ahd_setup_scb_common(struct ahd_softc *ahd, struct scb *scb)
|
||||
{
|
||||
/* XXX Handle target mode SCBs. */
|
||||
scb->crc_retry_count = 0;
|
||||
if ((scb->flags & SCB_PACKETIZED) != 0) {
|
||||
/* XXX what about ACA?? It is type 4, but TAG_TYPE == 0x3. */
|
||||
scb->hscb->task_attribute = scb->hscb->control & SCB_TAG_TYPE;
|
||||
} else {
|
||||
if (ahd_get_transfer_length(scb) & 0x01)
|
||||
scb->hscb->task_attribute = SCB_XFERLEN_ODD;
|
||||
else
|
||||
scb->hscb->task_attribute = 0;
|
||||
}
|
||||
|
||||
if (scb->hscb->cdb_len <= MAX_CDB_LEN_WITH_SENSE_ADDR
|
||||
|| (scb->hscb->cdb_len & SCB_CDB_LEN_PTR) != 0)
|
||||
scb->hscb->shared_data.idata.cdb_plus_saddr.sense_addr =
|
||||
ahd_htole32(scb->sense_busaddr);
|
||||
}
|
||||
|
||||
static void
|
||||
ahd_setup_data_scb(struct ahd_softc *ahd, struct scb *scb)
|
||||
{
|
||||
/*
|
||||
* Copy the first SG into the "current" data ponter area.
|
||||
*/
|
||||
if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) {
|
||||
struct ahd_dma64_seg *sg;
|
||||
|
||||
sg = (struct ahd_dma64_seg *)scb->sg_list;
|
||||
scb->hscb->dataptr = sg->addr;
|
||||
scb->hscb->datacnt = sg->len;
|
||||
} else {
|
||||
struct ahd_dma_seg *sg;
|
||||
uint32_t *dataptr_words;
|
||||
|
||||
sg = (struct ahd_dma_seg *)scb->sg_list;
|
||||
dataptr_words = (uint32_t*)&scb->hscb->dataptr;
|
||||
dataptr_words[0] = sg->addr;
|
||||
dataptr_words[1] = 0;
|
||||
if ((ahd->flags & AHD_39BIT_ADDRESSING) != 0) {
|
||||
uint64_t high_addr;
|
||||
|
||||
high_addr = ahd_le32toh(sg->len) & 0x7F000000;
|
||||
scb->hscb->dataptr |= ahd_htole64(high_addr << 8);
|
||||
}
|
||||
scb->hscb->datacnt = sg->len;
|
||||
}
|
||||
/*
|
||||
* Note where to find the SG entries in bus space.
|
||||
* We also set the full residual flag which the
|
||||
* sequencer will clear as soon as a data transfer
|
||||
* occurs.
|
||||
*/
|
||||
scb->hscb->sgptr = ahd_htole32(scb->sg_list_busaddr|SG_FULL_RESID);
|
||||
}
|
||||
|
||||
static void
|
||||
ahd_setup_noxfer_scb(struct ahd_softc *ahd, struct scb *scb)
|
||||
{
|
||||
scb->hscb->sgptr = ahd_htole32(SG_LIST_NULL);
|
||||
scb->hscb->dataptr = 0;
|
||||
scb->hscb->datacnt = 0;
|
||||
}
|
||||
|
||||
/************************** Memory mapping routines ***************************/
|
||||
static void *
|
||||
ahd_sg_bus_to_virt(struct ahd_softc *ahd, struct scb *scb, uint32_t sg_busaddr)
|
||||
{
|
||||
dma_addr_t sg_offset;
|
||||
|
||||
/* sg_list_phys points to entry 1, not 0 */
|
||||
sg_offset = sg_busaddr - (scb->sg_list_busaddr - ahd_sg_size(ahd));
|
||||
return ((uint8_t *)scb->sg_list + sg_offset);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
ahd_sg_virt_to_bus(struct ahd_softc *ahd, struct scb *scb, void *sg)
|
||||
{
|
||||
dma_addr_t sg_offset;
|
||||
|
||||
/* sg_list_phys points to entry 1, not 0 */
|
||||
sg_offset = ((uint8_t *)sg - (uint8_t *)scb->sg_list)
|
||||
- ahd_sg_size(ahd);
|
||||
|
||||
return (scb->sg_list_busaddr + sg_offset);
|
||||
}
|
||||
|
||||
static void
|
||||
ahd_sync_scb(struct ahd_softc *ahd, struct scb *scb, int op)
|
||||
{
|
||||
ahd_dmamap_sync(ahd, ahd->scb_data.hscb_dmat,
|
||||
scb->hscb_map->dmamap,
|
||||
/*offset*/(uint8_t*)scb->hscb - scb->hscb_map->vaddr,
|
||||
/*len*/sizeof(*scb->hscb), op);
|
||||
}
|
||||
|
||||
void
|
||||
ahd_sync_sglist(struct ahd_softc *ahd, struct scb *scb, int op)
|
||||
{
|
||||
if (scb->sg_count == 0)
|
||||
return;
|
||||
|
||||
ahd_dmamap_sync(ahd, ahd->scb_data.sg_dmat,
|
||||
scb->sg_map->dmamap,
|
||||
/*offset*/scb->sg_list_busaddr - ahd_sg_size(ahd),
|
||||
/*len*/ahd_sg_size(ahd) * scb->sg_count, op);
|
||||
}
|
||||
|
||||
static void
|
||||
ahd_sync_sense(struct ahd_softc *ahd, struct scb *scb, int op)
|
||||
{
|
||||
ahd_dmamap_sync(ahd, ahd->scb_data.sense_dmat,
|
||||
scb->sense_map->dmamap,
|
||||
/*offset*/scb->sense_busaddr,
|
||||
/*len*/AHD_SENSE_BUFSIZE, op);
|
||||
}
|
||||
|
||||
#ifdef AHD_TARGET_MODE
|
||||
static uint32_t
|
||||
ahd_targetcmd_offset(struct ahd_softc *ahd, u_int index)
|
||||
{
|
||||
return (((uint8_t *)&ahd->targetcmds[index])
|
||||
- (uint8_t *)ahd->qoutfifo);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*********************** Miscelaneous Support Functions ***********************/
|
||||
/*
|
||||
* Return pointers to the transfer negotiation information
|
||||
* for the specified our_id/remote_id pair.
|
||||
*/
|
||||
struct ahd_initiator_tinfo *
|
||||
ahd_fetch_transinfo(struct ahd_softc *ahd, char channel, u_int our_id,
|
||||
u_int remote_id, struct ahd_tmode_tstate **tstate)
|
||||
{
|
||||
/*
|
||||
* Transfer data structures are stored from the perspective
|
||||
* of the target role. Since the parameters for a connection
|
||||
* in the initiator role to a given target are the same as
|
||||
* when the roles are reversed, we pretend we are the target.
|
||||
*/
|
||||
if (channel == 'B')
|
||||
our_id += 8;
|
||||
*tstate = ahd->enabled_targets[our_id];
|
||||
return (&(*tstate)->transinfo[remote_id]);
|
||||
}
|
||||
|
||||
uint16_t
|
||||
ahd_inw(struct ahd_softc *ahd, u_int port)
|
||||
{
|
||||
/*
|
||||
* Read high byte first as some registers increment
|
||||
* or have other side effects when the low byte is
|
||||
* read.
|
||||
*/
|
||||
uint16_t r = ahd_inb(ahd, port+1) << 8;
|
||||
return r | ahd_inb(ahd, port);
|
||||
}
|
||||
|
||||
void
|
||||
ahd_outw(struct ahd_softc *ahd, u_int port, u_int value)
|
||||
{
|
||||
/*
|
||||
* Write low byte first to accomodate registers
|
||||
* such as PRGMCNT where the order maters.
|
||||
*/
|
||||
ahd_outb(ahd, port, value & 0xFF);
|
||||
ahd_outb(ahd, port+1, (value >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ahd_inl(struct ahd_softc *ahd, u_int port)
|
||||
{
|
||||
return ((ahd_inb(ahd, port))
|
||||
| (ahd_inb(ahd, port+1) << 8)
|
||||
| (ahd_inb(ahd, port+2) << 16)
|
||||
| (ahd_inb(ahd, port+3) << 24));
|
||||
}
|
||||
|
||||
void
|
||||
ahd_outl(struct ahd_softc *ahd, u_int port, uint32_t value)
|
||||
{
|
||||
ahd_outb(ahd, port, (value) & 0xFF);
|
||||
ahd_outb(ahd, port+1, ((value) >> 8) & 0xFF);
|
||||
ahd_outb(ahd, port+2, ((value) >> 16) & 0xFF);
|
||||
ahd_outb(ahd, port+3, ((value) >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
ahd_inq(struct ahd_softc *ahd, u_int port)
|
||||
{
|
||||
return ((ahd_inb(ahd, port))
|
||||
| (ahd_inb(ahd, port+1) << 8)
|
||||
| (ahd_inb(ahd, port+2) << 16)
|
||||
| (ahd_inb(ahd, port+3) << 24)
|
||||
| (((uint64_t)ahd_inb(ahd, port+4)) << 32)
|
||||
| (((uint64_t)ahd_inb(ahd, port+5)) << 40)
|
||||
| (((uint64_t)ahd_inb(ahd, port+6)) << 48)
|
||||
| (((uint64_t)ahd_inb(ahd, port+7)) << 56));
|
||||
}
|
||||
|
||||
void
|
||||
ahd_outq(struct ahd_softc *ahd, u_int port, uint64_t value)
|
||||
{
|
||||
ahd_outb(ahd, port, value & 0xFF);
|
||||
ahd_outb(ahd, port+1, (value >> 8) & 0xFF);
|
||||
ahd_outb(ahd, port+2, (value >> 16) & 0xFF);
|
||||
ahd_outb(ahd, port+3, (value >> 24) & 0xFF);
|
||||
ahd_outb(ahd, port+4, (value >> 32) & 0xFF);
|
||||
ahd_outb(ahd, port+5, (value >> 40) & 0xFF);
|
||||
ahd_outb(ahd, port+6, (value >> 48) & 0xFF);
|
||||
ahd_outb(ahd, port+7, (value >> 56) & 0xFF);
|
||||
}
|
||||
|
||||
u_int
|
||||
ahd_get_scbptr(struct ahd_softc *ahd)
|
||||
{
|
||||
AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK),
|
||||
~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK));
|
||||
return (ahd_inb(ahd, SCBPTR) | (ahd_inb(ahd, SCBPTR + 1) << 8));
|
||||
}
|
||||
|
||||
void
|
||||
ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr)
|
||||
{
|
||||
AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK),
|
||||
~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK));
|
||||
ahd_outb(ahd, SCBPTR, scbptr & 0xFF);
|
||||
ahd_outb(ahd, SCBPTR+1, (scbptr >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
#if 0 /* unused */
|
||||
static u_int
|
||||
ahd_get_hnscb_qoff(struct ahd_softc *ahd)
|
||||
{
|
||||
return (ahd_inw_atomic(ahd, HNSCB_QOFF));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value)
|
||||
{
|
||||
ahd_outw_atomic(ahd, HNSCB_QOFF, value);
|
||||
}
|
||||
|
||||
#if 0 /* unused */
|
||||
static u_int
|
||||
ahd_get_hescb_qoff(struct ahd_softc *ahd)
|
||||
{
|
||||
return (ahd_inb(ahd, HESCB_QOFF));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value)
|
||||
{
|
||||
ahd_outb(ahd, HESCB_QOFF, value);
|
||||
}
|
||||
|
||||
static u_int
|
||||
ahd_get_snscb_qoff(struct ahd_softc *ahd)
|
||||
{
|
||||
u_int oldvalue;
|
||||
|
||||
AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
|
||||
oldvalue = ahd_inw(ahd, SNSCB_QOFF);
|
||||
ahd_outw(ahd, SNSCB_QOFF, oldvalue);
|
||||
return (oldvalue);
|
||||
}
|
||||
|
||||
static void
|
||||
ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value)
|
||||
{
|
||||
AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
|
||||
ahd_outw(ahd, SNSCB_QOFF, value);
|
||||
}
|
||||
|
||||
#if 0 /* unused */
|
||||
static u_int
|
||||
ahd_get_sescb_qoff(struct ahd_softc *ahd)
|
||||
{
|
||||
AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
|
||||
return (ahd_inb(ahd, SESCB_QOFF));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value)
|
||||
{
|
||||
AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
|
||||
ahd_outb(ahd, SESCB_QOFF, value);
|
||||
}
|
||||
|
||||
#if 0 /* unused */
|
||||
static u_int
|
||||
ahd_get_sdscb_qoff(struct ahd_softc *ahd)
|
||||
{
|
||||
AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
|
||||
return (ahd_inb(ahd, SDSCB_QOFF) | (ahd_inb(ahd, SDSCB_QOFF + 1) << 8));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value)
|
||||
{
|
||||
AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
|
||||
ahd_outb(ahd, SDSCB_QOFF, value & 0xFF);
|
||||
ahd_outb(ahd, SDSCB_QOFF+1, (value >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
u_int
|
||||
ahd_inb_scbram(struct ahd_softc *ahd, u_int offset)
|
||||
{
|
||||
u_int value;
|
||||
|
||||
/*
|
||||
* Workaround PCI-X Rev A. hardware bug.
|
||||
* After a host read of SCB memory, the chip
|
||||
* may become confused into thinking prefetch
|
||||
* was required. This starts the discard timer
|
||||
* running and can cause an unexpected discard
|
||||
* timer interrupt. The work around is to read
|
||||
* a normal register prior to the exhaustion of
|
||||
* the discard timer. The mode pointer register
|
||||
* has no side effects and so serves well for
|
||||
* this purpose.
|
||||
*
|
||||
* Razor #528
|
||||
*/
|
||||
value = ahd_inb(ahd, offset);
|
||||
if ((ahd->bugs & AHD_PCIX_SCBRAM_RD_BUG) != 0)
|
||||
ahd_inb(ahd, MODE_PTR);
|
||||
return (value);
|
||||
}
|
||||
|
||||
u_int
|
||||
ahd_inw_scbram(struct ahd_softc *ahd, u_int offset)
|
||||
{
|
||||
return (ahd_inb_scbram(ahd, offset)
|
||||
| (ahd_inb_scbram(ahd, offset+1) << 8));
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
ahd_inl_scbram(struct ahd_softc *ahd, u_int offset)
|
||||
{
|
||||
return (ahd_inw_scbram(ahd, offset)
|
||||
| (ahd_inw_scbram(ahd, offset+2) << 16));
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
ahd_inq_scbram(struct ahd_softc *ahd, u_int offset)
|
||||
{
|
||||
return (ahd_inl_scbram(ahd, offset)
|
||||
| ((uint64_t)ahd_inl_scbram(ahd, offset+4)) << 32);
|
||||
}
|
||||
|
||||
struct scb *
|
||||
ahd_lookup_scb(struct ahd_softc *ahd, u_int tag)
|
||||
{
|
||||
struct scb* scb;
|
||||
|
||||
if (tag >= AHD_SCB_MAX)
|
||||
return (NULL);
|
||||
scb = ahd->scb_data.scbindex[tag];
|
||||
if (scb != NULL)
|
||||
ahd_sync_scb(ahd, scb,
|
||||
BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
|
||||
return (scb);
|
||||
}
|
||||
|
||||
static void
|
||||
ahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb)
|
||||
{
|
||||
struct hardware_scb *q_hscb;
|
||||
struct map_node *q_hscb_map;
|
||||
uint32_t saved_hscb_busaddr;
|
||||
|
||||
/*
|
||||
* Our queuing method is a bit tricky. The card
|
||||
* knows in advance which HSCB (by address) to download,
|
||||
* and we can't disappoint it. To achieve this, the next
|
||||
* HSCB to download is saved off in ahd->next_queued_hscb.
|
||||
* When we are called to queue "an arbitrary scb",
|
||||
* we copy the contents of the incoming HSCB to the one
|
||||
* the sequencer knows about, swap HSCB pointers and
|
||||
* finally assign the SCB to the tag indexed location
|
||||
* in the scb_array. This makes sure that we can still
|
||||
* locate the correct SCB by SCB_TAG.
|
||||
*/
|
||||
q_hscb = ahd->next_queued_hscb;
|
||||
q_hscb_map = ahd->next_queued_hscb_map;
|
||||
saved_hscb_busaddr = q_hscb->hscb_busaddr;
|
||||
memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb));
|
||||
q_hscb->hscb_busaddr = saved_hscb_busaddr;
|
||||
q_hscb->next_hscb_busaddr = scb->hscb->hscb_busaddr;
|
||||
|
||||
/* Now swap HSCB pointers. */
|
||||
ahd->next_queued_hscb = scb->hscb;
|
||||
ahd->next_queued_hscb_map = scb->hscb_map;
|
||||
scb->hscb = q_hscb;
|
||||
scb->hscb_map = q_hscb_map;
|
||||
|
||||
/* Now define the mapping from tag to SCB in the scbindex */
|
||||
ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tell the sequencer about a new transaction to execute.
|
||||
*/
|
||||
void
|
||||
ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb)
|
||||
{
|
||||
ahd_swap_with_next_hscb(ahd, scb);
|
||||
|
||||
if (SCBID_IS_NULL(SCB_GET_TAG(scb)))
|
||||
panic("Attempt to queue invalid SCB tag %x\n",
|
||||
SCB_GET_TAG(scb));
|
||||
|
||||
/*
|
||||
* Keep a history of SCBs we've downloaded in the qinfifo.
|
||||
*/
|
||||
ahd->qinfifo[AHD_QIN_WRAP(ahd->qinfifonext)] = SCB_GET_TAG(scb);
|
||||
ahd->qinfifonext++;
|
||||
|
||||
if (scb->sg_count != 0)
|
||||
ahd_setup_data_scb(ahd, scb);
|
||||
else
|
||||
ahd_setup_noxfer_scb(ahd, scb);
|
||||
ahd_setup_scb_common(ahd, scb);
|
||||
|
||||
/*
|
||||
* Make sure our data is consistent from the
|
||||
* perspective of the adapter.
|
||||
*/
|
||||
ahd_sync_scb(ahd, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
|
||||
|
||||
#ifdef AHD_DEBUG
|
||||
if ((ahd_debug & AHD_SHOW_QUEUE) != 0) {
|
||||
uint64_t host_dataptr;
|
||||
|
||||
host_dataptr = ahd_le64toh(scb->hscb->dataptr);
|
||||
printf("%s: Queueing SCB %d:0x%x bus addr 0x%x - 0x%x%x/0x%x\n",
|
||||
ahd_name(ahd),
|
||||
SCB_GET_TAG(scb), scb->hscb->scsiid,
|
||||
ahd_le32toh(scb->hscb->hscb_busaddr),
|
||||
(u_int)((host_dataptr >> 32) & 0xFFFFFFFF),
|
||||
(u_int)(host_dataptr & 0xFFFFFFFF),
|
||||
ahd_le32toh(scb->hscb->datacnt));
|
||||
}
|
||||
#endif
|
||||
/* Tell the adapter about the newly queued SCB */
|
||||
ahd_set_hnscb_qoff(ahd, ahd->qinfifonext);
|
||||
}
|
||||
|
||||
/************************** Interrupt Processing ******************************/
|
||||
static void
|
||||
ahd_sync_qoutfifo(struct ahd_softc *ahd, int op)
|
||||
{
|
||||
ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap,
|
||||
/*offset*/0,
|
||||
/*len*/AHD_SCB_MAX * sizeof(struct ahd_completion), op);
|
||||
}
|
||||
|
||||
static void
|
||||
ahd_sync_tqinfifo(struct ahd_softc *ahd, int op)
|
||||
{
|
||||
#ifdef AHD_TARGET_MODE
|
||||
if ((ahd->flags & AHD_TARGETROLE) != 0) {
|
||||
ahd_dmamap_sync(ahd, ahd->shared_data_dmat,
|
||||
ahd->shared_data_map.dmamap,
|
||||
ahd_targetcmd_offset(ahd, 0),
|
||||
sizeof(struct target_cmd) * AHD_TMODE_CMDS,
|
||||
op);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* See if the firmware has posted any completed commands
|
||||
* into our in-core command complete fifos.
|
||||
*/
|
||||
#define AHD_RUN_QOUTFIFO 0x1
|
||||
#define AHD_RUN_TQINFIFO 0x2
|
||||
static u_int
|
||||
ahd_check_cmdcmpltqueues(struct ahd_softc *ahd)
|
||||
{
|
||||
u_int retval;
|
||||
|
||||
retval = 0;
|
||||
ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap,
|
||||
/*offset*/ahd->qoutfifonext * sizeof(*ahd->qoutfifo),
|
||||
/*len*/sizeof(*ahd->qoutfifo), BUS_DMASYNC_POSTREAD);
|
||||
if (ahd->qoutfifo[ahd->qoutfifonext].valid_tag
|
||||
== ahd->qoutfifonext_valid_tag)
|
||||
retval |= AHD_RUN_QOUTFIFO;
|
||||
#ifdef AHD_TARGET_MODE
|
||||
if ((ahd->flags & AHD_TARGETROLE) != 0
|
||||
&& (ahd->flags & AHD_TQINFIFO_BLOCKED) == 0) {
|
||||
ahd_dmamap_sync(ahd, ahd->shared_data_dmat,
|
||||
ahd->shared_data_map.dmamap,
|
||||
ahd_targetcmd_offset(ahd, ahd->tqinfifofnext),
|
||||
/*len*/sizeof(struct target_cmd),
|
||||
BUS_DMASYNC_POSTREAD);
|
||||
if (ahd->targetcmds[ahd->tqinfifonext].cmd_valid != 0)
|
||||
retval |= AHD_RUN_TQINFIFO;
|
||||
}
|
||||
#endif
|
||||
return (retval);
|
||||
}
|
||||
|
||||
/*
|
||||
* Catch an interrupt from the adapter
|
||||
*/
|
||||
int
|
||||
ahd_intr(struct ahd_softc *ahd)
|
||||
{
|
||||
u_int intstat;
|
||||
|
||||
if ((ahd->pause & INTEN) == 0) {
|
||||
/*
|
||||
* Our interrupt is not enabled on the chip
|
||||
* and may be disabled for re-entrancy reasons,
|
||||
* so just return. This is likely just a shared
|
||||
* interrupt.
|
||||
*/
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Instead of directly reading the interrupt status register,
|
||||
* infer the cause of the interrupt by checking our in-core
|
||||
* completion queues. This avoids a costly PCI bus read in
|
||||
* most cases.
|
||||
*/
|
||||
if ((ahd->flags & AHD_ALL_INTERRUPTS) == 0
|
||||
&& (ahd_check_cmdcmpltqueues(ahd) != 0))
|
||||
intstat = CMDCMPLT;
|
||||
else
|
||||
intstat = ahd_inb(ahd, INTSTAT);
|
||||
|
||||
if ((intstat & INT_PEND) == 0)
|
||||
return (0);
|
||||
|
||||
if (intstat & CMDCMPLT) {
|
||||
ahd_outb(ahd, CLRINT, CLRCMDINT);
|
||||
|
||||
/*
|
||||
* Ensure that the chip sees that we've cleared
|
||||
* this interrupt before we walk the output fifo.
|
||||
* Otherwise, we may, due to posted bus writes,
|
||||
* clear the interrupt after we finish the scan,
|
||||
* and after the sequencer has added new entries
|
||||
* and asserted the interrupt again.
|
||||
*/
|
||||
if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) {
|
||||
if (ahd_is_paused(ahd)) {
|
||||
/*
|
||||
* Potentially lost SEQINT.
|
||||
* If SEQINTCODE is non-zero,
|
||||
* simulate the SEQINT.
|
||||
*/
|
||||
if (ahd_inb(ahd, SEQINTCODE) != NO_SEQINT)
|
||||
intstat |= SEQINT;
|
||||
}
|
||||
} else {
|
||||
ahd_flush_device_writes(ahd);
|
||||
}
|
||||
ahd_run_qoutfifo(ahd);
|
||||
ahd->cmdcmplt_counts[ahd->cmdcmplt_bucket]++;
|
||||
ahd->cmdcmplt_total++;
|
||||
#ifdef AHD_TARGET_MODE
|
||||
if ((ahd->flags & AHD_TARGETROLE) != 0)
|
||||
ahd_run_tqinfifo(ahd, /*paused*/FALSE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle statuses that may invalidate our cached
|
||||
* copy of INTSTAT separately.
|
||||
*/
|
||||
if (intstat == 0xFF && (ahd->features & AHD_REMOVABLE) != 0) {
|
||||
/* Hot eject. Do nothing */
|
||||
} else if (intstat & HWERRINT) {
|
||||
ahd_handle_hwerrint(ahd);
|
||||
} else if ((intstat & (PCIINT|SPLTINT)) != 0) {
|
||||
ahd->bus_intr(ahd);
|
||||
} else {
|
||||
|
||||
if ((intstat & SEQINT) != 0)
|
||||
ahd_handle_seqint(ahd, intstat);
|
||||
|
||||
if ((intstat & SCSIINT) != 0)
|
||||
ahd_handle_scsiint(ahd, intstat);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
/******************************** Private Inlines *****************************/
|
||||
static __inline void
|
||||
ahd_assert_atn(struct ahd_softc *ahd)
|
||||
{
|
||||
@ -280,7 +1046,7 @@ ahd_assert_atn(struct ahd_softc *ahd)
|
||||
* are currently in a packetized transfer. We could
|
||||
* just as easily be sending or receiving a message.
|
||||
*/
|
||||
static __inline int
|
||||
static int
|
||||
ahd_currently_packetized(struct ahd_softc *ahd)
|
||||
{
|
||||
ahd_mode_state saved_modes;
|
||||
@ -896,7 +1662,7 @@ ahd_run_data_fifo(struct ahd_softc *ahd, struct scb *scb)
|
||||
* a copy of the first byte (little endian) of the sgptr
|
||||
* hscb field.
|
||||
*/
|
||||
void
|
||||
static void
|
||||
ahd_run_qoutfifo(struct ahd_softc *ahd)
|
||||
{
|
||||
struct ahd_completion *completion;
|
||||
@ -935,7 +1701,7 @@ ahd_run_qoutfifo(struct ahd_softc *ahd)
|
||||
}
|
||||
|
||||
/************************* Interrupt Handling *********************************/
|
||||
void
|
||||
static void
|
||||
ahd_handle_hwerrint(struct ahd_softc *ahd)
|
||||
{
|
||||
/*
|
||||
@ -1009,7 +1775,7 @@ ahd_dump_sglist(struct scb *scb)
|
||||
}
|
||||
#endif /* AHD_DEBUG */
|
||||
|
||||
void
|
||||
static void
|
||||
ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
|
||||
{
|
||||
u_int seqintcode;
|
||||
@ -1621,7 +2387,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
|
||||
ahd_unpause(ahd);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
|
||||
{
|
||||
struct scb *scb;
|
||||
@ -3571,11 +4337,11 @@ ahd_print_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
|
||||
devinfo->target, devinfo->lun);
|
||||
}
|
||||
|
||||
static struct ahd_phase_table_entry*
|
||||
static const struct ahd_phase_table_entry*
|
||||
ahd_lookup_phase_entry(int phase)
|
||||
{
|
||||
struct ahd_phase_table_entry *entry;
|
||||
struct ahd_phase_table_entry *last_entry;
|
||||
const struct ahd_phase_table_entry *entry;
|
||||
const struct ahd_phase_table_entry *last_entry;
|
||||
|
||||
/*
|
||||
* num_phases doesn't include the default entry which
|
||||
@ -3941,7 +4707,7 @@ ahd_clear_msg_state(struct ahd_softc *ahd)
|
||||
*/
|
||||
static void
|
||||
ahd_handle_message_phase(struct ahd_softc *ahd)
|
||||
{
|
||||
{
|
||||
struct ahd_devinfo devinfo;
|
||||
u_int bus_phase;
|
||||
int end_session;
|
||||
@ -5983,8 +6749,7 @@ ahd_get_scb(struct ahd_softc *ahd, u_int col_idx)
|
||||
*/
|
||||
void
|
||||
ahd_free_scb(struct ahd_softc *ahd, struct scb *scb)
|
||||
{
|
||||
|
||||
{
|
||||
/* Clean up for the next user */
|
||||
scb->flags = SCB_FLAG_NONE;
|
||||
scb->hscb->control = 0;
|
||||
@ -6272,6 +7037,24 @@ static const char *termstat_strings[] = {
|
||||
"Not Configured"
|
||||
};
|
||||
|
||||
/***************************** Timer Facilities *******************************/
|
||||
#define ahd_timer_init init_timer
|
||||
#define ahd_timer_stop del_timer_sync
|
||||
typedef void ahd_linux_callback_t (u_long);
|
||||
|
||||
static void
|
||||
ahd_timer_reset(ahd_timer_t *timer, int usec, ahd_callback_t *func, void *arg)
|
||||
{
|
||||
struct ahd_softc *ahd;
|
||||
|
||||
ahd = (struct ahd_softc *)arg;
|
||||
del_timer(timer);
|
||||
timer->data = (u_long)arg;
|
||||
timer->expires = jiffies + (usec * HZ)/1000000;
|
||||
timer->function = (ahd_linux_callback_t*)func;
|
||||
add_timer(timer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Start the board, ready for normal operation
|
||||
*/
|
||||
@ -7370,7 +8153,7 @@ ahd_qinfifo_count(struct ahd_softc *ahd)
|
||||
+ ARRAY_SIZE(ahd->qinfifo) - wrap_qinpos);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
ahd_reset_cmds_pending(struct ahd_softc *ahd)
|
||||
{
|
||||
struct scb *scb;
|
||||
@ -8571,7 +9354,7 @@ ahd_loadseq(struct ahd_softc *ahd)
|
||||
struct cs cs_table[num_critical_sections];
|
||||
u_int begin_set[num_critical_sections];
|
||||
u_int end_set[num_critical_sections];
|
||||
struct patch *cur_patch;
|
||||
const struct patch *cur_patch;
|
||||
u_int cs_count;
|
||||
u_int cur_cs;
|
||||
u_int i;
|
||||
@ -8726,11 +9509,11 @@ ahd_loadseq(struct ahd_softc *ahd)
|
||||
}
|
||||
|
||||
static int
|
||||
ahd_check_patch(struct ahd_softc *ahd, struct patch **start_patch,
|
||||
ahd_check_patch(struct ahd_softc *ahd, const struct patch **start_patch,
|
||||
u_int start_instr, u_int *skip_addr)
|
||||
{
|
||||
struct patch *cur_patch;
|
||||
struct patch *last_patch;
|
||||
const struct patch *cur_patch;
|
||||
const struct patch *last_patch;
|
||||
u_int num_patches;
|
||||
|
||||
num_patches = ARRAY_SIZE(patches);
|
||||
@ -8764,7 +9547,7 @@ ahd_check_patch(struct ahd_softc *ahd, struct patch **start_patch,
|
||||
static u_int
|
||||
ahd_resolve_seqaddr(struct ahd_softc *ahd, u_int address)
|
||||
{
|
||||
struct patch *cur_patch;
|
||||
const struct patch *cur_patch;
|
||||
int address_offset;
|
||||
u_int skip_addr;
|
||||
u_int i;
|
||||
@ -8895,7 +9678,7 @@ ahd_probe_stack_size(struct ahd_softc *ahd)
|
||||
}
|
||||
|
||||
int
|
||||
ahd_print_register(ahd_reg_parse_entry_t *table, u_int num_entries,
|
||||
ahd_print_register(const ahd_reg_parse_entry_t *table, u_int num_entries,
|
||||
const char *name, u_int address, u_int value,
|
||||
u_int *cur_column, u_int wrap_point)
|
||||
{
|
||||
@ -9886,7 +10669,7 @@ ahd_update_scsiid(struct ahd_softc *ahd, u_int targid_mask)
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
ahd_run_tqinfifo(struct ahd_softc *ahd, int paused)
|
||||
{
|
||||
struct target_cmd *cmd;
|
||||
|
@ -63,18 +63,15 @@ static __inline ahd_mode_state ahd_build_mode_state(struct ahd_softc *ahd,
|
||||
static __inline void ahd_extract_mode_state(struct ahd_softc *ahd,
|
||||
ahd_mode_state state,
|
||||
ahd_mode *src, ahd_mode *dst);
|
||||
static __inline void ahd_set_modes(struct ahd_softc *ahd, ahd_mode src,
|
||||
ahd_mode dst);
|
||||
static __inline void ahd_update_modes(struct ahd_softc *ahd);
|
||||
static __inline void ahd_assert_modes(struct ahd_softc *ahd, ahd_mode srcmode,
|
||||
ahd_mode dstmode, const char *file,
|
||||
int line);
|
||||
static __inline ahd_mode_state ahd_save_modes(struct ahd_softc *ahd);
|
||||
static __inline void ahd_restore_modes(struct ahd_softc *ahd,
|
||||
ahd_mode_state state);
|
||||
static __inline int ahd_is_paused(struct ahd_softc *ahd);
|
||||
static __inline void ahd_pause(struct ahd_softc *ahd);
|
||||
static __inline void ahd_unpause(struct ahd_softc *ahd);
|
||||
|
||||
void ahd_set_modes(struct ahd_softc *ahd, ahd_mode src,
|
||||
ahd_mode dst);
|
||||
ahd_mode_state ahd_save_modes(struct ahd_softc *ahd);
|
||||
void ahd_restore_modes(struct ahd_softc *ahd,
|
||||
ahd_mode_state state);
|
||||
int ahd_is_paused(struct ahd_softc *ahd);
|
||||
void ahd_pause(struct ahd_softc *ahd);
|
||||
void ahd_unpause(struct ahd_softc *ahd);
|
||||
|
||||
static __inline void
|
||||
ahd_known_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst)
|
||||
@ -99,256 +96,16 @@ ahd_extract_mode_state(struct ahd_softc *ahd, ahd_mode_state state,
|
||||
*dst = (state & DST_MODE) >> DST_MODE_SHIFT;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_set_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst)
|
||||
{
|
||||
if (ahd->src_mode == src && ahd->dst_mode == dst)
|
||||
return;
|
||||
#ifdef AHD_DEBUG
|
||||
if (ahd->src_mode == AHD_MODE_UNKNOWN
|
||||
|| ahd->dst_mode == AHD_MODE_UNKNOWN)
|
||||
panic("Setting mode prior to saving it.\n");
|
||||
if ((ahd_debug & AHD_SHOW_MODEPTR) != 0)
|
||||
printf("%s: Setting mode 0x%x\n", ahd_name(ahd),
|
||||
ahd_build_mode_state(ahd, src, dst));
|
||||
#endif
|
||||
ahd_outb(ahd, MODE_PTR, ahd_build_mode_state(ahd, src, dst));
|
||||
ahd->src_mode = src;
|
||||
ahd->dst_mode = dst;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_update_modes(struct ahd_softc *ahd)
|
||||
{
|
||||
ahd_mode_state mode_ptr;
|
||||
ahd_mode src;
|
||||
ahd_mode dst;
|
||||
|
||||
mode_ptr = ahd_inb(ahd, MODE_PTR);
|
||||
#ifdef AHD_DEBUG
|
||||
if ((ahd_debug & AHD_SHOW_MODEPTR) != 0)
|
||||
printf("Reading mode 0x%x\n", mode_ptr);
|
||||
#endif
|
||||
ahd_extract_mode_state(ahd, mode_ptr, &src, &dst);
|
||||
ahd_known_modes(ahd, src, dst);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_assert_modes(struct ahd_softc *ahd, ahd_mode srcmode,
|
||||
ahd_mode dstmode, const char *file, int line)
|
||||
{
|
||||
#ifdef AHD_DEBUG
|
||||
if ((srcmode & AHD_MK_MSK(ahd->src_mode)) == 0
|
||||
|| (dstmode & AHD_MK_MSK(ahd->dst_mode)) == 0) {
|
||||
panic("%s:%s:%d: Mode assertion failed.\n",
|
||||
ahd_name(ahd), file, line);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static __inline ahd_mode_state
|
||||
ahd_save_modes(struct ahd_softc *ahd)
|
||||
{
|
||||
if (ahd->src_mode == AHD_MODE_UNKNOWN
|
||||
|| ahd->dst_mode == AHD_MODE_UNKNOWN)
|
||||
ahd_update_modes(ahd);
|
||||
|
||||
return (ahd_build_mode_state(ahd, ahd->src_mode, ahd->dst_mode));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_restore_modes(struct ahd_softc *ahd, ahd_mode_state state)
|
||||
{
|
||||
ahd_mode src;
|
||||
ahd_mode dst;
|
||||
|
||||
ahd_extract_mode_state(ahd, state, &src, &dst);
|
||||
ahd_set_modes(ahd, src, dst);
|
||||
}
|
||||
|
||||
#define AHD_ASSERT_MODES(ahd, source, dest) \
|
||||
ahd_assert_modes(ahd, source, dest, __FILE__, __LINE__);
|
||||
|
||||
/*
|
||||
* Determine whether the sequencer has halted code execution.
|
||||
* Returns non-zero status if the sequencer is stopped.
|
||||
*/
|
||||
static __inline int
|
||||
ahd_is_paused(struct ahd_softc *ahd)
|
||||
{
|
||||
return ((ahd_inb(ahd, HCNTRL) & PAUSE) != 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Request that the sequencer stop and wait, indefinitely, for it
|
||||
* to stop. The sequencer will only acknowledge that it is paused
|
||||
* once it has reached an instruction boundary and PAUSEDIS is
|
||||
* cleared in the SEQCTL register. The sequencer may use PAUSEDIS
|
||||
* for critical sections.
|
||||
*/
|
||||
static __inline void
|
||||
ahd_pause(struct ahd_softc *ahd)
|
||||
{
|
||||
ahd_outb(ahd, HCNTRL, ahd->pause);
|
||||
|
||||
/*
|
||||
* Since the sequencer can disable pausing in a critical section, we
|
||||
* must loop until it actually stops.
|
||||
*/
|
||||
while (ahd_is_paused(ahd) == 0)
|
||||
;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow the sequencer to continue program execution.
|
||||
* We check here to ensure that no additional interrupt
|
||||
* sources that would cause the sequencer to halt have been
|
||||
* asserted. If, for example, a SCSI bus reset is detected
|
||||
* while we are fielding a different, pausing, interrupt type,
|
||||
* we don't want to release the sequencer before going back
|
||||
* into our interrupt handler and dealing with this new
|
||||
* condition.
|
||||
*/
|
||||
static __inline void
|
||||
ahd_unpause(struct ahd_softc *ahd)
|
||||
{
|
||||
/*
|
||||
* Automatically restore our modes to those saved
|
||||
* prior to the first change of the mode.
|
||||
*/
|
||||
if (ahd->saved_src_mode != AHD_MODE_UNKNOWN
|
||||
&& ahd->saved_dst_mode != AHD_MODE_UNKNOWN) {
|
||||
if ((ahd->flags & AHD_UPDATE_PEND_CMDS) != 0)
|
||||
ahd_reset_cmds_pending(ahd);
|
||||
ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode);
|
||||
}
|
||||
|
||||
if ((ahd_inb(ahd, INTSTAT) & ~CMDCMPLT) == 0)
|
||||
ahd_outb(ahd, HCNTRL, ahd->unpause);
|
||||
|
||||
ahd_known_modes(ahd, AHD_MODE_UNKNOWN, AHD_MODE_UNKNOWN);
|
||||
}
|
||||
|
||||
/*********************** Scatter Gather List Handling *************************/
|
||||
static __inline void *ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb,
|
||||
void *sgptr, dma_addr_t addr,
|
||||
bus_size_t len, int last);
|
||||
static __inline void ahd_setup_scb_common(struct ahd_softc *ahd,
|
||||
struct scb *scb);
|
||||
static __inline void ahd_setup_data_scb(struct ahd_softc *ahd,
|
||||
struct scb *scb);
|
||||
static __inline void ahd_setup_noxfer_scb(struct ahd_softc *ahd,
|
||||
struct scb *scb);
|
||||
|
||||
static __inline void *
|
||||
ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb,
|
||||
void *sgptr, dma_addr_t addr, bus_size_t len, int last)
|
||||
{
|
||||
scb->sg_count++;
|
||||
if (sizeof(dma_addr_t) > 4
|
||||
&& (ahd->flags & AHD_64BIT_ADDRESSING) != 0) {
|
||||
struct ahd_dma64_seg *sg;
|
||||
|
||||
sg = (struct ahd_dma64_seg *)sgptr;
|
||||
sg->addr = ahd_htole64(addr);
|
||||
sg->len = ahd_htole32(len | (last ? AHD_DMA_LAST_SEG : 0));
|
||||
return (sg + 1);
|
||||
} else {
|
||||
struct ahd_dma_seg *sg;
|
||||
|
||||
sg = (struct ahd_dma_seg *)sgptr;
|
||||
sg->addr = ahd_htole32(addr & 0xFFFFFFFF);
|
||||
sg->len = ahd_htole32(len | ((addr >> 8) & 0x7F000000)
|
||||
| (last ? AHD_DMA_LAST_SEG : 0));
|
||||
return (sg + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_setup_scb_common(struct ahd_softc *ahd, struct scb *scb)
|
||||
{
|
||||
/* XXX Handle target mode SCBs. */
|
||||
scb->crc_retry_count = 0;
|
||||
if ((scb->flags & SCB_PACKETIZED) != 0) {
|
||||
/* XXX what about ACA?? It is type 4, but TAG_TYPE == 0x3. */
|
||||
scb->hscb->task_attribute = scb->hscb->control & SCB_TAG_TYPE;
|
||||
} else {
|
||||
if (ahd_get_transfer_length(scb) & 0x01)
|
||||
scb->hscb->task_attribute = SCB_XFERLEN_ODD;
|
||||
else
|
||||
scb->hscb->task_attribute = 0;
|
||||
}
|
||||
|
||||
if (scb->hscb->cdb_len <= MAX_CDB_LEN_WITH_SENSE_ADDR
|
||||
|| (scb->hscb->cdb_len & SCB_CDB_LEN_PTR) != 0)
|
||||
scb->hscb->shared_data.idata.cdb_plus_saddr.sense_addr =
|
||||
ahd_htole32(scb->sense_busaddr);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_setup_data_scb(struct ahd_softc *ahd, struct scb *scb)
|
||||
{
|
||||
/*
|
||||
* Copy the first SG into the "current" data ponter area.
|
||||
*/
|
||||
if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) {
|
||||
struct ahd_dma64_seg *sg;
|
||||
|
||||
sg = (struct ahd_dma64_seg *)scb->sg_list;
|
||||
scb->hscb->dataptr = sg->addr;
|
||||
scb->hscb->datacnt = sg->len;
|
||||
} else {
|
||||
struct ahd_dma_seg *sg;
|
||||
uint32_t *dataptr_words;
|
||||
|
||||
sg = (struct ahd_dma_seg *)scb->sg_list;
|
||||
dataptr_words = (uint32_t*)&scb->hscb->dataptr;
|
||||
dataptr_words[0] = sg->addr;
|
||||
dataptr_words[1] = 0;
|
||||
if ((ahd->flags & AHD_39BIT_ADDRESSING) != 0) {
|
||||
uint64_t high_addr;
|
||||
|
||||
high_addr = ahd_le32toh(sg->len) & 0x7F000000;
|
||||
scb->hscb->dataptr |= ahd_htole64(high_addr << 8);
|
||||
}
|
||||
scb->hscb->datacnt = sg->len;
|
||||
}
|
||||
/*
|
||||
* Note where to find the SG entries in bus space.
|
||||
* We also set the full residual flag which the
|
||||
* sequencer will clear as soon as a data transfer
|
||||
* occurs.
|
||||
*/
|
||||
scb->hscb->sgptr = ahd_htole32(scb->sg_list_busaddr|SG_FULL_RESID);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_setup_noxfer_scb(struct ahd_softc *ahd, struct scb *scb)
|
||||
{
|
||||
scb->hscb->sgptr = ahd_htole32(SG_LIST_NULL);
|
||||
scb->hscb->dataptr = 0;
|
||||
scb->hscb->datacnt = 0;
|
||||
}
|
||||
void *ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb,
|
||||
void *sgptr, dma_addr_t addr,
|
||||
bus_size_t len, int last);
|
||||
|
||||
/************************** Memory mapping routines ***************************/
|
||||
static __inline size_t ahd_sg_size(struct ahd_softc *ahd);
|
||||
static __inline void *
|
||||
ahd_sg_bus_to_virt(struct ahd_softc *ahd,
|
||||
struct scb *scb,
|
||||
uint32_t sg_busaddr);
|
||||
static __inline uint32_t
|
||||
ahd_sg_virt_to_bus(struct ahd_softc *ahd,
|
||||
struct scb *scb,
|
||||
void *sg);
|
||||
static __inline void ahd_sync_scb(struct ahd_softc *ahd,
|
||||
struct scb *scb, int op);
|
||||
static __inline void ahd_sync_sglist(struct ahd_softc *ahd,
|
||||
struct scb *scb, int op);
|
||||
static __inline void ahd_sync_sense(struct ahd_softc *ahd,
|
||||
struct scb *scb, int op);
|
||||
static __inline uint32_t
|
||||
ahd_targetcmd_offset(struct ahd_softc *ahd,
|
||||
u_int index);
|
||||
|
||||
void ahd_sync_sglist(struct ahd_softc *ahd,
|
||||
struct scb *scb, int op);
|
||||
|
||||
static __inline size_t
|
||||
ahd_sg_size(struct ahd_softc *ahd)
|
||||
@ -358,104 +115,32 @@ ahd_sg_size(struct ahd_softc *ahd)
|
||||
return (sizeof(struct ahd_dma_seg));
|
||||
}
|
||||
|
||||
static __inline void *
|
||||
ahd_sg_bus_to_virt(struct ahd_softc *ahd, struct scb *scb, uint32_t sg_busaddr)
|
||||
{
|
||||
dma_addr_t sg_offset;
|
||||
|
||||
/* sg_list_phys points to entry 1, not 0 */
|
||||
sg_offset = sg_busaddr - (scb->sg_list_busaddr - ahd_sg_size(ahd));
|
||||
return ((uint8_t *)scb->sg_list + sg_offset);
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
ahd_sg_virt_to_bus(struct ahd_softc *ahd, struct scb *scb, void *sg)
|
||||
{
|
||||
dma_addr_t sg_offset;
|
||||
|
||||
/* sg_list_phys points to entry 1, not 0 */
|
||||
sg_offset = ((uint8_t *)sg - (uint8_t *)scb->sg_list)
|
||||
- ahd_sg_size(ahd);
|
||||
|
||||
return (scb->sg_list_busaddr + sg_offset);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_sync_scb(struct ahd_softc *ahd, struct scb *scb, int op)
|
||||
{
|
||||
ahd_dmamap_sync(ahd, ahd->scb_data.hscb_dmat,
|
||||
scb->hscb_map->dmamap,
|
||||
/*offset*/(uint8_t*)scb->hscb - scb->hscb_map->vaddr,
|
||||
/*len*/sizeof(*scb->hscb), op);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_sync_sglist(struct ahd_softc *ahd, struct scb *scb, int op)
|
||||
{
|
||||
if (scb->sg_count == 0)
|
||||
return;
|
||||
|
||||
ahd_dmamap_sync(ahd, ahd->scb_data.sg_dmat,
|
||||
scb->sg_map->dmamap,
|
||||
/*offset*/scb->sg_list_busaddr - ahd_sg_size(ahd),
|
||||
/*len*/ahd_sg_size(ahd) * scb->sg_count, op);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_sync_sense(struct ahd_softc *ahd, struct scb *scb, int op)
|
||||
{
|
||||
ahd_dmamap_sync(ahd, ahd->scb_data.sense_dmat,
|
||||
scb->sense_map->dmamap,
|
||||
/*offset*/scb->sense_busaddr,
|
||||
/*len*/AHD_SENSE_BUFSIZE, op);
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
ahd_targetcmd_offset(struct ahd_softc *ahd, u_int index)
|
||||
{
|
||||
return (((uint8_t *)&ahd->targetcmds[index])
|
||||
- (uint8_t *)ahd->qoutfifo);
|
||||
}
|
||||
|
||||
/*********************** Miscellaneous Support Functions ***********************/
|
||||
static __inline struct ahd_initiator_tinfo *
|
||||
ahd_fetch_transinfo(struct ahd_softc *ahd,
|
||||
char channel, u_int our_id,
|
||||
u_int remote_id,
|
||||
struct ahd_tmode_tstate **tstate);
|
||||
static __inline uint16_t
|
||||
ahd_inw(struct ahd_softc *ahd, u_int port);
|
||||
static __inline void ahd_outw(struct ahd_softc *ahd, u_int port,
|
||||
u_int value);
|
||||
static __inline uint32_t
|
||||
ahd_inl(struct ahd_softc *ahd, u_int port);
|
||||
static __inline void ahd_outl(struct ahd_softc *ahd, u_int port,
|
||||
uint32_t value);
|
||||
static __inline uint64_t
|
||||
ahd_inq(struct ahd_softc *ahd, u_int port);
|
||||
static __inline void ahd_outq(struct ahd_softc *ahd, u_int port,
|
||||
uint64_t value);
|
||||
static __inline u_int ahd_get_scbptr(struct ahd_softc *ahd);
|
||||
static __inline void ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr);
|
||||
static __inline u_int ahd_get_hnscb_qoff(struct ahd_softc *ahd);
|
||||
static __inline void ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value);
|
||||
static __inline u_int ahd_get_hescb_qoff(struct ahd_softc *ahd);
|
||||
static __inline void ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value);
|
||||
static __inline u_int ahd_get_snscb_qoff(struct ahd_softc *ahd);
|
||||
static __inline void ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value);
|
||||
static __inline u_int ahd_get_sescb_qoff(struct ahd_softc *ahd);
|
||||
static __inline void ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value);
|
||||
static __inline u_int ahd_get_sdscb_qoff(struct ahd_softc *ahd);
|
||||
static __inline void ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value);
|
||||
static __inline u_int ahd_inb_scbram(struct ahd_softc *ahd, u_int offset);
|
||||
static __inline u_int ahd_inw_scbram(struct ahd_softc *ahd, u_int offset);
|
||||
static __inline uint32_t
|
||||
ahd_inl_scbram(struct ahd_softc *ahd, u_int offset);
|
||||
static __inline uint64_t
|
||||
ahd_inq_scbram(struct ahd_softc *ahd, u_int offset);
|
||||
static __inline void ahd_swap_with_next_hscb(struct ahd_softc *ahd,
|
||||
struct scb *scb);
|
||||
static __inline void ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb);
|
||||
struct ahd_initiator_tinfo *
|
||||
ahd_fetch_transinfo(struct ahd_softc *ahd,
|
||||
char channel, u_int our_id,
|
||||
u_int remote_id,
|
||||
struct ahd_tmode_tstate **tstate);
|
||||
uint16_t
|
||||
ahd_inw(struct ahd_softc *ahd, u_int port);
|
||||
void ahd_outw(struct ahd_softc *ahd, u_int port,
|
||||
u_int value);
|
||||
uint32_t
|
||||
ahd_inl(struct ahd_softc *ahd, u_int port);
|
||||
void ahd_outl(struct ahd_softc *ahd, u_int port,
|
||||
uint32_t value);
|
||||
uint64_t
|
||||
ahd_inq(struct ahd_softc *ahd, u_int port);
|
||||
void ahd_outq(struct ahd_softc *ahd, u_int port,
|
||||
uint64_t value);
|
||||
u_int ahd_get_scbptr(struct ahd_softc *ahd);
|
||||
void ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr);
|
||||
u_int ahd_inb_scbram(struct ahd_softc *ahd, u_int offset);
|
||||
u_int ahd_inw_scbram(struct ahd_softc *ahd, u_int offset);
|
||||
struct scb *
|
||||
ahd_lookup_scb(struct ahd_softc *ahd, u_int tag);
|
||||
void ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb);
|
||||
|
||||
static __inline uint8_t *
|
||||
ahd_get_sense_buf(struct ahd_softc *ahd,
|
||||
struct scb *scb);
|
||||
@ -463,25 +148,7 @@ static __inline uint32_t
|
||||
ahd_get_sense_bufaddr(struct ahd_softc *ahd,
|
||||
struct scb *scb);
|
||||
|
||||
/*
|
||||
* Return pointers to the transfer negotiation information
|
||||
* for the specified our_id/remote_id pair.
|
||||
*/
|
||||
static __inline struct ahd_initiator_tinfo *
|
||||
ahd_fetch_transinfo(struct ahd_softc *ahd, char channel, u_int our_id,
|
||||
u_int remote_id, struct ahd_tmode_tstate **tstate)
|
||||
{
|
||||
/*
|
||||
* Transfer data structures are stored from the perspective
|
||||
* of the target role. Since the parameters for a connection
|
||||
* in the initiator role to a given target are the same as
|
||||
* when the roles are reversed, we pretend we are the target.
|
||||
*/
|
||||
if (channel == 'B')
|
||||
our_id += 8;
|
||||
*tstate = ahd->enabled_targets[our_id];
|
||||
return (&(*tstate)->transinfo[remote_id]);
|
||||
}
|
||||
#if 0 /* unused */
|
||||
|
||||
#define AHD_COPY_COL_IDX(dst, src) \
|
||||
do { \
|
||||
@ -489,304 +156,7 @@ do { \
|
||||
dst->hscb->lun = src->hscb->lun; \
|
||||
} while (0)
|
||||
|
||||
static __inline uint16_t
|
||||
ahd_inw(struct ahd_softc *ahd, u_int port)
|
||||
{
|
||||
/*
|
||||
* Read high byte first as some registers increment
|
||||
* or have other side effects when the low byte is
|
||||
* read.
|
||||
*/
|
||||
uint16_t r = ahd_inb(ahd, port+1) << 8;
|
||||
return r | ahd_inb(ahd, port);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_outw(struct ahd_softc *ahd, u_int port, u_int value)
|
||||
{
|
||||
/*
|
||||
* Write low byte first to accomodate registers
|
||||
* such as PRGMCNT where the order maters.
|
||||
*/
|
||||
ahd_outb(ahd, port, value & 0xFF);
|
||||
ahd_outb(ahd, port+1, (value >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
ahd_inl(struct ahd_softc *ahd, u_int port)
|
||||
{
|
||||
return ((ahd_inb(ahd, port))
|
||||
| (ahd_inb(ahd, port+1) << 8)
|
||||
| (ahd_inb(ahd, port+2) << 16)
|
||||
| (ahd_inb(ahd, port+3) << 24));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_outl(struct ahd_softc *ahd, u_int port, uint32_t value)
|
||||
{
|
||||
ahd_outb(ahd, port, (value) & 0xFF);
|
||||
ahd_outb(ahd, port+1, ((value) >> 8) & 0xFF);
|
||||
ahd_outb(ahd, port+2, ((value) >> 16) & 0xFF);
|
||||
ahd_outb(ahd, port+3, ((value) >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
static __inline uint64_t
|
||||
ahd_inq(struct ahd_softc *ahd, u_int port)
|
||||
{
|
||||
return ((ahd_inb(ahd, port))
|
||||
| (ahd_inb(ahd, port+1) << 8)
|
||||
| (ahd_inb(ahd, port+2) << 16)
|
||||
| (ahd_inb(ahd, port+3) << 24)
|
||||
| (((uint64_t)ahd_inb(ahd, port+4)) << 32)
|
||||
| (((uint64_t)ahd_inb(ahd, port+5)) << 40)
|
||||
| (((uint64_t)ahd_inb(ahd, port+6)) << 48)
|
||||
| (((uint64_t)ahd_inb(ahd, port+7)) << 56));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_outq(struct ahd_softc *ahd, u_int port, uint64_t value)
|
||||
{
|
||||
ahd_outb(ahd, port, value & 0xFF);
|
||||
ahd_outb(ahd, port+1, (value >> 8) & 0xFF);
|
||||
ahd_outb(ahd, port+2, (value >> 16) & 0xFF);
|
||||
ahd_outb(ahd, port+3, (value >> 24) & 0xFF);
|
||||
ahd_outb(ahd, port+4, (value >> 32) & 0xFF);
|
||||
ahd_outb(ahd, port+5, (value >> 40) & 0xFF);
|
||||
ahd_outb(ahd, port+6, (value >> 48) & 0xFF);
|
||||
ahd_outb(ahd, port+7, (value >> 56) & 0xFF);
|
||||
}
|
||||
|
||||
static __inline u_int
|
||||
ahd_get_scbptr(struct ahd_softc *ahd)
|
||||
{
|
||||
AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK),
|
||||
~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK));
|
||||
return (ahd_inb(ahd, SCBPTR) | (ahd_inb(ahd, SCBPTR + 1) << 8));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr)
|
||||
{
|
||||
AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK),
|
||||
~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK));
|
||||
ahd_outb(ahd, SCBPTR, scbptr & 0xFF);
|
||||
ahd_outb(ahd, SCBPTR+1, (scbptr >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
static __inline u_int
|
||||
ahd_get_hnscb_qoff(struct ahd_softc *ahd)
|
||||
{
|
||||
return (ahd_inw_atomic(ahd, HNSCB_QOFF));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value)
|
||||
{
|
||||
ahd_outw_atomic(ahd, HNSCB_QOFF, value);
|
||||
}
|
||||
|
||||
static __inline u_int
|
||||
ahd_get_hescb_qoff(struct ahd_softc *ahd)
|
||||
{
|
||||
return (ahd_inb(ahd, HESCB_QOFF));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value)
|
||||
{
|
||||
ahd_outb(ahd, HESCB_QOFF, value);
|
||||
}
|
||||
|
||||
static __inline u_int
|
||||
ahd_get_snscb_qoff(struct ahd_softc *ahd)
|
||||
{
|
||||
u_int oldvalue;
|
||||
|
||||
AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
|
||||
oldvalue = ahd_inw(ahd, SNSCB_QOFF);
|
||||
ahd_outw(ahd, SNSCB_QOFF, oldvalue);
|
||||
return (oldvalue);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value)
|
||||
{
|
||||
AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
|
||||
ahd_outw(ahd, SNSCB_QOFF, value);
|
||||
}
|
||||
|
||||
static __inline u_int
|
||||
ahd_get_sescb_qoff(struct ahd_softc *ahd)
|
||||
{
|
||||
AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
|
||||
return (ahd_inb(ahd, SESCB_QOFF));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value)
|
||||
{
|
||||
AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
|
||||
ahd_outb(ahd, SESCB_QOFF, value);
|
||||
}
|
||||
|
||||
static __inline u_int
|
||||
ahd_get_sdscb_qoff(struct ahd_softc *ahd)
|
||||
{
|
||||
AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
|
||||
return (ahd_inb(ahd, SDSCB_QOFF) | (ahd_inb(ahd, SDSCB_QOFF + 1) << 8));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value)
|
||||
{
|
||||
AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
|
||||
ahd_outb(ahd, SDSCB_QOFF, value & 0xFF);
|
||||
ahd_outb(ahd, SDSCB_QOFF+1, (value >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
static __inline u_int
|
||||
ahd_inb_scbram(struct ahd_softc *ahd, u_int offset)
|
||||
{
|
||||
u_int value;
|
||||
|
||||
/*
|
||||
* Workaround PCI-X Rev A. hardware bug.
|
||||
* After a host read of SCB memory, the chip
|
||||
* may become confused into thinking prefetch
|
||||
* was required. This starts the discard timer
|
||||
* running and can cause an unexpected discard
|
||||
* timer interrupt. The work around is to read
|
||||
* a normal register prior to the exhaustion of
|
||||
* the discard timer. The mode pointer register
|
||||
* has no side effects and so serves well for
|
||||
* this purpose.
|
||||
*
|
||||
* Razor #528
|
||||
*/
|
||||
value = ahd_inb(ahd, offset);
|
||||
if ((ahd->bugs & AHD_PCIX_SCBRAM_RD_BUG) != 0)
|
||||
ahd_inb(ahd, MODE_PTR);
|
||||
return (value);
|
||||
}
|
||||
|
||||
static __inline u_int
|
||||
ahd_inw_scbram(struct ahd_softc *ahd, u_int offset)
|
||||
{
|
||||
return (ahd_inb_scbram(ahd, offset)
|
||||
| (ahd_inb_scbram(ahd, offset+1) << 8));
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
ahd_inl_scbram(struct ahd_softc *ahd, u_int offset)
|
||||
{
|
||||
return (ahd_inw_scbram(ahd, offset)
|
||||
| (ahd_inw_scbram(ahd, offset+2) << 16));
|
||||
}
|
||||
|
||||
static __inline uint64_t
|
||||
ahd_inq_scbram(struct ahd_softc *ahd, u_int offset)
|
||||
{
|
||||
return (ahd_inl_scbram(ahd, offset)
|
||||
| ((uint64_t)ahd_inl_scbram(ahd, offset+4)) << 32);
|
||||
}
|
||||
|
||||
static __inline struct scb *
|
||||
ahd_lookup_scb(struct ahd_softc *ahd, u_int tag)
|
||||
{
|
||||
struct scb* scb;
|
||||
|
||||
if (tag >= AHD_SCB_MAX)
|
||||
return (NULL);
|
||||
scb = ahd->scb_data.scbindex[tag];
|
||||
if (scb != NULL)
|
||||
ahd_sync_scb(ahd, scb,
|
||||
BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
|
||||
return (scb);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb)
|
||||
{
|
||||
struct hardware_scb *q_hscb;
|
||||
struct map_node *q_hscb_map;
|
||||
uint32_t saved_hscb_busaddr;
|
||||
|
||||
/*
|
||||
* Our queuing method is a bit tricky. The card
|
||||
* knows in advance which HSCB (by address) to download,
|
||||
* and we can't disappoint it. To achieve this, the next
|
||||
* HSCB to download is saved off in ahd->next_queued_hscb.
|
||||
* When we are called to queue "an arbitrary scb",
|
||||
* we copy the contents of the incoming HSCB to the one
|
||||
* the sequencer knows about, swap HSCB pointers and
|
||||
* finally assign the SCB to the tag indexed location
|
||||
* in the scb_array. This makes sure that we can still
|
||||
* locate the correct SCB by SCB_TAG.
|
||||
*/
|
||||
q_hscb = ahd->next_queued_hscb;
|
||||
q_hscb_map = ahd->next_queued_hscb_map;
|
||||
saved_hscb_busaddr = q_hscb->hscb_busaddr;
|
||||
memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb));
|
||||
q_hscb->hscb_busaddr = saved_hscb_busaddr;
|
||||
q_hscb->next_hscb_busaddr = scb->hscb->hscb_busaddr;
|
||||
|
||||
/* Now swap HSCB pointers. */
|
||||
ahd->next_queued_hscb = scb->hscb;
|
||||
ahd->next_queued_hscb_map = scb->hscb_map;
|
||||
scb->hscb = q_hscb;
|
||||
scb->hscb_map = q_hscb_map;
|
||||
|
||||
/* Now define the mapping from tag to SCB in the scbindex */
|
||||
ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tell the sequencer about a new transaction to execute.
|
||||
*/
|
||||
static __inline void
|
||||
ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb)
|
||||
{
|
||||
ahd_swap_with_next_hscb(ahd, scb);
|
||||
|
||||
if (SCBID_IS_NULL(SCB_GET_TAG(scb)))
|
||||
panic("Attempt to queue invalid SCB tag %x\n",
|
||||
SCB_GET_TAG(scb));
|
||||
|
||||
/*
|
||||
* Keep a history of SCBs we've downloaded in the qinfifo.
|
||||
*/
|
||||
ahd->qinfifo[AHD_QIN_WRAP(ahd->qinfifonext)] = SCB_GET_TAG(scb);
|
||||
ahd->qinfifonext++;
|
||||
|
||||
if (scb->sg_count != 0)
|
||||
ahd_setup_data_scb(ahd, scb);
|
||||
else
|
||||
ahd_setup_noxfer_scb(ahd, scb);
|
||||
ahd_setup_scb_common(ahd, scb);
|
||||
|
||||
/*
|
||||
* Make sure our data is consistent from the
|
||||
* perspective of the adapter.
|
||||
*/
|
||||
ahd_sync_scb(ahd, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
|
||||
|
||||
#ifdef AHD_DEBUG
|
||||
if ((ahd_debug & AHD_SHOW_QUEUE) != 0) {
|
||||
uint64_t host_dataptr;
|
||||
|
||||
host_dataptr = ahd_le64toh(scb->hscb->dataptr);
|
||||
printf("%s: Queueing SCB %d:0x%x bus addr 0x%x - 0x%x%x/0x%x\n",
|
||||
ahd_name(ahd),
|
||||
SCB_GET_TAG(scb), scb->hscb->scsiid,
|
||||
ahd_le32toh(scb->hscb->hscb_busaddr),
|
||||
(u_int)((host_dataptr >> 32) & 0xFFFFFFFF),
|
||||
(u_int)(host_dataptr & 0xFFFFFFFF),
|
||||
ahd_le32toh(scb->hscb->datacnt));
|
||||
}
|
||||
#endif
|
||||
/* Tell the adapter about the newly queued SCB */
|
||||
ahd_set_hnscb_qoff(ahd, ahd->qinfifonext);
|
||||
}
|
||||
|
||||
static __inline uint8_t *
|
||||
ahd_get_sense_buf(struct ahd_softc *ahd, struct scb *scb)
|
||||
@ -801,151 +171,6 @@ ahd_get_sense_bufaddr(struct ahd_softc *ahd, struct scb *scb)
|
||||
}
|
||||
|
||||
/************************** Interrupt Processing ******************************/
|
||||
static __inline void ahd_sync_qoutfifo(struct ahd_softc *ahd, int op);
|
||||
static __inline void ahd_sync_tqinfifo(struct ahd_softc *ahd, int op);
|
||||
static __inline u_int ahd_check_cmdcmpltqueues(struct ahd_softc *ahd);
|
||||
static __inline int ahd_intr(struct ahd_softc *ahd);
|
||||
|
||||
static __inline void
|
||||
ahd_sync_qoutfifo(struct ahd_softc *ahd, int op)
|
||||
{
|
||||
ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap,
|
||||
/*offset*/0,
|
||||
/*len*/AHD_SCB_MAX * sizeof(struct ahd_completion), op);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_sync_tqinfifo(struct ahd_softc *ahd, int op)
|
||||
{
|
||||
#ifdef AHD_TARGET_MODE
|
||||
if ((ahd->flags & AHD_TARGETROLE) != 0) {
|
||||
ahd_dmamap_sync(ahd, ahd->shared_data_dmat,
|
||||
ahd->shared_data_map.dmamap,
|
||||
ahd_targetcmd_offset(ahd, 0),
|
||||
sizeof(struct target_cmd) * AHD_TMODE_CMDS,
|
||||
op);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* See if the firmware has posted any completed commands
|
||||
* into our in-core command complete fifos.
|
||||
*/
|
||||
#define AHD_RUN_QOUTFIFO 0x1
|
||||
#define AHD_RUN_TQINFIFO 0x2
|
||||
static __inline u_int
|
||||
ahd_check_cmdcmpltqueues(struct ahd_softc *ahd)
|
||||
{
|
||||
u_int retval;
|
||||
|
||||
retval = 0;
|
||||
ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap,
|
||||
/*offset*/ahd->qoutfifonext * sizeof(*ahd->qoutfifo),
|
||||
/*len*/sizeof(*ahd->qoutfifo), BUS_DMASYNC_POSTREAD);
|
||||
if (ahd->qoutfifo[ahd->qoutfifonext].valid_tag
|
||||
== ahd->qoutfifonext_valid_tag)
|
||||
retval |= AHD_RUN_QOUTFIFO;
|
||||
#ifdef AHD_TARGET_MODE
|
||||
if ((ahd->flags & AHD_TARGETROLE) != 0
|
||||
&& (ahd->flags & AHD_TQINFIFO_BLOCKED) == 0) {
|
||||
ahd_dmamap_sync(ahd, ahd->shared_data_dmat,
|
||||
ahd->shared_data_map.dmamap,
|
||||
ahd_targetcmd_offset(ahd, ahd->tqinfifofnext),
|
||||
/*len*/sizeof(struct target_cmd),
|
||||
BUS_DMASYNC_POSTREAD);
|
||||
if (ahd->targetcmds[ahd->tqinfifonext].cmd_valid != 0)
|
||||
retval |= AHD_RUN_TQINFIFO;
|
||||
}
|
||||
#endif
|
||||
return (retval);
|
||||
}
|
||||
|
||||
/*
|
||||
* Catch an interrupt from the adapter
|
||||
*/
|
||||
static __inline int
|
||||
ahd_intr(struct ahd_softc *ahd)
|
||||
{
|
||||
u_int intstat;
|
||||
|
||||
if ((ahd->pause & INTEN) == 0) {
|
||||
/*
|
||||
* Our interrupt is not enabled on the chip
|
||||
* and may be disabled for re-entrancy reasons,
|
||||
* so just return. This is likely just a shared
|
||||
* interrupt.
|
||||
*/
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Instead of directly reading the interrupt status register,
|
||||
* infer the cause of the interrupt by checking our in-core
|
||||
* completion queues. This avoids a costly PCI bus read in
|
||||
* most cases.
|
||||
*/
|
||||
if ((ahd->flags & AHD_ALL_INTERRUPTS) == 0
|
||||
&& (ahd_check_cmdcmpltqueues(ahd) != 0))
|
||||
intstat = CMDCMPLT;
|
||||
else
|
||||
intstat = ahd_inb(ahd, INTSTAT);
|
||||
|
||||
if ((intstat & INT_PEND) == 0)
|
||||
return (0);
|
||||
|
||||
if (intstat & CMDCMPLT) {
|
||||
ahd_outb(ahd, CLRINT, CLRCMDINT);
|
||||
|
||||
/*
|
||||
* Ensure that the chip sees that we've cleared
|
||||
* this interrupt before we walk the output fifo.
|
||||
* Otherwise, we may, due to posted bus writes,
|
||||
* clear the interrupt after we finish the scan,
|
||||
* and after the sequencer has added new entries
|
||||
* and asserted the interrupt again.
|
||||
*/
|
||||
if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) {
|
||||
if (ahd_is_paused(ahd)) {
|
||||
/*
|
||||
* Potentially lost SEQINT.
|
||||
* If SEQINTCODE is non-zero,
|
||||
* simulate the SEQINT.
|
||||
*/
|
||||
if (ahd_inb(ahd, SEQINTCODE) != NO_SEQINT)
|
||||
intstat |= SEQINT;
|
||||
}
|
||||
} else {
|
||||
ahd_flush_device_writes(ahd);
|
||||
}
|
||||
ahd_run_qoutfifo(ahd);
|
||||
ahd->cmdcmplt_counts[ahd->cmdcmplt_bucket]++;
|
||||
ahd->cmdcmplt_total++;
|
||||
#ifdef AHD_TARGET_MODE
|
||||
if ((ahd->flags & AHD_TARGETROLE) != 0)
|
||||
ahd_run_tqinfifo(ahd, /*paused*/FALSE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle statuses that may invalidate our cached
|
||||
* copy of INTSTAT separately.
|
||||
*/
|
||||
if (intstat == 0xFF && (ahd->features & AHD_REMOVABLE) != 0) {
|
||||
/* Hot eject. Do nothing */
|
||||
} else if (intstat & HWERRINT) {
|
||||
ahd_handle_hwerrint(ahd);
|
||||
} else if ((intstat & (PCIINT|SPLTINT)) != 0) {
|
||||
ahd->bus_intr(ahd);
|
||||
} else {
|
||||
|
||||
if ((intstat & SEQINT) != 0)
|
||||
ahd_handle_seqint(ahd, intstat);
|
||||
|
||||
if ((intstat & SCSIINT) != 0)
|
||||
ahd_handle_scsiint(ahd, intstat);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
int ahd_intr(struct ahd_softc *ahd);
|
||||
|
||||
#endif /* _AIC79XX_INLINE_H_ */
|
||||
|
@ -193,7 +193,7 @@ struct ahd_linux_iocell_opts
|
||||
#define AIC79XX_PRECOMP_INDEX 0
|
||||
#define AIC79XX_SLEWRATE_INDEX 1
|
||||
#define AIC79XX_AMPLITUDE_INDEX 2
|
||||
static struct ahd_linux_iocell_opts aic79xx_iocell_info[] =
|
||||
static const struct ahd_linux_iocell_opts aic79xx_iocell_info[] =
|
||||
{
|
||||
AIC79XX_DEFAULT_IOOPTS,
|
||||
AIC79XX_DEFAULT_IOOPTS,
|
||||
@ -369,10 +369,167 @@ static void ahd_release_simq(struct ahd_softc *ahd);
|
||||
static int ahd_linux_unit;
|
||||
|
||||
|
||||
/****************************** Inlines ***************************************/
|
||||
static __inline void ahd_linux_unmap_scb(struct ahd_softc*, struct scb*);
|
||||
/************************** OS Utility Wrappers *******************************/
|
||||
void ahd_delay(long);
|
||||
void
|
||||
ahd_delay(long usec)
|
||||
{
|
||||
/*
|
||||
* udelay on Linux can have problems for
|
||||
* multi-millisecond waits. Wait at most
|
||||
* 1024us per call.
|
||||
*/
|
||||
while (usec > 0) {
|
||||
udelay(usec % 1024);
|
||||
usec -= 1024;
|
||||
}
|
||||
}
|
||||
|
||||
static __inline void
|
||||
|
||||
/***************************** Low Level I/O **********************************/
|
||||
uint8_t ahd_inb(struct ahd_softc * ahd, long port);
|
||||
void ahd_outb(struct ahd_softc * ahd, long port, uint8_t val);
|
||||
void ahd_outw_atomic(struct ahd_softc * ahd,
|
||||
long port, uint16_t val);
|
||||
void ahd_outsb(struct ahd_softc * ahd, long port,
|
||||
uint8_t *, int count);
|
||||
void ahd_insb(struct ahd_softc * ahd, long port,
|
||||
uint8_t *, int count);
|
||||
|
||||
uint8_t
|
||||
ahd_inb(struct ahd_softc * ahd, long port)
|
||||
{
|
||||
uint8_t x;
|
||||
|
||||
if (ahd->tags[0] == BUS_SPACE_MEMIO) {
|
||||
x = readb(ahd->bshs[0].maddr + port);
|
||||
} else {
|
||||
x = inb(ahd->bshs[(port) >> 8].ioport + ((port) & 0xFF));
|
||||
}
|
||||
mb();
|
||||
return (x);
|
||||
}
|
||||
|
||||
#if 0 /* unused */
|
||||
static uint16_t
|
||||
ahd_inw_atomic(struct ahd_softc * ahd, long port)
|
||||
{
|
||||
uint8_t x;
|
||||
|
||||
if (ahd->tags[0] == BUS_SPACE_MEMIO) {
|
||||
x = readw(ahd->bshs[0].maddr + port);
|
||||
} else {
|
||||
x = inw(ahd->bshs[(port) >> 8].ioport + ((port) & 0xFF));
|
||||
}
|
||||
mb();
|
||||
return (x);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
ahd_outb(struct ahd_softc * ahd, long port, uint8_t val)
|
||||
{
|
||||
if (ahd->tags[0] == BUS_SPACE_MEMIO) {
|
||||
writeb(val, ahd->bshs[0].maddr + port);
|
||||
} else {
|
||||
outb(val, ahd->bshs[(port) >> 8].ioport + (port & 0xFF));
|
||||
}
|
||||
mb();
|
||||
}
|
||||
|
||||
void
|
||||
ahd_outw_atomic(struct ahd_softc * ahd, long port, uint16_t val)
|
||||
{
|
||||
if (ahd->tags[0] == BUS_SPACE_MEMIO) {
|
||||
writew(val, ahd->bshs[0].maddr + port);
|
||||
} else {
|
||||
outw(val, ahd->bshs[(port) >> 8].ioport + (port & 0xFF));
|
||||
}
|
||||
mb();
|
||||
}
|
||||
|
||||
void
|
||||
ahd_outsb(struct ahd_softc * ahd, long port, uint8_t *array, int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* There is probably a more efficient way to do this on Linux
|
||||
* but we don't use this for anything speed critical and this
|
||||
* should work.
|
||||
*/
|
||||
for (i = 0; i < count; i++)
|
||||
ahd_outb(ahd, port, *array++);
|
||||
}
|
||||
|
||||
void
|
||||
ahd_insb(struct ahd_softc * ahd, long port, uint8_t *array, int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* There is probably a more efficient way to do this on Linux
|
||||
* but we don't use this for anything speed critical and this
|
||||
* should work.
|
||||
*/
|
||||
for (i = 0; i < count; i++)
|
||||
*array++ = ahd_inb(ahd, port);
|
||||
}
|
||||
|
||||
/******************************* PCI Routines *********************************/
|
||||
uint32_t
|
||||
ahd_pci_read_config(ahd_dev_softc_t pci, int reg, int width)
|
||||
{
|
||||
switch (width) {
|
||||
case 1:
|
||||
{
|
||||
uint8_t retval;
|
||||
|
||||
pci_read_config_byte(pci, reg, &retval);
|
||||
return (retval);
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
uint16_t retval;
|
||||
pci_read_config_word(pci, reg, &retval);
|
||||
return (retval);
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
uint32_t retval;
|
||||
pci_read_config_dword(pci, reg, &retval);
|
||||
return (retval);
|
||||
}
|
||||
default:
|
||||
panic("ahd_pci_read_config: Read size too big");
|
||||
/* NOTREACHED */
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ahd_pci_write_config(ahd_dev_softc_t pci, int reg, uint32_t value, int width)
|
||||
{
|
||||
switch (width) {
|
||||
case 1:
|
||||
pci_write_config_byte(pci, reg, value);
|
||||
break;
|
||||
case 2:
|
||||
pci_write_config_word(pci, reg, value);
|
||||
break;
|
||||
case 4:
|
||||
pci_write_config_dword(pci, reg, value);
|
||||
break;
|
||||
default:
|
||||
panic("ahd_pci_write_config: Write size too big");
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
|
||||
/****************************** Inlines ***************************************/
|
||||
static void ahd_linux_unmap_scb(struct ahd_softc*, struct scb*);
|
||||
|
||||
static void
|
||||
ahd_linux_unmap_scb(struct ahd_softc *ahd, struct scb *scb)
|
||||
{
|
||||
struct scsi_cmnd *cmd;
|
||||
@ -400,13 +557,11 @@ ahd_linux_info(struct Scsi_Host *host)
|
||||
bp = &buffer[0];
|
||||
ahd = *(struct ahd_softc **)host->hostdata;
|
||||
memset(bp, 0, sizeof(buffer));
|
||||
strcpy(bp, "Adaptec AIC79XX PCI-X SCSI HBA DRIVER, Rev ");
|
||||
strcat(bp, AIC79XX_DRIVER_VERSION);
|
||||
strcat(bp, "\n");
|
||||
strcat(bp, " <");
|
||||
strcpy(bp, "Adaptec AIC79XX PCI-X SCSI HBA DRIVER, Rev " AIC79XX_DRIVER_VERSION "\n"
|
||||
" <");
|
||||
strcat(bp, ahd->description);
|
||||
strcat(bp, ">\n");
|
||||
strcat(bp, " ");
|
||||
strcat(bp, ">\n"
|
||||
" ");
|
||||
ahd_controller_info(ahd, ahd_info);
|
||||
strcat(bp, ahd_info);
|
||||
|
||||
@ -432,7 +587,7 @@ ahd_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *))
|
||||
return rtn;
|
||||
}
|
||||
|
||||
static inline struct scsi_target **
|
||||
static struct scsi_target **
|
||||
ahd_linux_target_in_softc(struct scsi_target *starget)
|
||||
{
|
||||
struct ahd_softc *ahd =
|
||||
@ -991,7 +1146,7 @@ aic79xx_setup(char *s)
|
||||
char *p;
|
||||
char *end;
|
||||
|
||||
static struct {
|
||||
static const struct {
|
||||
const char *name;
|
||||
uint32_t *flag;
|
||||
} options[] = {
|
||||
@ -1223,7 +1378,7 @@ ahd_platform_init(struct ahd_softc *ahd)
|
||||
* Lookup and commit any modified IO Cell options.
|
||||
*/
|
||||
if (ahd->unit < ARRAY_SIZE(aic79xx_iocell_info)) {
|
||||
struct ahd_linux_iocell_opts *iocell_opts;
|
||||
const struct ahd_linux_iocell_opts *iocell_opts;
|
||||
|
||||
iocell_opts = &aic79xx_iocell_info[ahd->unit];
|
||||
if (iocell_opts->precomp != AIC79XX_DEFAULT_PRECOMP)
|
||||
@ -2613,7 +2768,7 @@ static void ahd_linux_set_pcomp_en(struct scsi_target *starget, int pcomp)
|
||||
uint8_t precomp;
|
||||
|
||||
if (ahd->unit < ARRAY_SIZE(aic79xx_iocell_info)) {
|
||||
struct ahd_linux_iocell_opts *iocell_opts;
|
||||
const struct ahd_linux_iocell_opts *iocell_opts;
|
||||
|
||||
iocell_opts = &aic79xx_iocell_info[ahd->unit];
|
||||
precomp = iocell_opts->precomp;
|
||||
|
@ -222,22 +222,6 @@ typedef struct timer_list ahd_timer_t;
|
||||
/***************************** Timer Facilities *******************************/
|
||||
#define ahd_timer_init init_timer
|
||||
#define ahd_timer_stop del_timer_sync
|
||||
typedef void ahd_linux_callback_t (u_long);
|
||||
static __inline void ahd_timer_reset(ahd_timer_t *timer, int usec,
|
||||
ahd_callback_t *func, void *arg);
|
||||
|
||||
static __inline void
|
||||
ahd_timer_reset(ahd_timer_t *timer, int usec, ahd_callback_t *func, void *arg)
|
||||
{
|
||||
struct ahd_softc *ahd;
|
||||
|
||||
ahd = (struct ahd_softc *)arg;
|
||||
del_timer(timer);
|
||||
timer->data = (u_long)arg;
|
||||
timer->expires = jiffies + (usec * HZ)/1000000;
|
||||
timer->function = (ahd_linux_callback_t*)func;
|
||||
add_timer(timer);
|
||||
}
|
||||
|
||||
/***************************** SMP support ************************************/
|
||||
#include <linux/spinlock.h>
|
||||
@ -376,7 +360,7 @@ struct ahd_platform_data {
|
||||
#define AHD_LINUX_NOIRQ ((uint32_t)~0)
|
||||
uint32_t irq; /* IRQ for this adapter */
|
||||
uint32_t bios_address;
|
||||
uint32_t mem_busaddr; /* Mem Base Addr */
|
||||
resource_size_t mem_busaddr; /* Mem Base Addr */
|
||||
};
|
||||
|
||||
/************************** OS Utility Wrappers *******************************/
|
||||
@ -386,111 +370,18 @@ struct ahd_platform_data {
|
||||
#define malloc(size, type, flags) kmalloc(size, flags)
|
||||
#define free(ptr, type) kfree(ptr)
|
||||
|
||||
static __inline void ahd_delay(long);
|
||||
static __inline void
|
||||
ahd_delay(long usec)
|
||||
{
|
||||
/*
|
||||
* udelay on Linux can have problems for
|
||||
* multi-millisecond waits. Wait at most
|
||||
* 1024us per call.
|
||||
*/
|
||||
while (usec > 0) {
|
||||
udelay(usec % 1024);
|
||||
usec -= 1024;
|
||||
}
|
||||
}
|
||||
|
||||
void ahd_delay(long);
|
||||
|
||||
/***************************** Low Level I/O **********************************/
|
||||
static __inline uint8_t ahd_inb(struct ahd_softc * ahd, long port);
|
||||
static __inline uint16_t ahd_inw_atomic(struct ahd_softc * ahd, long port);
|
||||
static __inline void ahd_outb(struct ahd_softc * ahd, long port, uint8_t val);
|
||||
static __inline void ahd_outw_atomic(struct ahd_softc * ahd,
|
||||
uint8_t ahd_inb(struct ahd_softc * ahd, long port);
|
||||
void ahd_outb(struct ahd_softc * ahd, long port, uint8_t val);
|
||||
void ahd_outw_atomic(struct ahd_softc * ahd,
|
||||
long port, uint16_t val);
|
||||
static __inline void ahd_outsb(struct ahd_softc * ahd, long port,
|
||||
void ahd_outsb(struct ahd_softc * ahd, long port,
|
||||
uint8_t *, int count);
|
||||
static __inline void ahd_insb(struct ahd_softc * ahd, long port,
|
||||
void ahd_insb(struct ahd_softc * ahd, long port,
|
||||
uint8_t *, int count);
|
||||
|
||||
static __inline uint8_t
|
||||
ahd_inb(struct ahd_softc * ahd, long port)
|
||||
{
|
||||
uint8_t x;
|
||||
|
||||
if (ahd->tags[0] == BUS_SPACE_MEMIO) {
|
||||
x = readb(ahd->bshs[0].maddr + port);
|
||||
} else {
|
||||
x = inb(ahd->bshs[(port) >> 8].ioport + ((port) & 0xFF));
|
||||
}
|
||||
mb();
|
||||
return (x);
|
||||
}
|
||||
|
||||
static __inline uint16_t
|
||||
ahd_inw_atomic(struct ahd_softc * ahd, long port)
|
||||
{
|
||||
uint8_t x;
|
||||
|
||||
if (ahd->tags[0] == BUS_SPACE_MEMIO) {
|
||||
x = readw(ahd->bshs[0].maddr + port);
|
||||
} else {
|
||||
x = inw(ahd->bshs[(port) >> 8].ioport + ((port) & 0xFF));
|
||||
}
|
||||
mb();
|
||||
return (x);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_outb(struct ahd_softc * ahd, long port, uint8_t val)
|
||||
{
|
||||
if (ahd->tags[0] == BUS_SPACE_MEMIO) {
|
||||
writeb(val, ahd->bshs[0].maddr + port);
|
||||
} else {
|
||||
outb(val, ahd->bshs[(port) >> 8].ioport + (port & 0xFF));
|
||||
}
|
||||
mb();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_outw_atomic(struct ahd_softc * ahd, long port, uint16_t val)
|
||||
{
|
||||
if (ahd->tags[0] == BUS_SPACE_MEMIO) {
|
||||
writew(val, ahd->bshs[0].maddr + port);
|
||||
} else {
|
||||
outw(val, ahd->bshs[(port) >> 8].ioport + (port & 0xFF));
|
||||
}
|
||||
mb();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_outsb(struct ahd_softc * ahd, long port, uint8_t *array, int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* There is probably a more efficient way to do this on Linux
|
||||
* but we don't use this for anything speed critical and this
|
||||
* should work.
|
||||
*/
|
||||
for (i = 0; i < count; i++)
|
||||
ahd_outb(ahd, port, *array++);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_insb(struct ahd_softc * ahd, long port, uint8_t *array, int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* There is probably a more efficient way to do this on Linux
|
||||
* but we don't use this for anything speed critical and this
|
||||
* should work.
|
||||
*/
|
||||
for (i = 0; i < count; i++)
|
||||
*array++ = ahd_inb(ahd, port);
|
||||
}
|
||||
|
||||
/**************************** Initialization **********************************/
|
||||
int ahd_linux_register_host(struct ahd_softc *,
|
||||
struct scsi_host_template *);
|
||||
@ -593,62 +484,12 @@ void ahd_linux_pci_exit(void);
|
||||
int ahd_pci_map_registers(struct ahd_softc *ahd);
|
||||
int ahd_pci_map_int(struct ahd_softc *ahd);
|
||||
|
||||
static __inline uint32_t ahd_pci_read_config(ahd_dev_softc_t pci,
|
||||
uint32_t ahd_pci_read_config(ahd_dev_softc_t pci,
|
||||
int reg, int width);
|
||||
|
||||
static __inline uint32_t
|
||||
ahd_pci_read_config(ahd_dev_softc_t pci, int reg, int width)
|
||||
{
|
||||
switch (width) {
|
||||
case 1:
|
||||
{
|
||||
uint8_t retval;
|
||||
|
||||
pci_read_config_byte(pci, reg, &retval);
|
||||
return (retval);
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
uint16_t retval;
|
||||
pci_read_config_word(pci, reg, &retval);
|
||||
return (retval);
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
uint32_t retval;
|
||||
pci_read_config_dword(pci, reg, &retval);
|
||||
return (retval);
|
||||
}
|
||||
default:
|
||||
panic("ahd_pci_read_config: Read size too big");
|
||||
/* NOTREACHED */
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
static __inline void ahd_pci_write_config(ahd_dev_softc_t pci,
|
||||
void ahd_pci_write_config(ahd_dev_softc_t pci,
|
||||
int reg, uint32_t value,
|
||||
int width);
|
||||
|
||||
static __inline void
|
||||
ahd_pci_write_config(ahd_dev_softc_t pci, int reg, uint32_t value, int width)
|
||||
{
|
||||
switch (width) {
|
||||
case 1:
|
||||
pci_write_config_byte(pci, reg, value);
|
||||
break;
|
||||
case 2:
|
||||
pci_write_config_word(pci, reg, value);
|
||||
break;
|
||||
case 4:
|
||||
pci_write_config_dword(pci, reg, value);
|
||||
break;
|
||||
default:
|
||||
panic("ahd_pci_write_config: Write size too big");
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
|
||||
static __inline int ahd_get_pci_function(ahd_dev_softc_t);
|
||||
static __inline int
|
||||
ahd_get_pci_function(ahd_dev_softc_t pci)
|
||||
|
@ -49,7 +49,7 @@
|
||||
ID2C(x), \
|
||||
ID2C(IDIROC(x))
|
||||
|
||||
static struct pci_device_id ahd_linux_pci_id_table[] = {
|
||||
static const struct pci_device_id ahd_linux_pci_id_table[] = {
|
||||
/* aic7901 based controllers */
|
||||
ID(ID_AHA_29320A),
|
||||
ID(ID_AHA_29320ALP),
|
||||
@ -159,7 +159,7 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
char buf[80];
|
||||
struct ahd_softc *ahd;
|
||||
ahd_dev_softc_t pci;
|
||||
struct ahd_pci_identity *entry;
|
||||
const struct ahd_pci_identity *entry;
|
||||
char *name;
|
||||
int error;
|
||||
struct device *dev = &pdev->dev;
|
||||
@ -249,8 +249,8 @@ ahd_linux_pci_exit(void)
|
||||
}
|
||||
|
||||
static int
|
||||
ahd_linux_pci_reserve_io_regions(struct ahd_softc *ahd, u_long *base,
|
||||
u_long *base2)
|
||||
ahd_linux_pci_reserve_io_regions(struct ahd_softc *ahd, resource_size_t *base,
|
||||
resource_size_t *base2)
|
||||
{
|
||||
*base = pci_resource_start(ahd->dev_softc, 0);
|
||||
/*
|
||||
@ -272,11 +272,11 @@ ahd_linux_pci_reserve_io_regions(struct ahd_softc *ahd, u_long *base,
|
||||
|
||||
static int
|
||||
ahd_linux_pci_reserve_mem_region(struct ahd_softc *ahd,
|
||||
u_long *bus_addr,
|
||||
resource_size_t *bus_addr,
|
||||
uint8_t __iomem **maddr)
|
||||
{
|
||||
u_long start;
|
||||
u_long base_page;
|
||||
resource_size_t start;
|
||||
resource_size_t base_page;
|
||||
u_long base_offset;
|
||||
int error = 0;
|
||||
|
||||
@ -310,7 +310,7 @@ int
|
||||
ahd_pci_map_registers(struct ahd_softc *ahd)
|
||||
{
|
||||
uint32_t command;
|
||||
u_long base;
|
||||
resource_size_t base;
|
||||
uint8_t __iomem *maddr;
|
||||
int error;
|
||||
|
||||
@ -346,31 +346,32 @@ ahd_pci_map_registers(struct ahd_softc *ahd)
|
||||
} else
|
||||
command |= PCIM_CMD_MEMEN;
|
||||
} else if (bootverbose) {
|
||||
printf("aic79xx: PCI%d:%d:%d MEM region 0x%lx "
|
||||
printf("aic79xx: PCI%d:%d:%d MEM region 0x%llx "
|
||||
"unavailable. Cannot memory map device.\n",
|
||||
ahd_get_pci_bus(ahd->dev_softc),
|
||||
ahd_get_pci_slot(ahd->dev_softc),
|
||||
ahd_get_pci_function(ahd->dev_softc),
|
||||
base);
|
||||
(unsigned long long)base);
|
||||
}
|
||||
|
||||
if (maddr == NULL) {
|
||||
u_long base2;
|
||||
resource_size_t base2;
|
||||
|
||||
error = ahd_linux_pci_reserve_io_regions(ahd, &base, &base2);
|
||||
if (error == 0) {
|
||||
ahd->tags[0] = BUS_SPACE_PIO;
|
||||
ahd->tags[1] = BUS_SPACE_PIO;
|
||||
ahd->bshs[0].ioport = base;
|
||||
ahd->bshs[1].ioport = base2;
|
||||
ahd->bshs[0].ioport = (u_long)base;
|
||||
ahd->bshs[1].ioport = (u_long)base2;
|
||||
command |= PCIM_CMD_PORTEN;
|
||||
} else {
|
||||
printf("aic79xx: PCI%d:%d:%d IO regions 0x%lx and 0x%lx"
|
||||
"unavailable. Cannot map device.\n",
|
||||
printf("aic79xx: PCI%d:%d:%d IO regions 0x%llx and "
|
||||
"0x%llx unavailable. Cannot map device.\n",
|
||||
ahd_get_pci_bus(ahd->dev_softc),
|
||||
ahd_get_pci_slot(ahd->dev_softc),
|
||||
ahd_get_pci_function(ahd->dev_softc),
|
||||
base, base2);
|
||||
(unsigned long long)base,
|
||||
(unsigned long long)base2);
|
||||
}
|
||||
}
|
||||
ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command, 4);
|
||||
|
@ -97,7 +97,7 @@ static ahd_device_setup_t ahd_aic7901A_setup;
|
||||
static ahd_device_setup_t ahd_aic7902_setup;
|
||||
static ahd_device_setup_t ahd_aic790X_setup;
|
||||
|
||||
static struct ahd_pci_identity ahd_pci_ident_table [] =
|
||||
static const struct ahd_pci_identity ahd_pci_ident_table[] =
|
||||
{
|
||||
/* aic7901 based controllers */
|
||||
{
|
||||
@ -253,7 +253,7 @@ static void ahd_configure_termination(struct ahd_softc *ahd,
|
||||
static void ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat);
|
||||
static void ahd_pci_intr(struct ahd_softc *ahd);
|
||||
|
||||
struct ahd_pci_identity *
|
||||
const struct ahd_pci_identity *
|
||||
ahd_find_pci_device(ahd_dev_softc_t pci)
|
||||
{
|
||||
uint64_t full_id;
|
||||
@ -261,7 +261,7 @@ ahd_find_pci_device(ahd_dev_softc_t pci)
|
||||
uint16_t vendor;
|
||||
uint16_t subdevice;
|
||||
uint16_t subvendor;
|
||||
struct ahd_pci_identity *entry;
|
||||
const struct ahd_pci_identity *entry;
|
||||
u_int i;
|
||||
|
||||
vendor = ahd_pci_read_config(pci, PCIR_DEVVENDOR, /*bytes*/2);
|
||||
@ -292,7 +292,7 @@ ahd_find_pci_device(ahd_dev_softc_t pci)
|
||||
}
|
||||
|
||||
int
|
||||
ahd_pci_config(struct ahd_softc *ahd, struct ahd_pci_identity *entry)
|
||||
ahd_pci_config(struct ahd_softc *ahd, const struct ahd_pci_identity *entry)
|
||||
{
|
||||
struct scb_data *shared_scb_data;
|
||||
u_int command;
|
||||
|
@ -57,7 +57,7 @@ static int ahd_proc_write_seeprom(struct ahd_softc *ahd,
|
||||
* Table of syncrates that don't follow the "divisible by 4"
|
||||
* rule. This table will be expanded in future SCSI specs.
|
||||
*/
|
||||
static struct {
|
||||
static const struct {
|
||||
u_int period_factor;
|
||||
u_int period; /* in 100ths of ns */
|
||||
} scsi_syncrates[] = {
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -5,7 +5,7 @@
|
||||
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#120 $
|
||||
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#77 $
|
||||
*/
|
||||
static uint8_t seqprog[] = {
|
||||
static const uint8_t seqprog[] = {
|
||||
0xff, 0x02, 0x06, 0x78,
|
||||
0x00, 0xea, 0x6e, 0x59,
|
||||
0x01, 0xea, 0x04, 0x30,
|
||||
@ -1027,7 +1027,7 @@ ahd_patch0_func(struct ahd_softc *ahd)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static struct patch {
|
||||
static const struct patch {
|
||||
ahd_patch_func_t *patch_func;
|
||||
uint32_t begin :10,
|
||||
skip_instr :10,
|
||||
@ -1166,7 +1166,7 @@ static struct patch {
|
||||
{ ahd_patch23_func, 815, 11, 1 }
|
||||
};
|
||||
|
||||
static struct cs {
|
||||
static const struct cs {
|
||||
uint16_t begin;
|
||||
uint16_t end;
|
||||
} critical_sections[] = {
|
||||
|
@ -736,7 +736,7 @@ struct ahc_syncrate {
|
||||
#define ST_SXFR 0x010 /* Rate Single Transition Only */
|
||||
#define DT_SXFR 0x040 /* Rate Double Transition Only */
|
||||
uint8_t period; /* Period to send to SCSI target */
|
||||
char *rate;
|
||||
const char *rate;
|
||||
};
|
||||
|
||||
/* Safe and valid period for async negotiations. */
|
||||
@ -1114,7 +1114,7 @@ typedef int (ahc_device_setup_t)(struct ahc_softc *);
|
||||
struct ahc_pci_identity {
|
||||
uint64_t full_id;
|
||||
uint64_t id_mask;
|
||||
char *name;
|
||||
const char *name;
|
||||
ahc_device_setup_t *setup;
|
||||
};
|
||||
|
||||
@ -1133,15 +1133,11 @@ extern const int ahc_num_aic7770_devs;
|
||||
|
||||
/*************************** Function Declarations ****************************/
|
||||
/******************************************************************************/
|
||||
u_int ahc_index_busy_tcl(struct ahc_softc *ahc, u_int tcl);
|
||||
void ahc_unbusy_tcl(struct ahc_softc *ahc, u_int tcl);
|
||||
void ahc_busy_tcl(struct ahc_softc *ahc,
|
||||
u_int tcl, u_int busyid);
|
||||
|
||||
/***************************** PCI Front End *********************************/
|
||||
struct ahc_pci_identity *ahc_find_pci_device(ahc_dev_softc_t);
|
||||
const struct ahc_pci_identity *ahc_find_pci_device(ahc_dev_softc_t);
|
||||
int ahc_pci_config(struct ahc_softc *,
|
||||
struct ahc_pci_identity *);
|
||||
const struct ahc_pci_identity *);
|
||||
int ahc_pci_test_register_access(struct ahc_softc *);
|
||||
#ifdef CONFIG_PM
|
||||
void ahc_pci_resume(struct ahc_softc *ahc);
|
||||
@ -1155,9 +1151,6 @@ int aic7770_config(struct ahc_softc *ahc,
|
||||
|
||||
/************************** SCB and SCB queue management **********************/
|
||||
int ahc_probe_scbs(struct ahc_softc *);
|
||||
void ahc_run_untagged_queues(struct ahc_softc *ahc);
|
||||
void ahc_run_untagged_queue(struct ahc_softc *ahc,
|
||||
struct scb_tailq *queue);
|
||||
void ahc_qinfifo_requeue_tail(struct ahc_softc *ahc,
|
||||
struct scb *scb);
|
||||
int ahc_match_scb(struct ahc_softc *ahc, struct scb *scb,
|
||||
@ -1178,22 +1171,8 @@ int ahc_resume(struct ahc_softc *ahc);
|
||||
#endif
|
||||
void ahc_set_unit(struct ahc_softc *, int);
|
||||
void ahc_set_name(struct ahc_softc *, char *);
|
||||
void ahc_alloc_scbs(struct ahc_softc *ahc);
|
||||
void ahc_free(struct ahc_softc *ahc);
|
||||
int ahc_reset(struct ahc_softc *ahc, int reinit);
|
||||
void ahc_shutdown(void *arg);
|
||||
|
||||
/*************************** Interrupt Services *******************************/
|
||||
void ahc_clear_intstat(struct ahc_softc *ahc);
|
||||
void ahc_run_qoutfifo(struct ahc_softc *ahc);
|
||||
#ifdef AHC_TARGET_MODE
|
||||
void ahc_run_tqinfifo(struct ahc_softc *ahc, int paused);
|
||||
#endif
|
||||
void ahc_handle_brkadrint(struct ahc_softc *ahc);
|
||||
void ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat);
|
||||
void ahc_handle_scsiint(struct ahc_softc *ahc,
|
||||
u_int intstat);
|
||||
void ahc_clear_critical_section(struct ahc_softc *ahc);
|
||||
|
||||
/***************************** Error Recovery *********************************/
|
||||
typedef enum {
|
||||
@ -1214,36 +1193,19 @@ int ahc_search_disc_list(struct ahc_softc *ahc, int target,
|
||||
char channel, int lun, u_int tag,
|
||||
int stop_on_first, int remove,
|
||||
int save_state);
|
||||
void ahc_freeze_devq(struct ahc_softc *ahc, struct scb *scb);
|
||||
int ahc_reset_channel(struct ahc_softc *ahc, char channel,
|
||||
int initiate_reset);
|
||||
int ahc_abort_scbs(struct ahc_softc *ahc, int target,
|
||||
char channel, int lun, u_int tag,
|
||||
role_t role, uint32_t status);
|
||||
void ahc_restart(struct ahc_softc *ahc);
|
||||
void ahc_calc_residual(struct ahc_softc *ahc,
|
||||
struct scb *scb);
|
||||
|
||||
/*************************** Utility Functions ********************************/
|
||||
struct ahc_phase_table_entry*
|
||||
ahc_lookup_phase_entry(int phase);
|
||||
void ahc_compile_devinfo(struct ahc_devinfo *devinfo,
|
||||
u_int our_id, u_int target,
|
||||
u_int lun, char channel,
|
||||
role_t role);
|
||||
/************************** Transfer Negotiation ******************************/
|
||||
struct ahc_syncrate* ahc_find_syncrate(struct ahc_softc *ahc, u_int *period,
|
||||
const struct ahc_syncrate* ahc_find_syncrate(struct ahc_softc *ahc, u_int *period,
|
||||
u_int *ppr_options, u_int maxsync);
|
||||
u_int ahc_find_period(struct ahc_softc *ahc,
|
||||
u_int scsirate, u_int maxsync);
|
||||
void ahc_validate_offset(struct ahc_softc *ahc,
|
||||
struct ahc_initiator_tinfo *tinfo,
|
||||
struct ahc_syncrate *syncrate,
|
||||
u_int *offset, int wide,
|
||||
role_t role);
|
||||
void ahc_validate_width(struct ahc_softc *ahc,
|
||||
struct ahc_initiator_tinfo *tinfo,
|
||||
u_int *bus_width,
|
||||
role_t role);
|
||||
/*
|
||||
* Negotiation types. These are used to qualify if we should renegotiate
|
||||
* even if our goal and current transport parameters are identical.
|
||||
@ -1263,7 +1225,7 @@ void ahc_set_width(struct ahc_softc *ahc,
|
||||
u_int width, u_int type, int paused);
|
||||
void ahc_set_syncrate(struct ahc_softc *ahc,
|
||||
struct ahc_devinfo *devinfo,
|
||||
struct ahc_syncrate *syncrate,
|
||||
const struct ahc_syncrate *syncrate,
|
||||
u_int period, u_int offset,
|
||||
u_int ppr_options,
|
||||
u_int type, int paused);
|
||||
@ -1305,11 +1267,10 @@ extern uint32_t ahc_debug;
|
||||
#define AHC_SHOW_MASKED_ERRORS 0x1000
|
||||
#define AHC_DEBUG_SEQUENCER 0x2000
|
||||
#endif
|
||||
void ahc_print_scb(struct scb *scb);
|
||||
void ahc_print_devinfo(struct ahc_softc *ahc,
|
||||
struct ahc_devinfo *dev);
|
||||
void ahc_dump_card_state(struct ahc_softc *ahc);
|
||||
int ahc_print_register(ahc_reg_parse_entry_t *table,
|
||||
int ahc_print_register(const ahc_reg_parse_entry_t *table,
|
||||
u_int num_entries,
|
||||
const char *name,
|
||||
u_int address,
|
||||
|
@ -238,6 +238,7 @@ register SXFRCTL2 {
|
||||
register OPTIONMODE {
|
||||
address 0x008
|
||||
access_mode RW
|
||||
count 2
|
||||
field AUTORATEEN 0x80
|
||||
field AUTOACKEN 0x40
|
||||
field ATNMGMNTEN 0x20
|
||||
@ -254,6 +255,7 @@ register TARGCRCCNT {
|
||||
address 0x00a
|
||||
size 2
|
||||
access_mode RW
|
||||
count 2
|
||||
}
|
||||
|
||||
/*
|
||||
@ -344,6 +346,7 @@ register SSTAT2 {
|
||||
register SSTAT3 {
|
||||
address 0x00e
|
||||
access_mode RO
|
||||
count 2
|
||||
mask SCSICNT 0xf0
|
||||
mask OFFCNT 0x0f
|
||||
mask U2OFFCNT 0x7f
|
||||
@ -367,6 +370,7 @@ register SCSIID_ULTRA2 {
|
||||
register SIMODE0 {
|
||||
address 0x010
|
||||
access_mode RW
|
||||
count 2
|
||||
field ENSELDO 0x40
|
||||
field ENSELDI 0x20
|
||||
field ENSELINGO 0x10
|
||||
@ -429,6 +433,7 @@ register SHADDR {
|
||||
register SELTIMER {
|
||||
address 0x018
|
||||
access_mode RW
|
||||
count 1
|
||||
field STAGE6 0x20
|
||||
field STAGE5 0x10
|
||||
field STAGE4 0x08
|
||||
@ -467,6 +472,7 @@ register TARGID {
|
||||
address 0x01b
|
||||
size 2
|
||||
access_mode RW
|
||||
count 14
|
||||
}
|
||||
|
||||
/*
|
||||
@ -480,6 +486,7 @@ register TARGID {
|
||||
register SPIOCAP {
|
||||
address 0x01b
|
||||
access_mode RW
|
||||
count 10
|
||||
field SOFT1 0x80
|
||||
field SOFT0 0x40
|
||||
field SOFTCMDEN 0x20
|
||||
@ -492,6 +499,7 @@ register SPIOCAP {
|
||||
|
||||
register BRDCTL {
|
||||
address 0x01d
|
||||
count 11
|
||||
field BRDDAT7 0x80
|
||||
field BRDDAT6 0x40
|
||||
field BRDDAT5 0x20
|
||||
@ -534,6 +542,7 @@ register BRDCTL {
|
||||
*/
|
||||
register SEECTL {
|
||||
address 0x01e
|
||||
count 11
|
||||
field EXTARBACK 0x80
|
||||
field EXTARBREQ 0x40
|
||||
field SEEMS 0x20
|
||||
@ -570,6 +579,7 @@ register SBLKCTL {
|
||||
register SEQCTL {
|
||||
address 0x060
|
||||
access_mode RW
|
||||
count 15
|
||||
field PERRORDIS 0x80
|
||||
field PAUSEDIS 0x40
|
||||
field FAILDIS 0x20
|
||||
@ -590,6 +600,7 @@ register SEQCTL {
|
||||
register SEQRAM {
|
||||
address 0x061
|
||||
access_mode RW
|
||||
count 2
|
||||
}
|
||||
|
||||
/*
|
||||
@ -604,6 +615,7 @@ register SEQADDR0 {
|
||||
register SEQADDR1 {
|
||||
address 0x063
|
||||
access_mode RW
|
||||
count 8
|
||||
mask SEQADDR1_MASK 0x01
|
||||
}
|
||||
|
||||
@ -649,6 +661,7 @@ register NONE {
|
||||
register FLAGS {
|
||||
address 0x06b
|
||||
access_mode RO
|
||||
count 18
|
||||
field ZERO 0x02
|
||||
field CARRY 0x01
|
||||
}
|
||||
@ -671,6 +684,7 @@ register FUNCTION1 {
|
||||
register STACK {
|
||||
address 0x06f
|
||||
access_mode RO
|
||||
count 5
|
||||
}
|
||||
|
||||
const STACK_SIZE 4
|
||||
@ -692,6 +706,7 @@ register BCTL {
|
||||
register DSCOMMAND0 {
|
||||
address 0x084
|
||||
access_mode RW
|
||||
count 7
|
||||
field CACHETHEN 0x80 /* Cache Threshold enable */
|
||||
field DPARCKEN 0x40 /* Data Parity Check Enable */
|
||||
field MPARCKEN 0x20 /* Memory Parity Check Enable */
|
||||
@ -717,6 +732,7 @@ register DSCOMMAND1 {
|
||||
register BUSTIME {
|
||||
address 0x085
|
||||
access_mode RW
|
||||
count 2
|
||||
mask BOFF 0xf0
|
||||
mask BON 0x0f
|
||||
}
|
||||
@ -727,6 +743,7 @@ register BUSTIME {
|
||||
register BUSSPD {
|
||||
address 0x086
|
||||
access_mode RW
|
||||
count 2
|
||||
mask DFTHRSH 0xc0
|
||||
mask STBOFF 0x38
|
||||
mask STBON 0x07
|
||||
@ -737,6 +754,7 @@ register BUSSPD {
|
||||
/* aic7850/55/60/70/80/95 only */
|
||||
register DSPCISTATUS {
|
||||
address 0x086
|
||||
count 4
|
||||
mask DFTHRSH_100 0xc0
|
||||
}
|
||||
|
||||
@ -758,6 +776,7 @@ const SEQ_MAILBOX_SHIFT 0
|
||||
register HCNTRL {
|
||||
address 0x087
|
||||
access_mode RW
|
||||
count 14
|
||||
field POWRDN 0x40
|
||||
field SWINT 0x10
|
||||
field IRQMS 0x08
|
||||
@ -869,6 +888,7 @@ register INTSTAT {
|
||||
register ERROR {
|
||||
address 0x092
|
||||
access_mode RO
|
||||
count 26
|
||||
field CIOPARERR 0x80 /* Ultra2 only */
|
||||
field PCIERRSTAT 0x40 /* PCI only */
|
||||
field MPARERR 0x20 /* PCI only */
|
||||
@ -885,6 +905,7 @@ register ERROR {
|
||||
register CLRINT {
|
||||
address 0x092
|
||||
access_mode WO
|
||||
count 24
|
||||
field CLRPARERR 0x10 /* PCI only */
|
||||
field CLRBRKADRINT 0x08
|
||||
field CLRSCSIINT 0x04
|
||||
@ -943,6 +964,7 @@ register DFDAT {
|
||||
register SCBCNT {
|
||||
address 0x09a
|
||||
access_mode RW
|
||||
count 1
|
||||
field SCBAUTO 0x80
|
||||
mask SCBCNT_MASK 0x1f
|
||||
}
|
||||
@ -954,6 +976,7 @@ register SCBCNT {
|
||||
register QINFIFO {
|
||||
address 0x09b
|
||||
access_mode RW
|
||||
count 12
|
||||
}
|
||||
|
||||
/*
|
||||
@ -972,11 +995,13 @@ register QINCNT {
|
||||
register QOUTFIFO {
|
||||
address 0x09d
|
||||
access_mode WO
|
||||
count 7
|
||||
}
|
||||
|
||||
register CRCCONTROL1 {
|
||||
address 0x09d
|
||||
access_mode RW
|
||||
count 3
|
||||
field CRCONSEEN 0x80
|
||||
field CRCVALCHKEN 0x40
|
||||
field CRCENDCHKEN 0x20
|
||||
@ -1013,6 +1038,7 @@ register SCSIPHASE {
|
||||
register SFUNCT {
|
||||
address 0x09f
|
||||
access_mode RW
|
||||
count 4
|
||||
field ALT_MODE 0x80
|
||||
}
|
||||
|
||||
@ -1095,6 +1121,7 @@ scb {
|
||||
}
|
||||
SCB_SCSIOFFSET {
|
||||
size 1
|
||||
count 1
|
||||
}
|
||||
SCB_NEXT {
|
||||
size 1
|
||||
@ -1118,6 +1145,7 @@ const SG_SIZEOF 0x08 /* sizeof(struct ahc_dma) */
|
||||
register SEECTL_2840 {
|
||||
address 0x0c0
|
||||
access_mode RW
|
||||
count 2
|
||||
field CS_2840 0x04
|
||||
field CK_2840 0x02
|
||||
field DO_2840 0x01
|
||||
@ -1126,6 +1154,7 @@ register SEECTL_2840 {
|
||||
register STATUS_2840 {
|
||||
address 0x0c1
|
||||
access_mode RW
|
||||
count 4
|
||||
field EEPROM_TF 0x80
|
||||
mask BIOS_SEL 0x60
|
||||
mask ADSEL 0x1e
|
||||
@ -1161,6 +1190,7 @@ register CCSGCTL {
|
||||
|
||||
register CCSCBCNT {
|
||||
address 0xEF
|
||||
count 1
|
||||
}
|
||||
|
||||
register CCSCBCTL {
|
||||
@ -1187,6 +1217,7 @@ register CCSCBRAM {
|
||||
register SCBBADDR {
|
||||
address 0x0F0
|
||||
access_mode RW
|
||||
count 3
|
||||
}
|
||||
|
||||
register CCSCBPTR {
|
||||
@ -1195,6 +1226,7 @@ register CCSCBPTR {
|
||||
|
||||
register HNSCB_QOFF {
|
||||
address 0x0F4
|
||||
count 4
|
||||
}
|
||||
|
||||
register SNSCB_QOFF {
|
||||
@ -1234,6 +1266,7 @@ register DFF_THRSH {
|
||||
mask WR_DFTHRSH_85 0x50
|
||||
mask WR_DFTHRSH_90 0x60
|
||||
mask WR_DFTHRSH_MAX 0x70
|
||||
count 4
|
||||
}
|
||||
|
||||
register SG_CACHE_PRE {
|
||||
@ -1287,6 +1320,7 @@ scratch_ram {
|
||||
ULTRA_ENB {
|
||||
alias CMDSIZE_TABLE
|
||||
size 2
|
||||
count 2
|
||||
}
|
||||
/*
|
||||
* Bit vector of targets that have disconnection disabled as set by
|
||||
@ -1296,6 +1330,7 @@ scratch_ram {
|
||||
*/
|
||||
DISC_DSB {
|
||||
size 2
|
||||
count 6
|
||||
}
|
||||
CMDSIZE_TABLE_TAIL {
|
||||
size 4
|
||||
@ -1323,6 +1358,7 @@ scratch_ram {
|
||||
/* Parameters for DMA Logic */
|
||||
DMAPARAMS {
|
||||
size 1
|
||||
count 12
|
||||
field PRELOADEN 0x80
|
||||
field WIDEODD 0x40
|
||||
field SCSIEN 0x20
|
||||
@ -1436,11 +1472,12 @@ scratch_ram {
|
||||
KERNEL_TQINPOS {
|
||||
size 1
|
||||
}
|
||||
TQINPOS {
|
||||
TQINPOS {
|
||||
size 1
|
||||
}
|
||||
ARG_1 {
|
||||
size 1
|
||||
count 1
|
||||
mask SEND_MSG 0x80
|
||||
mask SEND_SENSE 0x40
|
||||
mask SEND_REJ 0x20
|
||||
@ -1495,6 +1532,7 @@ scratch_ram {
|
||||
size 1
|
||||
field HA_274_EXTENDED_TRANS 0x01
|
||||
alias INITIATOR_TAG
|
||||
count 1
|
||||
}
|
||||
|
||||
SEQ_FLAGS2 {
|
||||
@ -1518,6 +1556,7 @@ scratch_ram {
|
||||
*/
|
||||
SCSICONF {
|
||||
size 1
|
||||
count 12
|
||||
field TERM_ENB 0x80
|
||||
field RESET_SCSI 0x40
|
||||
field ENSPCHK 0x20
|
||||
@ -1527,16 +1566,19 @@ scratch_ram {
|
||||
INTDEF {
|
||||
address 0x05c
|
||||
size 1
|
||||
count 1
|
||||
field EDGE_TRIG 0x80
|
||||
mask VECTOR 0x0f
|
||||
}
|
||||
HOSTCONF {
|
||||
address 0x05d
|
||||
size 1
|
||||
count 1
|
||||
}
|
||||
HA_274_BIOSCTRL {
|
||||
address 0x05f
|
||||
size 1
|
||||
count 1
|
||||
mask BIOSMODE 0x30
|
||||
mask BIOSDISABLED 0x30
|
||||
field CHANNEL_B_PRIMARY 0x08
|
||||
@ -1552,6 +1594,7 @@ scratch_ram {
|
||||
*/
|
||||
TARG_OFFSET {
|
||||
size 16
|
||||
count 1
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,16 +84,16 @@ struct seeprom_cmd {
|
||||
};
|
||||
|
||||
/* Short opcodes for the c46 */
|
||||
static struct seeprom_cmd seeprom_ewen = {9, {1, 0, 0, 1, 1, 0, 0, 0, 0}};
|
||||
static struct seeprom_cmd seeprom_ewds = {9, {1, 0, 0, 0, 0, 0, 0, 0, 0}};
|
||||
static const struct seeprom_cmd seeprom_ewen = {9, {1, 0, 0, 1, 1, 0, 0, 0, 0}};
|
||||
static const struct seeprom_cmd seeprom_ewds = {9, {1, 0, 0, 0, 0, 0, 0, 0, 0}};
|
||||
|
||||
/* Long opcodes for the C56/C66 */
|
||||
static struct seeprom_cmd seeprom_long_ewen = {11, {1, 0, 0, 1, 1, 0, 0, 0, 0}};
|
||||
static struct seeprom_cmd seeprom_long_ewds = {11, {1, 0, 0, 0, 0, 0, 0, 0, 0}};
|
||||
static const struct seeprom_cmd seeprom_long_ewen = {11, {1, 0, 0, 1, 1, 0, 0, 0, 0}};
|
||||
static const struct seeprom_cmd seeprom_long_ewds = {11, {1, 0, 0, 0, 0, 0, 0, 0, 0}};
|
||||
|
||||
/* Common opcodes */
|
||||
static struct seeprom_cmd seeprom_write = {3, {1, 0, 1}};
|
||||
static struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
|
||||
static const struct seeprom_cmd seeprom_write = {3, {1, 0, 1}};
|
||||
static const struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
|
||||
|
||||
/*
|
||||
* Wait for the SEERDY to go high; about 800 ns.
|
||||
@ -108,7 +108,7 @@ static struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
|
||||
* Send a START condition and the given command
|
||||
*/
|
||||
static void
|
||||
send_seeprom_cmd(struct seeprom_descriptor *sd, struct seeprom_cmd *cmd)
|
||||
send_seeprom_cmd(struct seeprom_descriptor *sd, const struct seeprom_cmd *cmd)
|
||||
{
|
||||
uint8_t temp;
|
||||
int i = 0;
|
||||
@ -227,7 +227,7 @@ int
|
||||
ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf,
|
||||
u_int start_addr, u_int count)
|
||||
{
|
||||
struct seeprom_cmd *ewen, *ewds;
|
||||
const struct seeprom_cmd *ewen, *ewds;
|
||||
uint16_t v;
|
||||
uint8_t temp;
|
||||
int i, k;
|
||||
|
@ -51,8 +51,7 @@
|
||||
#endif
|
||||
|
||||
/***************************** Lookup Tables **********************************/
|
||||
char *ahc_chip_names[] =
|
||||
{
|
||||
static const char *const ahc_chip_names[] = {
|
||||
"NONE",
|
||||
"aic7770",
|
||||
"aic7850",
|
||||
@ -75,10 +74,10 @@ static const u_int num_chip_names = ARRAY_SIZE(ahc_chip_names);
|
||||
*/
|
||||
struct ahc_hard_error_entry {
|
||||
uint8_t errno;
|
||||
char *errmesg;
|
||||
const char *errmesg;
|
||||
};
|
||||
|
||||
static struct ahc_hard_error_entry ahc_hard_errors[] = {
|
||||
static const struct ahc_hard_error_entry ahc_hard_errors[] = {
|
||||
{ ILLHADDR, "Illegal Host Access" },
|
||||
{ ILLSADDR, "Illegal Sequencer Address referrenced" },
|
||||
{ ILLOPCODE, "Illegal Opcode in sequencer program" },
|
||||
@ -90,7 +89,7 @@ static struct ahc_hard_error_entry ahc_hard_errors[] = {
|
||||
};
|
||||
static const u_int num_errors = ARRAY_SIZE(ahc_hard_errors);
|
||||
|
||||
static struct ahc_phase_table_entry ahc_phase_table[] =
|
||||
static const struct ahc_phase_table_entry ahc_phase_table[] =
|
||||
{
|
||||
{ P_DATAOUT, MSG_NOOP, "in Data-out phase" },
|
||||
{ P_DATAIN, MSG_INITIATOR_DET_ERR, "in Data-in phase" },
|
||||
@ -115,7 +114,7 @@ static const u_int num_phases = ARRAY_SIZE(ahc_phase_table) - 1;
|
||||
* Provides a mapping of tranfer periods in ns to the proper value to
|
||||
* stick in the scsixfer reg.
|
||||
*/
|
||||
static struct ahc_syncrate ahc_syncrates[] =
|
||||
static const struct ahc_syncrate ahc_syncrates[] =
|
||||
{
|
||||
/* ultra2 fast/ultra period rate */
|
||||
{ 0x42, 0x000, 9, "80.0" },
|
||||
@ -148,7 +147,7 @@ static struct ahc_tmode_tstate*
|
||||
static void ahc_free_tstate(struct ahc_softc *ahc,
|
||||
u_int scsi_id, char channel, int force);
|
||||
#endif
|
||||
static struct ahc_syncrate*
|
||||
static const struct ahc_syncrate*
|
||||
ahc_devlimited_syncrate(struct ahc_softc *ahc,
|
||||
struct ahc_initiator_tinfo *,
|
||||
u_int *period,
|
||||
@ -204,9 +203,9 @@ static void ahc_setup_target_msgin(struct ahc_softc *ahc,
|
||||
#endif
|
||||
|
||||
static bus_dmamap_callback_t ahc_dmamap_cb;
|
||||
static void ahc_build_free_scb_list(struct ahc_softc *ahc);
|
||||
static int ahc_init_scbdata(struct ahc_softc *ahc);
|
||||
static void ahc_fini_scbdata(struct ahc_softc *ahc);
|
||||
static void ahc_build_free_scb_list(struct ahc_softc *ahc);
|
||||
static int ahc_init_scbdata(struct ahc_softc *ahc);
|
||||
static void ahc_fini_scbdata(struct ahc_softc *ahc);
|
||||
static void ahc_qinfifo_requeue(struct ahc_softc *ahc,
|
||||
struct scb *prev_scb,
|
||||
struct scb *scb);
|
||||
@ -222,7 +221,7 @@ static void ahc_dumpseq(struct ahc_softc *ahc);
|
||||
#endif
|
||||
static int ahc_loadseq(struct ahc_softc *ahc);
|
||||
static int ahc_check_patch(struct ahc_softc *ahc,
|
||||
struct patch **start_patch,
|
||||
const struct patch **start_patch,
|
||||
u_int start_instr, u_int *skip_addr);
|
||||
static void ahc_download_instr(struct ahc_softc *ahc,
|
||||
u_int instrptr, uint8_t *dconsts);
|
||||
@ -237,11 +236,582 @@ static void ahc_update_scsiid(struct ahc_softc *ahc,
|
||||
static int ahc_handle_target_cmd(struct ahc_softc *ahc,
|
||||
struct target_cmd *cmd);
|
||||
#endif
|
||||
|
||||
static u_int ahc_index_busy_tcl(struct ahc_softc *ahc, u_int tcl);
|
||||
static void ahc_unbusy_tcl(struct ahc_softc *ahc, u_int tcl);
|
||||
static void ahc_busy_tcl(struct ahc_softc *ahc,
|
||||
u_int tcl, u_int busyid);
|
||||
|
||||
/************************** SCB and SCB queue management **********************/
|
||||
static void ahc_run_untagged_queues(struct ahc_softc *ahc);
|
||||
static void ahc_run_untagged_queue(struct ahc_softc *ahc,
|
||||
struct scb_tailq *queue);
|
||||
|
||||
/****************************** Initialization ********************************/
|
||||
static void ahc_alloc_scbs(struct ahc_softc *ahc);
|
||||
static void ahc_shutdown(void *arg);
|
||||
|
||||
/*************************** Interrupt Services *******************************/
|
||||
static void ahc_clear_intstat(struct ahc_softc *ahc);
|
||||
static void ahc_run_qoutfifo(struct ahc_softc *ahc);
|
||||
#ifdef AHC_TARGET_MODE
|
||||
static void ahc_run_tqinfifo(struct ahc_softc *ahc, int paused);
|
||||
#endif
|
||||
static void ahc_handle_brkadrint(struct ahc_softc *ahc);
|
||||
static void ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat);
|
||||
static void ahc_handle_scsiint(struct ahc_softc *ahc,
|
||||
u_int intstat);
|
||||
static void ahc_clear_critical_section(struct ahc_softc *ahc);
|
||||
|
||||
/***************************** Error Recovery *********************************/
|
||||
static void ahc_freeze_devq(struct ahc_softc *ahc, struct scb *scb);
|
||||
static int ahc_abort_scbs(struct ahc_softc *ahc, int target,
|
||||
char channel, int lun, u_int tag,
|
||||
role_t role, uint32_t status);
|
||||
static void ahc_calc_residual(struct ahc_softc *ahc,
|
||||
struct scb *scb);
|
||||
|
||||
/*********************** Untagged Transaction Routines ************************/
|
||||
static inline void ahc_freeze_untagged_queues(struct ahc_softc *ahc);
|
||||
static inline void ahc_release_untagged_queues(struct ahc_softc *ahc);
|
||||
|
||||
/*
|
||||
* Block our completion routine from starting the next untagged
|
||||
* transaction for this target or target lun.
|
||||
*/
|
||||
static inline void
|
||||
ahc_freeze_untagged_queues(struct ahc_softc *ahc)
|
||||
{
|
||||
if ((ahc->flags & AHC_SCB_BTT) == 0)
|
||||
ahc->untagged_queue_lock++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow the next untagged transaction for this target or target lun
|
||||
* to be executed. We use a counting semaphore to allow the lock
|
||||
* to be acquired recursively. Once the count drops to zero, the
|
||||
* transaction queues will be run.
|
||||
*/
|
||||
static inline void
|
||||
ahc_release_untagged_queues(struct ahc_softc *ahc)
|
||||
{
|
||||
if ((ahc->flags & AHC_SCB_BTT) == 0) {
|
||||
ahc->untagged_queue_lock--;
|
||||
if (ahc->untagged_queue_lock == 0)
|
||||
ahc_run_untagged_queues(ahc);
|
||||
}
|
||||
}
|
||||
|
||||
/************************* Sequencer Execution Control ************************/
|
||||
/*
|
||||
* Work around any chip bugs related to halting sequencer execution.
|
||||
* On Ultra2 controllers, we must clear the CIOBUS stretch signal by
|
||||
* reading a register that will set this signal and deassert it.
|
||||
* Without this workaround, if the chip is paused, by an interrupt or
|
||||
* manual pause while accessing scb ram, accesses to certain registers
|
||||
* will hang the system (infinite pci retries).
|
||||
*/
|
||||
static void
|
||||
ahc_pause_bug_fix(struct ahc_softc *ahc)
|
||||
{
|
||||
if ((ahc->features & AHC_ULTRA2) != 0)
|
||||
(void)ahc_inb(ahc, CCSCBCTL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine whether the sequencer has halted code execution.
|
||||
* Returns non-zero status if the sequencer is stopped.
|
||||
*/
|
||||
int
|
||||
ahc_is_paused(struct ahc_softc *ahc)
|
||||
{
|
||||
return ((ahc_inb(ahc, HCNTRL) & PAUSE) != 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Request that the sequencer stop and wait, indefinitely, for it
|
||||
* to stop. The sequencer will only acknowledge that it is paused
|
||||
* once it has reached an instruction boundary and PAUSEDIS is
|
||||
* cleared in the SEQCTL register. The sequencer may use PAUSEDIS
|
||||
* for critical sections.
|
||||
*/
|
||||
void
|
||||
ahc_pause(struct ahc_softc *ahc)
|
||||
{
|
||||
ahc_outb(ahc, HCNTRL, ahc->pause);
|
||||
|
||||
/*
|
||||
* Since the sequencer can disable pausing in a critical section, we
|
||||
* must loop until it actually stops.
|
||||
*/
|
||||
while (ahc_is_paused(ahc) == 0)
|
||||
;
|
||||
|
||||
ahc_pause_bug_fix(ahc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow the sequencer to continue program execution.
|
||||
* We check here to ensure that no additional interrupt
|
||||
* sources that would cause the sequencer to halt have been
|
||||
* asserted. If, for example, a SCSI bus reset is detected
|
||||
* while we are fielding a different, pausing, interrupt type,
|
||||
* we don't want to release the sequencer before going back
|
||||
* into our interrupt handler and dealing with this new
|
||||
* condition.
|
||||
*/
|
||||
void
|
||||
ahc_unpause(struct ahc_softc *ahc)
|
||||
{
|
||||
if ((ahc_inb(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0)
|
||||
ahc_outb(ahc, HCNTRL, ahc->unpause);
|
||||
}
|
||||
|
||||
/************************** Memory mapping routines ***************************/
|
||||
static struct ahc_dma_seg *
|
||||
ahc_sg_bus_to_virt(struct scb *scb, uint32_t sg_busaddr)
|
||||
{
|
||||
int sg_index;
|
||||
|
||||
sg_index = (sg_busaddr - scb->sg_list_phys)/sizeof(struct ahc_dma_seg);
|
||||
/* sg_list_phys points to entry 1, not 0 */
|
||||
sg_index++;
|
||||
|
||||
return (&scb->sg_list[sg_index]);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
ahc_sg_virt_to_bus(struct scb *scb, struct ahc_dma_seg *sg)
|
||||
{
|
||||
int sg_index;
|
||||
|
||||
/* sg_list_phys points to entry 1, not 0 */
|
||||
sg_index = sg - &scb->sg_list[1];
|
||||
|
||||
return (scb->sg_list_phys + (sg_index * sizeof(*scb->sg_list)));
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index)
|
||||
{
|
||||
return (ahc->scb_data->hscb_busaddr
|
||||
+ (sizeof(struct hardware_scb) * index));
|
||||
}
|
||||
|
||||
static void
|
||||
ahc_sync_scb(struct ahc_softc *ahc, struct scb *scb, int op)
|
||||
{
|
||||
ahc_dmamap_sync(ahc, ahc->scb_data->hscb_dmat,
|
||||
ahc->scb_data->hscb_dmamap,
|
||||
/*offset*/(scb->hscb - ahc->hscbs) * sizeof(*scb->hscb),
|
||||
/*len*/sizeof(*scb->hscb), op);
|
||||
}
|
||||
|
||||
void
|
||||
ahc_sync_sglist(struct ahc_softc *ahc, struct scb *scb, int op)
|
||||
{
|
||||
if (scb->sg_count == 0)
|
||||
return;
|
||||
|
||||
ahc_dmamap_sync(ahc, ahc->scb_data->sg_dmat, scb->sg_map->sg_dmamap,
|
||||
/*offset*/(scb->sg_list - scb->sg_map->sg_vaddr)
|
||||
* sizeof(struct ahc_dma_seg),
|
||||
/*len*/sizeof(struct ahc_dma_seg) * scb->sg_count, op);
|
||||
}
|
||||
|
||||
#ifdef AHC_TARGET_MODE
|
||||
static uint32_t
|
||||
ahc_targetcmd_offset(struct ahc_softc *ahc, u_int index)
|
||||
{
|
||||
return (((uint8_t *)&ahc->targetcmds[index]) - ahc->qoutfifo);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*********************** Miscelaneous Support Functions ***********************/
|
||||
/*
|
||||
* Determine whether the sequencer reported a residual
|
||||
* for this SCB/transaction.
|
||||
*/
|
||||
static void
|
||||
ahc_update_residual(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
uint32_t sgptr;
|
||||
|
||||
sgptr = ahc_le32toh(scb->hscb->sgptr);
|
||||
if ((sgptr & SG_RESID_VALID) != 0)
|
||||
ahc_calc_residual(ahc, scb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return pointers to the transfer negotiation information
|
||||
* for the specified our_id/remote_id pair.
|
||||
*/
|
||||
struct ahc_initiator_tinfo *
|
||||
ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id,
|
||||
u_int remote_id, struct ahc_tmode_tstate **tstate)
|
||||
{
|
||||
/*
|
||||
* Transfer data structures are stored from the perspective
|
||||
* of the target role. Since the parameters for a connection
|
||||
* in the initiator role to a given target are the same as
|
||||
* when the roles are reversed, we pretend we are the target.
|
||||
*/
|
||||
if (channel == 'B')
|
||||
our_id += 8;
|
||||
*tstate = ahc->enabled_targets[our_id];
|
||||
return (&(*tstate)->transinfo[remote_id]);
|
||||
}
|
||||
|
||||
uint16_t
|
||||
ahc_inw(struct ahc_softc *ahc, u_int port)
|
||||
{
|
||||
uint16_t r = ahc_inb(ahc, port+1) << 8;
|
||||
return r | ahc_inb(ahc, port);
|
||||
}
|
||||
|
||||
void
|
||||
ahc_outw(struct ahc_softc *ahc, u_int port, u_int value)
|
||||
{
|
||||
ahc_outb(ahc, port, value & 0xFF);
|
||||
ahc_outb(ahc, port+1, (value >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ahc_inl(struct ahc_softc *ahc, u_int port)
|
||||
{
|
||||
return ((ahc_inb(ahc, port))
|
||||
| (ahc_inb(ahc, port+1) << 8)
|
||||
| (ahc_inb(ahc, port+2) << 16)
|
||||
| (ahc_inb(ahc, port+3) << 24));
|
||||
}
|
||||
|
||||
void
|
||||
ahc_outl(struct ahc_softc *ahc, u_int port, uint32_t value)
|
||||
{
|
||||
ahc_outb(ahc, port, (value) & 0xFF);
|
||||
ahc_outb(ahc, port+1, ((value) >> 8) & 0xFF);
|
||||
ahc_outb(ahc, port+2, ((value) >> 16) & 0xFF);
|
||||
ahc_outb(ahc, port+3, ((value) >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
ahc_inq(struct ahc_softc *ahc, u_int port)
|
||||
{
|
||||
return ((ahc_inb(ahc, port))
|
||||
| (ahc_inb(ahc, port+1) << 8)
|
||||
| (ahc_inb(ahc, port+2) << 16)
|
||||
| (ahc_inb(ahc, port+3) << 24)
|
||||
| (((uint64_t)ahc_inb(ahc, port+4)) << 32)
|
||||
| (((uint64_t)ahc_inb(ahc, port+5)) << 40)
|
||||
| (((uint64_t)ahc_inb(ahc, port+6)) << 48)
|
||||
| (((uint64_t)ahc_inb(ahc, port+7)) << 56));
|
||||
}
|
||||
|
||||
void
|
||||
ahc_outq(struct ahc_softc *ahc, u_int port, uint64_t value)
|
||||
{
|
||||
ahc_outb(ahc, port, value & 0xFF);
|
||||
ahc_outb(ahc, port+1, (value >> 8) & 0xFF);
|
||||
ahc_outb(ahc, port+2, (value >> 16) & 0xFF);
|
||||
ahc_outb(ahc, port+3, (value >> 24) & 0xFF);
|
||||
ahc_outb(ahc, port+4, (value >> 32) & 0xFF);
|
||||
ahc_outb(ahc, port+5, (value >> 40) & 0xFF);
|
||||
ahc_outb(ahc, port+6, (value >> 48) & 0xFF);
|
||||
ahc_outb(ahc, port+7, (value >> 56) & 0xFF);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a free scb. If there are none, see if we can allocate a new SCB.
|
||||
*/
|
||||
struct scb *
|
||||
ahc_get_scb(struct ahc_softc *ahc)
|
||||
{
|
||||
struct scb *scb;
|
||||
|
||||
if ((scb = SLIST_FIRST(&ahc->scb_data->free_scbs)) == NULL) {
|
||||
ahc_alloc_scbs(ahc);
|
||||
scb = SLIST_FIRST(&ahc->scb_data->free_scbs);
|
||||
if (scb == NULL)
|
||||
return (NULL);
|
||||
}
|
||||
SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links.sle);
|
||||
return (scb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return an SCB resource to the free list.
|
||||
*/
|
||||
void
|
||||
ahc_free_scb(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
struct hardware_scb *hscb;
|
||||
|
||||
hscb = scb->hscb;
|
||||
/* Clean up for the next user */
|
||||
ahc->scb_data->scbindex[hscb->tag] = NULL;
|
||||
scb->flags = SCB_FREE;
|
||||
hscb->control = 0;
|
||||
|
||||
SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, scb, links.sle);
|
||||
|
||||
/* Notify the OSM that a resource is now available. */
|
||||
ahc_platform_scb_free(ahc, scb);
|
||||
}
|
||||
|
||||
struct scb *
|
||||
ahc_lookup_scb(struct ahc_softc *ahc, u_int tag)
|
||||
{
|
||||
struct scb* scb;
|
||||
|
||||
scb = ahc->scb_data->scbindex[tag];
|
||||
if (scb != NULL)
|
||||
ahc_sync_scb(ahc, scb,
|
||||
BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
|
||||
return (scb);
|
||||
}
|
||||
|
||||
static void
|
||||
ahc_swap_with_next_hscb(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
struct hardware_scb *q_hscb;
|
||||
u_int saved_tag;
|
||||
|
||||
/*
|
||||
* Our queuing method is a bit tricky. The card
|
||||
* knows in advance which HSCB to download, and we
|
||||
* can't disappoint it. To achieve this, the next
|
||||
* SCB to download is saved off in ahc->next_queued_scb.
|
||||
* When we are called to queue "an arbitrary scb",
|
||||
* we copy the contents of the incoming HSCB to the one
|
||||
* the sequencer knows about, swap HSCB pointers and
|
||||
* finally assign the SCB to the tag indexed location
|
||||
* in the scb_array. This makes sure that we can still
|
||||
* locate the correct SCB by SCB_TAG.
|
||||
*/
|
||||
q_hscb = ahc->next_queued_scb->hscb;
|
||||
saved_tag = q_hscb->tag;
|
||||
memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb));
|
||||
if ((scb->flags & SCB_CDB32_PTR) != 0) {
|
||||
q_hscb->shared_data.cdb_ptr =
|
||||
ahc_htole32(ahc_hscb_busaddr(ahc, q_hscb->tag)
|
||||
+ offsetof(struct hardware_scb, cdb32));
|
||||
}
|
||||
q_hscb->tag = saved_tag;
|
||||
q_hscb->next = scb->hscb->tag;
|
||||
|
||||
/* Now swap HSCB pointers. */
|
||||
ahc->next_queued_scb->hscb = scb->hscb;
|
||||
scb->hscb = q_hscb;
|
||||
|
||||
/* Now define the mapping from tag to SCB in the scbindex */
|
||||
ahc->scb_data->scbindex[scb->hscb->tag] = scb;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tell the sequencer about a new transaction to execute.
|
||||
*/
|
||||
void
|
||||
ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
ahc_swap_with_next_hscb(ahc, scb);
|
||||
|
||||
if (scb->hscb->tag == SCB_LIST_NULL
|
||||
|| scb->hscb->next == SCB_LIST_NULL)
|
||||
panic("Attempt to queue invalid SCB tag %x:%x\n",
|
||||
scb->hscb->tag, scb->hscb->next);
|
||||
|
||||
/*
|
||||
* Setup data "oddness".
|
||||
*/
|
||||
scb->hscb->lun &= LID;
|
||||
if (ahc_get_transfer_length(scb) & 0x1)
|
||||
scb->hscb->lun |= SCB_XFERLEN_ODD;
|
||||
|
||||
/*
|
||||
* Keep a history of SCBs we've downloaded in the qinfifo.
|
||||
*/
|
||||
ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag;
|
||||
|
||||
/*
|
||||
* Make sure our data is consistent from the
|
||||
* perspective of the adapter.
|
||||
*/
|
||||
ahc_sync_scb(ahc, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
|
||||
|
||||
/* Tell the adapter about the newly queued SCB */
|
||||
if ((ahc->features & AHC_QUEUE_REGS) != 0) {
|
||||
ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext);
|
||||
} else {
|
||||
if ((ahc->features & AHC_AUTOPAUSE) == 0)
|
||||
ahc_pause(ahc);
|
||||
ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext);
|
||||
if ((ahc->features & AHC_AUTOPAUSE) == 0)
|
||||
ahc_unpause(ahc);
|
||||
}
|
||||
}
|
||||
|
||||
struct scsi_sense_data *
|
||||
ahc_get_sense_buf(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
int offset;
|
||||
|
||||
offset = scb - ahc->scb_data->scbarray;
|
||||
return (&ahc->scb_data->sense[offset]);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
ahc_get_sense_bufaddr(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
int offset;
|
||||
|
||||
offset = scb - ahc->scb_data->scbarray;
|
||||
return (ahc->scb_data->sense_busaddr
|
||||
+ (offset * sizeof(struct scsi_sense_data)));
|
||||
}
|
||||
|
||||
/************************** Interrupt Processing ******************************/
|
||||
static void
|
||||
ahc_sync_qoutfifo(struct ahc_softc *ahc, int op)
|
||||
{
|
||||
ahc_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap,
|
||||
/*offset*/0, /*len*/256, op);
|
||||
}
|
||||
|
||||
static void
|
||||
ahc_sync_tqinfifo(struct ahc_softc *ahc, int op)
|
||||
{
|
||||
#ifdef AHC_TARGET_MODE
|
||||
if ((ahc->flags & AHC_TARGETROLE) != 0) {
|
||||
ahc_dmamap_sync(ahc, ahc->shared_data_dmat,
|
||||
ahc->shared_data_dmamap,
|
||||
ahc_targetcmd_offset(ahc, 0),
|
||||
sizeof(struct target_cmd) * AHC_TMODE_CMDS,
|
||||
op);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* See if the firmware has posted any completed commands
|
||||
* into our in-core command complete fifos.
|
||||
*/
|
||||
#define AHC_RUN_QOUTFIFO 0x1
|
||||
#define AHC_RUN_TQINFIFO 0x2
|
||||
static u_int
|
||||
ahc_check_cmdcmpltqueues(struct ahc_softc *ahc)
|
||||
{
|
||||
u_int retval;
|
||||
|
||||
retval = 0;
|
||||
ahc_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap,
|
||||
/*offset*/ahc->qoutfifonext, /*len*/1,
|
||||
BUS_DMASYNC_POSTREAD);
|
||||
if (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL)
|
||||
retval |= AHC_RUN_QOUTFIFO;
|
||||
#ifdef AHC_TARGET_MODE
|
||||
if ((ahc->flags & AHC_TARGETROLE) != 0
|
||||
&& (ahc->flags & AHC_TQINFIFO_BLOCKED) == 0) {
|
||||
ahc_dmamap_sync(ahc, ahc->shared_data_dmat,
|
||||
ahc->shared_data_dmamap,
|
||||
ahc_targetcmd_offset(ahc, ahc->tqinfifofnext),
|
||||
/*len*/sizeof(struct target_cmd),
|
||||
BUS_DMASYNC_POSTREAD);
|
||||
if (ahc->targetcmds[ahc->tqinfifonext].cmd_valid != 0)
|
||||
retval |= AHC_RUN_TQINFIFO;
|
||||
}
|
||||
#endif
|
||||
return (retval);
|
||||
}
|
||||
|
||||
/*
|
||||
* Catch an interrupt from the adapter
|
||||
*/
|
||||
int
|
||||
ahc_intr(struct ahc_softc *ahc)
|
||||
{
|
||||
u_int intstat;
|
||||
|
||||
if ((ahc->pause & INTEN) == 0) {
|
||||
/*
|
||||
* Our interrupt is not enabled on the chip
|
||||
* and may be disabled for re-entrancy reasons,
|
||||
* so just return. This is likely just a shared
|
||||
* interrupt.
|
||||
*/
|
||||
return (0);
|
||||
}
|
||||
/*
|
||||
* Instead of directly reading the interrupt status register,
|
||||
* infer the cause of the interrupt by checking our in-core
|
||||
* completion queues. This avoids a costly PCI bus read in
|
||||
* most cases.
|
||||
*/
|
||||
if ((ahc->flags & (AHC_ALL_INTERRUPTS|AHC_EDGE_INTERRUPT)) == 0
|
||||
&& (ahc_check_cmdcmpltqueues(ahc) != 0))
|
||||
intstat = CMDCMPLT;
|
||||
else {
|
||||
intstat = ahc_inb(ahc, INTSTAT);
|
||||
}
|
||||
|
||||
if ((intstat & INT_PEND) == 0) {
|
||||
#if AHC_PCI_CONFIG > 0
|
||||
if (ahc->unsolicited_ints > 500) {
|
||||
ahc->unsolicited_ints = 0;
|
||||
if ((ahc->chip & AHC_PCI) != 0
|
||||
&& (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0)
|
||||
ahc->bus_intr(ahc);
|
||||
}
|
||||
#endif
|
||||
ahc->unsolicited_ints++;
|
||||
return (0);
|
||||
}
|
||||
ahc->unsolicited_ints = 0;
|
||||
|
||||
if (intstat & CMDCMPLT) {
|
||||
ahc_outb(ahc, CLRINT, CLRCMDINT);
|
||||
|
||||
/*
|
||||
* Ensure that the chip sees that we've cleared
|
||||
* this interrupt before we walk the output fifo.
|
||||
* Otherwise, we may, due to posted bus writes,
|
||||
* clear the interrupt after we finish the scan,
|
||||
* and after the sequencer has added new entries
|
||||
* and asserted the interrupt again.
|
||||
*/
|
||||
ahc_flush_device_writes(ahc);
|
||||
ahc_run_qoutfifo(ahc);
|
||||
#ifdef AHC_TARGET_MODE
|
||||
if ((ahc->flags & AHC_TARGETROLE) != 0)
|
||||
ahc_run_tqinfifo(ahc, /*paused*/FALSE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle statuses that may invalidate our cached
|
||||
* copy of INTSTAT separately.
|
||||
*/
|
||||
if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0) {
|
||||
/* Hot eject. Do nothing */
|
||||
} else if (intstat & BRKADRINT) {
|
||||
ahc_handle_brkadrint(ahc);
|
||||
} else if ((intstat & (SEQINT|SCSIINT)) != 0) {
|
||||
|
||||
ahc_pause_bug_fix(ahc);
|
||||
|
||||
if ((intstat & SEQINT) != 0)
|
||||
ahc_handle_seqint(ahc, intstat);
|
||||
|
||||
if ((intstat & SCSIINT) != 0)
|
||||
ahc_handle_scsiint(ahc, intstat);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
/************************* Sequencer Execution Control ************************/
|
||||
/*
|
||||
* Restart the sequencer program from address zero
|
||||
*/
|
||||
void
|
||||
static void
|
||||
ahc_restart(struct ahc_softc *ahc)
|
||||
{
|
||||
|
||||
@ -302,7 +872,7 @@ ahc_restart(struct ahc_softc *ahc)
|
||||
}
|
||||
|
||||
/************************* Input/Output Queues ********************************/
|
||||
void
|
||||
static void
|
||||
ahc_run_qoutfifo(struct ahc_softc *ahc)
|
||||
{
|
||||
struct scb *scb;
|
||||
@ -349,7 +919,7 @@ ahc_run_qoutfifo(struct ahc_softc *ahc)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
ahc_run_untagged_queues(struct ahc_softc *ahc)
|
||||
{
|
||||
int i;
|
||||
@ -358,7 +928,7 @@ ahc_run_untagged_queues(struct ahc_softc *ahc)
|
||||
ahc_run_untagged_queue(ahc, &ahc->untagged_queues[i]);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
ahc_run_untagged_queue(struct ahc_softc *ahc, struct scb_tailq *queue)
|
||||
{
|
||||
struct scb *scb;
|
||||
@ -374,7 +944,7 @@ ahc_run_untagged_queue(struct ahc_softc *ahc, struct scb_tailq *queue)
|
||||
}
|
||||
|
||||
/************************* Interrupt Handling *********************************/
|
||||
void
|
||||
static void
|
||||
ahc_handle_brkadrint(struct ahc_softc *ahc)
|
||||
{
|
||||
/*
|
||||
@ -403,7 +973,7 @@ ahc_handle_brkadrint(struct ahc_softc *ahc)
|
||||
ahc_shutdown(ahc);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
|
||||
{
|
||||
struct scb *scb;
|
||||
@ -954,7 +1524,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
|
||||
ahc_unpause(ahc);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
|
||||
{
|
||||
u_int scb_index;
|
||||
@ -1407,7 +1977,7 @@ ahc_force_renegotiation(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
|
||||
}
|
||||
|
||||
#define AHC_MAX_STEPS 2000
|
||||
void
|
||||
static void
|
||||
ahc_clear_critical_section(struct ahc_softc *ahc)
|
||||
{
|
||||
int stepping;
|
||||
@ -1500,7 +2070,7 @@ ahc_clear_critical_section(struct ahc_softc *ahc)
|
||||
/*
|
||||
* Clear any pending interrupt status.
|
||||
*/
|
||||
void
|
||||
static void
|
||||
ahc_clear_intstat(struct ahc_softc *ahc)
|
||||
{
|
||||
/* Clear any interrupt conditions this may have caused */
|
||||
@ -1519,7 +2089,8 @@ ahc_clear_intstat(struct ahc_softc *ahc)
|
||||
uint32_t ahc_debug = AHC_DEBUG_OPTS;
|
||||
#endif
|
||||
|
||||
void
|
||||
#if 0 /* unused */
|
||||
static void
|
||||
ahc_print_scb(struct scb *scb)
|
||||
{
|
||||
int i;
|
||||
@ -1551,6 +2122,7 @@ ahc_print_scb(struct scb *scb)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/************************* Transfer Negotiation *******************************/
|
||||
/*
|
||||
@ -1634,7 +2206,7 @@ ahc_free_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel, int force)
|
||||
* by the capabilities of the bus connectivity of and sync settings for
|
||||
* the target.
|
||||
*/
|
||||
struct ahc_syncrate *
|
||||
const struct ahc_syncrate *
|
||||
ahc_devlimited_syncrate(struct ahc_softc *ahc,
|
||||
struct ahc_initiator_tinfo *tinfo,
|
||||
u_int *period, u_int *ppr_options, role_t role)
|
||||
@ -1689,11 +2261,11 @@ ahc_devlimited_syncrate(struct ahc_softc *ahc,
|
||||
* Return the period and offset that should be sent to the target
|
||||
* if this was the beginning of an SDTR.
|
||||
*/
|
||||
struct ahc_syncrate *
|
||||
const struct ahc_syncrate *
|
||||
ahc_find_syncrate(struct ahc_softc *ahc, u_int *period,
|
||||
u_int *ppr_options, u_int maxsync)
|
||||
{
|
||||
struct ahc_syncrate *syncrate;
|
||||
const struct ahc_syncrate *syncrate;
|
||||
|
||||
if ((ahc->features & AHC_DT) == 0)
|
||||
*ppr_options &= ~MSG_EXT_PPR_DT_REQ;
|
||||
@ -1768,7 +2340,7 @@ ahc_find_syncrate(struct ahc_softc *ahc, u_int *period,
|
||||
u_int
|
||||
ahc_find_period(struct ahc_softc *ahc, u_int scsirate, u_int maxsync)
|
||||
{
|
||||
struct ahc_syncrate *syncrate;
|
||||
const struct ahc_syncrate *syncrate;
|
||||
|
||||
if ((ahc->features & AHC_ULTRA2) != 0)
|
||||
scsirate &= SXFR_ULTRA2;
|
||||
@ -1806,10 +2378,10 @@ ahc_find_period(struct ahc_softc *ahc, u_int scsirate, u_int maxsync)
|
||||
* Truncate the given synchronous offset to a value the
|
||||
* current adapter type and syncrate are capable of.
|
||||
*/
|
||||
void
|
||||
static void
|
||||
ahc_validate_offset(struct ahc_softc *ahc,
|
||||
struct ahc_initiator_tinfo *tinfo,
|
||||
struct ahc_syncrate *syncrate,
|
||||
const struct ahc_syncrate *syncrate,
|
||||
u_int *offset, int wide, role_t role)
|
||||
{
|
||||
u_int maxoffset;
|
||||
@ -1838,7 +2410,7 @@ ahc_validate_offset(struct ahc_softc *ahc,
|
||||
* Truncate the given transfer width parameter to a value the
|
||||
* current adapter type is capable of.
|
||||
*/
|
||||
void
|
||||
static void
|
||||
ahc_validate_width(struct ahc_softc *ahc, struct ahc_initiator_tinfo *tinfo,
|
||||
u_int *bus_width, role_t role)
|
||||
{
|
||||
@ -1913,7 +2485,7 @@ ahc_update_neg_request(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
|
||||
*/
|
||||
void
|
||||
ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
|
||||
struct ahc_syncrate *syncrate, u_int period,
|
||||
const struct ahc_syncrate *syncrate, u_int period,
|
||||
u_int offset, u_int ppr_options, u_int type, int paused)
|
||||
{
|
||||
struct ahc_initiator_tinfo *tinfo;
|
||||
@ -2220,11 +2792,11 @@ ahc_fetch_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
|
||||
role);
|
||||
}
|
||||
|
||||
struct ahc_phase_table_entry*
|
||||
static const struct ahc_phase_table_entry*
|
||||
ahc_lookup_phase_entry(int phase)
|
||||
{
|
||||
struct ahc_phase_table_entry *entry;
|
||||
struct ahc_phase_table_entry *last_entry;
|
||||
const struct ahc_phase_table_entry *entry;
|
||||
const struct ahc_phase_table_entry *last_entry;
|
||||
|
||||
/*
|
||||
* num_phases doesn't include the default entry which
|
||||
@ -2390,7 +2962,7 @@ ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
|
||||
*/
|
||||
struct ahc_initiator_tinfo *tinfo;
|
||||
struct ahc_tmode_tstate *tstate;
|
||||
struct ahc_syncrate *rate;
|
||||
const struct ahc_syncrate *rate;
|
||||
int dowide;
|
||||
int dosync;
|
||||
int doppr;
|
||||
@ -2655,7 +3227,7 @@ ahc_handle_proto_violation(struct ahc_softc *ahc)
|
||||
*/
|
||||
static void
|
||||
ahc_handle_message_phase(struct ahc_softc *ahc)
|
||||
{
|
||||
{
|
||||
struct ahc_devinfo devinfo;
|
||||
u_int bus_phase;
|
||||
int end_session;
|
||||
@ -3056,7 +3628,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
|
||||
switch (ahc->msgin_buf[2]) {
|
||||
case MSG_EXT_SDTR:
|
||||
{
|
||||
struct ahc_syncrate *syncrate;
|
||||
const struct ahc_syncrate *syncrate;
|
||||
u_int period;
|
||||
u_int ppr_options;
|
||||
u_int offset;
|
||||
@ -3231,7 +3803,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
|
||||
}
|
||||
case MSG_EXT_PPR:
|
||||
{
|
||||
struct ahc_syncrate *syncrate;
|
||||
const struct ahc_syncrate *syncrate;
|
||||
u_int period;
|
||||
u_int offset;
|
||||
u_int bus_width;
|
||||
@ -3984,7 +4556,7 @@ ahc_free(struct ahc_softc *ahc)
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
ahc_shutdown(void *arg)
|
||||
{
|
||||
struct ahc_softc *ahc;
|
||||
@ -4388,7 +4960,7 @@ ahc_fini_scbdata(struct ahc_softc *ahc)
|
||||
free(scb_data->scbarray, M_DEVBUF);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
ahc_alloc_scbs(struct ahc_softc *ahc)
|
||||
{
|
||||
struct scb_data *scb_data;
|
||||
@ -5121,7 +5693,7 @@ ahc_resume(struct ahc_softc *ahc)
|
||||
* Return the untagged transaction id for a given target/channel lun.
|
||||
* Optionally, clear the entry.
|
||||
*/
|
||||
u_int
|
||||
static u_int
|
||||
ahc_index_busy_tcl(struct ahc_softc *ahc, u_int tcl)
|
||||
{
|
||||
u_int scbid;
|
||||
@ -5142,7 +5714,7 @@ ahc_index_busy_tcl(struct ahc_softc *ahc, u_int tcl)
|
||||
return (scbid);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
ahc_unbusy_tcl(struct ahc_softc *ahc, u_int tcl)
|
||||
{
|
||||
u_int target_offset;
|
||||
@ -5160,7 +5732,7 @@ ahc_unbusy_tcl(struct ahc_softc *ahc, u_int tcl)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
ahc_busy_tcl(struct ahc_softc *ahc, u_int tcl, u_int scbid)
|
||||
{
|
||||
u_int target_offset;
|
||||
@ -5215,7 +5787,7 @@ ahc_match_scb(struct ahc_softc *ahc, struct scb *scb, int target,
|
||||
return match;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
ahc_freeze_devq(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
int target;
|
||||
@ -5707,7 +6279,7 @@ ahc_add_curscb_to_free_list(struct ahc_softc *ahc)
|
||||
*/
|
||||
static u_int
|
||||
ahc_rem_wscb(struct ahc_softc *ahc, u_int scbpos, u_int prev)
|
||||
{
|
||||
{
|
||||
u_int curscb, next;
|
||||
|
||||
/*
|
||||
@ -5756,7 +6328,7 @@ ahc_rem_wscb(struct ahc_softc *ahc, u_int scbpos, u_int prev)
|
||||
* been modified from CAM_REQ_INPROG. This routine assumes that the sequencer
|
||||
* is paused before it is called.
|
||||
*/
|
||||
int
|
||||
static int
|
||||
ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel,
|
||||
int lun, u_int tag, role_t role, uint32_t status)
|
||||
{
|
||||
@ -6078,7 +6650,7 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset)
|
||||
/*
|
||||
* Calculate the residual for a just completed SCB.
|
||||
*/
|
||||
void
|
||||
static void
|
||||
ahc_calc_residual(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
struct hardware_scb *hscb;
|
||||
@ -6279,7 +6851,7 @@ ahc_loadseq(struct ahc_softc *ahc)
|
||||
struct cs cs_table[num_critical_sections];
|
||||
u_int begin_set[num_critical_sections];
|
||||
u_int end_set[num_critical_sections];
|
||||
struct patch *cur_patch;
|
||||
const struct patch *cur_patch;
|
||||
u_int cs_count;
|
||||
u_int cur_cs;
|
||||
u_int i;
|
||||
@ -6384,11 +6956,11 @@ ahc_loadseq(struct ahc_softc *ahc)
|
||||
}
|
||||
|
||||
static int
|
||||
ahc_check_patch(struct ahc_softc *ahc, struct patch **start_patch,
|
||||
ahc_check_patch(struct ahc_softc *ahc, const struct patch **start_patch,
|
||||
u_int start_instr, u_int *skip_addr)
|
||||
{
|
||||
struct patch *cur_patch;
|
||||
struct patch *last_patch;
|
||||
const struct patch *cur_patch;
|
||||
const struct patch *last_patch;
|
||||
u_int num_patches;
|
||||
|
||||
num_patches = ARRAY_SIZE(patches);
|
||||
@ -6447,7 +7019,7 @@ ahc_download_instr(struct ahc_softc *ahc, u_int instrptr, uint8_t *dconsts)
|
||||
case AIC_OP_JE:
|
||||
case AIC_OP_JZ:
|
||||
{
|
||||
struct patch *cur_patch;
|
||||
const struct patch *cur_patch;
|
||||
int address_offset;
|
||||
u_int address;
|
||||
u_int skip_addr;
|
||||
@ -6545,7 +7117,7 @@ ahc_download_instr(struct ahc_softc *ahc, u_int instrptr, uint8_t *dconsts)
|
||||
}
|
||||
|
||||
int
|
||||
ahc_print_register(ahc_reg_parse_entry_t *table, u_int num_entries,
|
||||
ahc_print_register(const ahc_reg_parse_entry_t *table, u_int num_entries,
|
||||
const char *name, u_int address, u_int value,
|
||||
u_int *cur_column, u_int wrap_point)
|
||||
{
|
||||
@ -7229,7 +7801,7 @@ ahc_update_scsiid(struct ahc_softc *ahc, u_int targid_mask)
|
||||
ahc_outb(ahc, SCSIID, scsiid);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
ahc_run_tqinfifo(struct ahc_softc *ahc, int paused)
|
||||
{
|
||||
struct target_cmd *cmd;
|
||||
|
@ -46,179 +46,13 @@
|
||||
#define _AIC7XXX_INLINE_H_
|
||||
|
||||
/************************* Sequencer Execution Control ************************/
|
||||
static __inline void ahc_pause_bug_fix(struct ahc_softc *ahc);
|
||||
static __inline int ahc_is_paused(struct ahc_softc *ahc);
|
||||
static __inline void ahc_pause(struct ahc_softc *ahc);
|
||||
static __inline void ahc_unpause(struct ahc_softc *ahc);
|
||||
|
||||
/*
|
||||
* Work around any chip bugs related to halting sequencer execution.
|
||||
* On Ultra2 controllers, we must clear the CIOBUS stretch signal by
|
||||
* reading a register that will set this signal and deassert it.
|
||||
* Without this workaround, if the chip is paused, by an interrupt or
|
||||
* manual pause while accessing scb ram, accesses to certain registers
|
||||
* will hang the system (infinite pci retries).
|
||||
*/
|
||||
static __inline void
|
||||
ahc_pause_bug_fix(struct ahc_softc *ahc)
|
||||
{
|
||||
if ((ahc->features & AHC_ULTRA2) != 0)
|
||||
(void)ahc_inb(ahc, CCSCBCTL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine whether the sequencer has halted code execution.
|
||||
* Returns non-zero status if the sequencer is stopped.
|
||||
*/
|
||||
static __inline int
|
||||
ahc_is_paused(struct ahc_softc *ahc)
|
||||
{
|
||||
return ((ahc_inb(ahc, HCNTRL) & PAUSE) != 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Request that the sequencer stop and wait, indefinitely, for it
|
||||
* to stop. The sequencer will only acknowledge that it is paused
|
||||
* once it has reached an instruction boundary and PAUSEDIS is
|
||||
* cleared in the SEQCTL register. The sequencer may use PAUSEDIS
|
||||
* for critical sections.
|
||||
*/
|
||||
static __inline void
|
||||
ahc_pause(struct ahc_softc *ahc)
|
||||
{
|
||||
ahc_outb(ahc, HCNTRL, ahc->pause);
|
||||
|
||||
/*
|
||||
* Since the sequencer can disable pausing in a critical section, we
|
||||
* must loop until it actually stops.
|
||||
*/
|
||||
while (ahc_is_paused(ahc) == 0)
|
||||
;
|
||||
|
||||
ahc_pause_bug_fix(ahc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow the sequencer to continue program execution.
|
||||
* We check here to ensure that no additional interrupt
|
||||
* sources that would cause the sequencer to halt have been
|
||||
* asserted. If, for example, a SCSI bus reset is detected
|
||||
* while we are fielding a different, pausing, interrupt type,
|
||||
* we don't want to release the sequencer before going back
|
||||
* into our interrupt handler and dealing with this new
|
||||
* condition.
|
||||
*/
|
||||
static __inline void
|
||||
ahc_unpause(struct ahc_softc *ahc)
|
||||
{
|
||||
if ((ahc_inb(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0)
|
||||
ahc_outb(ahc, HCNTRL, ahc->unpause);
|
||||
}
|
||||
|
||||
/*********************** Untagged Transaction Routines ************************/
|
||||
static __inline void ahc_freeze_untagged_queues(struct ahc_softc *ahc);
|
||||
static __inline void ahc_release_untagged_queues(struct ahc_softc *ahc);
|
||||
|
||||
/*
|
||||
* Block our completion routine from starting the next untagged
|
||||
* transaction for this target or target lun.
|
||||
*/
|
||||
static __inline void
|
||||
ahc_freeze_untagged_queues(struct ahc_softc *ahc)
|
||||
{
|
||||
if ((ahc->flags & AHC_SCB_BTT) == 0)
|
||||
ahc->untagged_queue_lock++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow the next untagged transaction for this target or target lun
|
||||
* to be executed. We use a counting semaphore to allow the lock
|
||||
* to be acquired recursively. Once the count drops to zero, the
|
||||
* transaction queues will be run.
|
||||
*/
|
||||
static __inline void
|
||||
ahc_release_untagged_queues(struct ahc_softc *ahc)
|
||||
{
|
||||
if ((ahc->flags & AHC_SCB_BTT) == 0) {
|
||||
ahc->untagged_queue_lock--;
|
||||
if (ahc->untagged_queue_lock == 0)
|
||||
ahc_run_untagged_queues(ahc);
|
||||
}
|
||||
}
|
||||
int ahc_is_paused(struct ahc_softc *ahc);
|
||||
void ahc_pause(struct ahc_softc *ahc);
|
||||
void ahc_unpause(struct ahc_softc *ahc);
|
||||
|
||||
/************************** Memory mapping routines ***************************/
|
||||
static __inline struct ahc_dma_seg *
|
||||
ahc_sg_bus_to_virt(struct scb *scb,
|
||||
uint32_t sg_busaddr);
|
||||
static __inline uint32_t
|
||||
ahc_sg_virt_to_bus(struct scb *scb,
|
||||
struct ahc_dma_seg *sg);
|
||||
static __inline uint32_t
|
||||
ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index);
|
||||
static __inline void ahc_sync_scb(struct ahc_softc *ahc,
|
||||
struct scb *scb, int op);
|
||||
static __inline void ahc_sync_sglist(struct ahc_softc *ahc,
|
||||
struct scb *scb, int op);
|
||||
static __inline uint32_t
|
||||
ahc_targetcmd_offset(struct ahc_softc *ahc,
|
||||
u_int index);
|
||||
|
||||
static __inline struct ahc_dma_seg *
|
||||
ahc_sg_bus_to_virt(struct scb *scb, uint32_t sg_busaddr)
|
||||
{
|
||||
int sg_index;
|
||||
|
||||
sg_index = (sg_busaddr - scb->sg_list_phys)/sizeof(struct ahc_dma_seg);
|
||||
/* sg_list_phys points to entry 1, not 0 */
|
||||
sg_index++;
|
||||
|
||||
return (&scb->sg_list[sg_index]);
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
ahc_sg_virt_to_bus(struct scb *scb, struct ahc_dma_seg *sg)
|
||||
{
|
||||
int sg_index;
|
||||
|
||||
/* sg_list_phys points to entry 1, not 0 */
|
||||
sg_index = sg - &scb->sg_list[1];
|
||||
|
||||
return (scb->sg_list_phys + (sg_index * sizeof(*scb->sg_list)));
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index)
|
||||
{
|
||||
return (ahc->scb_data->hscb_busaddr
|
||||
+ (sizeof(struct hardware_scb) * index));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_sync_scb(struct ahc_softc *ahc, struct scb *scb, int op)
|
||||
{
|
||||
ahc_dmamap_sync(ahc, ahc->scb_data->hscb_dmat,
|
||||
ahc->scb_data->hscb_dmamap,
|
||||
/*offset*/(scb->hscb - ahc->hscbs) * sizeof(*scb->hscb),
|
||||
/*len*/sizeof(*scb->hscb), op);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_sync_sglist(struct ahc_softc *ahc, struct scb *scb, int op)
|
||||
{
|
||||
if (scb->sg_count == 0)
|
||||
return;
|
||||
|
||||
ahc_dmamap_sync(ahc, ahc->scb_data->sg_dmat, scb->sg_map->sg_dmamap,
|
||||
/*offset*/(scb->sg_list - scb->sg_map->sg_vaddr)
|
||||
* sizeof(struct ahc_dma_seg),
|
||||
/*len*/sizeof(struct ahc_dma_seg) * scb->sg_count, op);
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
ahc_targetcmd_offset(struct ahc_softc *ahc, u_int index)
|
||||
{
|
||||
return (((uint8_t *)&ahc->targetcmds[index]) - ahc->qoutfifo);
|
||||
}
|
||||
void ahc_sync_sglist(struct ahc_softc *ahc,
|
||||
struct scb *scb, int op);
|
||||
|
||||
/******************************** Debugging ***********************************/
|
||||
static __inline char *ahc_name(struct ahc_softc *ahc);
|
||||
@ -231,420 +65,34 @@ ahc_name(struct ahc_softc *ahc)
|
||||
|
||||
/*********************** Miscellaneous Support Functions ***********************/
|
||||
|
||||
static __inline void ahc_update_residual(struct ahc_softc *ahc,
|
||||
struct scb *scb);
|
||||
static __inline struct ahc_initiator_tinfo *
|
||||
ahc_fetch_transinfo(struct ahc_softc *ahc,
|
||||
char channel, u_int our_id,
|
||||
u_int remote_id,
|
||||
struct ahc_tmode_tstate **tstate);
|
||||
static __inline uint16_t
|
||||
ahc_inw(struct ahc_softc *ahc, u_int port);
|
||||
static __inline void ahc_outw(struct ahc_softc *ahc, u_int port,
|
||||
u_int value);
|
||||
static __inline uint32_t
|
||||
ahc_inl(struct ahc_softc *ahc, u_int port);
|
||||
static __inline void ahc_outl(struct ahc_softc *ahc, u_int port,
|
||||
uint32_t value);
|
||||
static __inline uint64_t
|
||||
ahc_inq(struct ahc_softc *ahc, u_int port);
|
||||
static __inline void ahc_outq(struct ahc_softc *ahc, u_int port,
|
||||
uint64_t value);
|
||||
static __inline struct scb*
|
||||
ahc_get_scb(struct ahc_softc *ahc);
|
||||
static __inline void ahc_free_scb(struct ahc_softc *ahc, struct scb *scb);
|
||||
static __inline void ahc_swap_with_next_hscb(struct ahc_softc *ahc,
|
||||
struct scb *scb);
|
||||
static __inline void ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb);
|
||||
static __inline struct scsi_sense_data *
|
||||
ahc_get_sense_buf(struct ahc_softc *ahc,
|
||||
struct scb *scb);
|
||||
static __inline uint32_t
|
||||
ahc_get_sense_bufaddr(struct ahc_softc *ahc,
|
||||
struct scb *scb);
|
||||
|
||||
/*
|
||||
* Determine whether the sequencer reported a residual
|
||||
* for this SCB/transaction.
|
||||
*/
|
||||
static __inline void
|
||||
ahc_update_residual(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
uint32_t sgptr;
|
||||
|
||||
sgptr = ahc_le32toh(scb->hscb->sgptr);
|
||||
if ((sgptr & SG_RESID_VALID) != 0)
|
||||
ahc_calc_residual(ahc, scb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return pointers to the transfer negotiation information
|
||||
* for the specified our_id/remote_id pair.
|
||||
*/
|
||||
static __inline struct ahc_initiator_tinfo *
|
||||
ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id,
|
||||
u_int remote_id, struct ahc_tmode_tstate **tstate)
|
||||
{
|
||||
/*
|
||||
* Transfer data structures are stored from the perspective
|
||||
* of the target role. Since the parameters for a connection
|
||||
* in the initiator role to a given target are the same as
|
||||
* when the roles are reversed, we pretend we are the target.
|
||||
*/
|
||||
if (channel == 'B')
|
||||
our_id += 8;
|
||||
*tstate = ahc->enabled_targets[our_id];
|
||||
return (&(*tstate)->transinfo[remote_id]);
|
||||
}
|
||||
|
||||
static __inline uint16_t
|
||||
ahc_inw(struct ahc_softc *ahc, u_int port)
|
||||
{
|
||||
uint16_t r = ahc_inb(ahc, port+1) << 8;
|
||||
return r | ahc_inb(ahc, port);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_outw(struct ahc_softc *ahc, u_int port, u_int value)
|
||||
{
|
||||
ahc_outb(ahc, port, value & 0xFF);
|
||||
ahc_outb(ahc, port+1, (value >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
ahc_inl(struct ahc_softc *ahc, u_int port)
|
||||
{
|
||||
return ((ahc_inb(ahc, port))
|
||||
| (ahc_inb(ahc, port+1) << 8)
|
||||
| (ahc_inb(ahc, port+2) << 16)
|
||||
| (ahc_inb(ahc, port+3) << 24));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_outl(struct ahc_softc *ahc, u_int port, uint32_t value)
|
||||
{
|
||||
ahc_outb(ahc, port, (value) & 0xFF);
|
||||
ahc_outb(ahc, port+1, ((value) >> 8) & 0xFF);
|
||||
ahc_outb(ahc, port+2, ((value) >> 16) & 0xFF);
|
||||
ahc_outb(ahc, port+3, ((value) >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
static __inline uint64_t
|
||||
ahc_inq(struct ahc_softc *ahc, u_int port)
|
||||
{
|
||||
return ((ahc_inb(ahc, port))
|
||||
| (ahc_inb(ahc, port+1) << 8)
|
||||
| (ahc_inb(ahc, port+2) << 16)
|
||||
| (ahc_inb(ahc, port+3) << 24)
|
||||
| (((uint64_t)ahc_inb(ahc, port+4)) << 32)
|
||||
| (((uint64_t)ahc_inb(ahc, port+5)) << 40)
|
||||
| (((uint64_t)ahc_inb(ahc, port+6)) << 48)
|
||||
| (((uint64_t)ahc_inb(ahc, port+7)) << 56));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_outq(struct ahc_softc *ahc, u_int port, uint64_t value)
|
||||
{
|
||||
ahc_outb(ahc, port, value & 0xFF);
|
||||
ahc_outb(ahc, port+1, (value >> 8) & 0xFF);
|
||||
ahc_outb(ahc, port+2, (value >> 16) & 0xFF);
|
||||
ahc_outb(ahc, port+3, (value >> 24) & 0xFF);
|
||||
ahc_outb(ahc, port+4, (value >> 32) & 0xFF);
|
||||
ahc_outb(ahc, port+5, (value >> 40) & 0xFF);
|
||||
ahc_outb(ahc, port+6, (value >> 48) & 0xFF);
|
||||
ahc_outb(ahc, port+7, (value >> 56) & 0xFF);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a free scb. If there are none, see if we can allocate a new SCB.
|
||||
*/
|
||||
static __inline struct scb *
|
||||
ahc_get_scb(struct ahc_softc *ahc)
|
||||
{
|
||||
struct scb *scb;
|
||||
|
||||
if ((scb = SLIST_FIRST(&ahc->scb_data->free_scbs)) == NULL) {
|
||||
ahc_alloc_scbs(ahc);
|
||||
scb = SLIST_FIRST(&ahc->scb_data->free_scbs);
|
||||
if (scb == NULL)
|
||||
return (NULL);
|
||||
}
|
||||
SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links.sle);
|
||||
return (scb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return an SCB resource to the free list.
|
||||
*/
|
||||
static __inline void
|
||||
ahc_free_scb(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
struct hardware_scb *hscb;
|
||||
|
||||
hscb = scb->hscb;
|
||||
/* Clean up for the next user */
|
||||
ahc->scb_data->scbindex[hscb->tag] = NULL;
|
||||
scb->flags = SCB_FREE;
|
||||
hscb->control = 0;
|
||||
|
||||
SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, scb, links.sle);
|
||||
|
||||
/* Notify the OSM that a resource is now available. */
|
||||
ahc_platform_scb_free(ahc, scb);
|
||||
}
|
||||
|
||||
static __inline struct scb *
|
||||
ahc_lookup_scb(struct ahc_softc *ahc, u_int tag)
|
||||
{
|
||||
struct scb* scb;
|
||||
|
||||
scb = ahc->scb_data->scbindex[tag];
|
||||
if (scb != NULL)
|
||||
ahc_sync_scb(ahc, scb,
|
||||
BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
|
||||
return (scb);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_swap_with_next_hscb(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
struct hardware_scb *q_hscb;
|
||||
u_int saved_tag;
|
||||
|
||||
/*
|
||||
* Our queuing method is a bit tricky. The card
|
||||
* knows in advance which HSCB to download, and we
|
||||
* can't disappoint it. To achieve this, the next
|
||||
* SCB to download is saved off in ahc->next_queued_scb.
|
||||
* When we are called to queue "an arbitrary scb",
|
||||
* we copy the contents of the incoming HSCB to the one
|
||||
* the sequencer knows about, swap HSCB pointers and
|
||||
* finally assign the SCB to the tag indexed location
|
||||
* in the scb_array. This makes sure that we can still
|
||||
* locate the correct SCB by SCB_TAG.
|
||||
*/
|
||||
q_hscb = ahc->next_queued_scb->hscb;
|
||||
saved_tag = q_hscb->tag;
|
||||
memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb));
|
||||
if ((scb->flags & SCB_CDB32_PTR) != 0) {
|
||||
q_hscb->shared_data.cdb_ptr =
|
||||
ahc_htole32(ahc_hscb_busaddr(ahc, q_hscb->tag)
|
||||
+ offsetof(struct hardware_scb, cdb32));
|
||||
}
|
||||
q_hscb->tag = saved_tag;
|
||||
q_hscb->next = scb->hscb->tag;
|
||||
|
||||
/* Now swap HSCB pointers. */
|
||||
ahc->next_queued_scb->hscb = scb->hscb;
|
||||
scb->hscb = q_hscb;
|
||||
|
||||
/* Now define the mapping from tag to SCB in the scbindex */
|
||||
ahc->scb_data->scbindex[scb->hscb->tag] = scb;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tell the sequencer about a new transaction to execute.
|
||||
*/
|
||||
static __inline void
|
||||
ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
ahc_swap_with_next_hscb(ahc, scb);
|
||||
|
||||
if (scb->hscb->tag == SCB_LIST_NULL
|
||||
|| scb->hscb->next == SCB_LIST_NULL)
|
||||
panic("Attempt to queue invalid SCB tag %x:%x\n",
|
||||
scb->hscb->tag, scb->hscb->next);
|
||||
|
||||
/*
|
||||
* Setup data "oddness".
|
||||
*/
|
||||
scb->hscb->lun &= LID;
|
||||
if (ahc_get_transfer_length(scb) & 0x1)
|
||||
scb->hscb->lun |= SCB_XFERLEN_ODD;
|
||||
|
||||
/*
|
||||
* Keep a history of SCBs we've downloaded in the qinfifo.
|
||||
*/
|
||||
ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag;
|
||||
|
||||
/*
|
||||
* Make sure our data is consistent from the
|
||||
* perspective of the adapter.
|
||||
*/
|
||||
ahc_sync_scb(ahc, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
|
||||
|
||||
/* Tell the adapter about the newly queued SCB */
|
||||
if ((ahc->features & AHC_QUEUE_REGS) != 0) {
|
||||
ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext);
|
||||
} else {
|
||||
if ((ahc->features & AHC_AUTOPAUSE) == 0)
|
||||
ahc_pause(ahc);
|
||||
ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext);
|
||||
if ((ahc->features & AHC_AUTOPAUSE) == 0)
|
||||
ahc_unpause(ahc);
|
||||
}
|
||||
}
|
||||
|
||||
static __inline struct scsi_sense_data *
|
||||
ahc_get_sense_buf(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
int offset;
|
||||
|
||||
offset = scb - ahc->scb_data->scbarray;
|
||||
return (&ahc->scb_data->sense[offset]);
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
ahc_get_sense_bufaddr(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
int offset;
|
||||
|
||||
offset = scb - ahc->scb_data->scbarray;
|
||||
return (ahc->scb_data->sense_busaddr
|
||||
+ (offset * sizeof(struct scsi_sense_data)));
|
||||
}
|
||||
struct ahc_initiator_tinfo *
|
||||
ahc_fetch_transinfo(struct ahc_softc *ahc,
|
||||
char channel, u_int our_id,
|
||||
u_int remote_id,
|
||||
struct ahc_tmode_tstate **tstate);
|
||||
uint16_t
|
||||
ahc_inw(struct ahc_softc *ahc, u_int port);
|
||||
void ahc_outw(struct ahc_softc *ahc, u_int port,
|
||||
u_int value);
|
||||
uint32_t
|
||||
ahc_inl(struct ahc_softc *ahc, u_int port);
|
||||
void ahc_outl(struct ahc_softc *ahc, u_int port,
|
||||
uint32_t value);
|
||||
uint64_t
|
||||
ahc_inq(struct ahc_softc *ahc, u_int port);
|
||||
void ahc_outq(struct ahc_softc *ahc, u_int port,
|
||||
uint64_t value);
|
||||
struct scb*
|
||||
ahc_get_scb(struct ahc_softc *ahc);
|
||||
void ahc_free_scb(struct ahc_softc *ahc, struct scb *scb);
|
||||
struct scb *
|
||||
ahc_lookup_scb(struct ahc_softc *ahc, u_int tag);
|
||||
void ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb);
|
||||
struct scsi_sense_data *
|
||||
ahc_get_sense_buf(struct ahc_softc *ahc,
|
||||
struct scb *scb);
|
||||
|
||||
/************************** Interrupt Processing ******************************/
|
||||
static __inline void ahc_sync_qoutfifo(struct ahc_softc *ahc, int op);
|
||||
static __inline void ahc_sync_tqinfifo(struct ahc_softc *ahc, int op);
|
||||
static __inline u_int ahc_check_cmdcmpltqueues(struct ahc_softc *ahc);
|
||||
static __inline int ahc_intr(struct ahc_softc *ahc);
|
||||
|
||||
static __inline void
|
||||
ahc_sync_qoutfifo(struct ahc_softc *ahc, int op)
|
||||
{
|
||||
ahc_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap,
|
||||
/*offset*/0, /*len*/256, op);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_sync_tqinfifo(struct ahc_softc *ahc, int op)
|
||||
{
|
||||
#ifdef AHC_TARGET_MODE
|
||||
if ((ahc->flags & AHC_TARGETROLE) != 0) {
|
||||
ahc_dmamap_sync(ahc, ahc->shared_data_dmat,
|
||||
ahc->shared_data_dmamap,
|
||||
ahc_targetcmd_offset(ahc, 0),
|
||||
sizeof(struct target_cmd) * AHC_TMODE_CMDS,
|
||||
op);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* See if the firmware has posted any completed commands
|
||||
* into our in-core command complete fifos.
|
||||
*/
|
||||
#define AHC_RUN_QOUTFIFO 0x1
|
||||
#define AHC_RUN_TQINFIFO 0x2
|
||||
static __inline u_int
|
||||
ahc_check_cmdcmpltqueues(struct ahc_softc *ahc)
|
||||
{
|
||||
u_int retval;
|
||||
|
||||
retval = 0;
|
||||
ahc_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap,
|
||||
/*offset*/ahc->qoutfifonext, /*len*/1,
|
||||
BUS_DMASYNC_POSTREAD);
|
||||
if (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL)
|
||||
retval |= AHC_RUN_QOUTFIFO;
|
||||
#ifdef AHC_TARGET_MODE
|
||||
if ((ahc->flags & AHC_TARGETROLE) != 0
|
||||
&& (ahc->flags & AHC_TQINFIFO_BLOCKED) == 0) {
|
||||
ahc_dmamap_sync(ahc, ahc->shared_data_dmat,
|
||||
ahc->shared_data_dmamap,
|
||||
ahc_targetcmd_offset(ahc, ahc->tqinfifofnext),
|
||||
/*len*/sizeof(struct target_cmd),
|
||||
BUS_DMASYNC_POSTREAD);
|
||||
if (ahc->targetcmds[ahc->tqinfifonext].cmd_valid != 0)
|
||||
retval |= AHC_RUN_TQINFIFO;
|
||||
}
|
||||
#endif
|
||||
return (retval);
|
||||
}
|
||||
|
||||
/*
|
||||
* Catch an interrupt from the adapter
|
||||
*/
|
||||
static __inline int
|
||||
ahc_intr(struct ahc_softc *ahc)
|
||||
{
|
||||
u_int intstat;
|
||||
|
||||
if ((ahc->pause & INTEN) == 0) {
|
||||
/*
|
||||
* Our interrupt is not enabled on the chip
|
||||
* and may be disabled for re-entrancy reasons,
|
||||
* so just return. This is likely just a shared
|
||||
* interrupt.
|
||||
*/
|
||||
return (0);
|
||||
}
|
||||
/*
|
||||
* Instead of directly reading the interrupt status register,
|
||||
* infer the cause of the interrupt by checking our in-core
|
||||
* completion queues. This avoids a costly PCI bus read in
|
||||
* most cases.
|
||||
*/
|
||||
if ((ahc->flags & (AHC_ALL_INTERRUPTS|AHC_EDGE_INTERRUPT)) == 0
|
||||
&& (ahc_check_cmdcmpltqueues(ahc) != 0))
|
||||
intstat = CMDCMPLT;
|
||||
else {
|
||||
intstat = ahc_inb(ahc, INTSTAT);
|
||||
}
|
||||
|
||||
if ((intstat & INT_PEND) == 0) {
|
||||
#if AHC_PCI_CONFIG > 0
|
||||
if (ahc->unsolicited_ints > 500) {
|
||||
ahc->unsolicited_ints = 0;
|
||||
if ((ahc->chip & AHC_PCI) != 0
|
||||
&& (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0)
|
||||
ahc->bus_intr(ahc);
|
||||
}
|
||||
#endif
|
||||
ahc->unsolicited_ints++;
|
||||
return (0);
|
||||
}
|
||||
ahc->unsolicited_ints = 0;
|
||||
|
||||
if (intstat & CMDCMPLT) {
|
||||
ahc_outb(ahc, CLRINT, CLRCMDINT);
|
||||
|
||||
/*
|
||||
* Ensure that the chip sees that we've cleared
|
||||
* this interrupt before we walk the output fifo.
|
||||
* Otherwise, we may, due to posted bus writes,
|
||||
* clear the interrupt after we finish the scan,
|
||||
* and after the sequencer has added new entries
|
||||
* and asserted the interrupt again.
|
||||
*/
|
||||
ahc_flush_device_writes(ahc);
|
||||
ahc_run_qoutfifo(ahc);
|
||||
#ifdef AHC_TARGET_MODE
|
||||
if ((ahc->flags & AHC_TARGETROLE) != 0)
|
||||
ahc_run_tqinfifo(ahc, /*paused*/FALSE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle statuses that may invalidate our cached
|
||||
* copy of INTSTAT separately.
|
||||
*/
|
||||
if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0) {
|
||||
/* Hot eject. Do nothing */
|
||||
} else if (intstat & BRKADRINT) {
|
||||
ahc_handle_brkadrint(ahc);
|
||||
} else if ((intstat & (SEQINT|SCSIINT)) != 0) {
|
||||
|
||||
ahc_pause_bug_fix(ahc);
|
||||
|
||||
if ((intstat & SEQINT) != 0)
|
||||
ahc_handle_seqint(ahc, intstat);
|
||||
|
||||
if ((intstat & SCSIINT) != 0)
|
||||
ahc_handle_scsiint(ahc, intstat);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
int ahc_intr(struct ahc_softc *ahc);
|
||||
|
||||
#endif /* _AIC7XXX_INLINE_H_ */
|
||||
|
@ -388,14 +388,83 @@ static int aic7xxx_setup(char *s);
|
||||
static int ahc_linux_unit;
|
||||
|
||||
|
||||
/********************************* Inlines ************************************/
|
||||
static __inline void ahc_linux_unmap_scb(struct ahc_softc*, struct scb*);
|
||||
/************************** OS Utility Wrappers *******************************/
|
||||
void
|
||||
ahc_delay(long usec)
|
||||
{
|
||||
/*
|
||||
* udelay on Linux can have problems for
|
||||
* multi-millisecond waits. Wait at most
|
||||
* 1024us per call.
|
||||
*/
|
||||
while (usec > 0) {
|
||||
udelay(usec % 1024);
|
||||
usec -= 1024;
|
||||
}
|
||||
}
|
||||
|
||||
static __inline int ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb,
|
||||
/***************************** Low Level I/O **********************************/
|
||||
uint8_t
|
||||
ahc_inb(struct ahc_softc * ahc, long port)
|
||||
{
|
||||
uint8_t x;
|
||||
|
||||
if (ahc->tag == BUS_SPACE_MEMIO) {
|
||||
x = readb(ahc->bsh.maddr + port);
|
||||
} else {
|
||||
x = inb(ahc->bsh.ioport + port);
|
||||
}
|
||||
mb();
|
||||
return (x);
|
||||
}
|
||||
|
||||
void
|
||||
ahc_outb(struct ahc_softc * ahc, long port, uint8_t val)
|
||||
{
|
||||
if (ahc->tag == BUS_SPACE_MEMIO) {
|
||||
writeb(val, ahc->bsh.maddr + port);
|
||||
} else {
|
||||
outb(val, ahc->bsh.ioport + port);
|
||||
}
|
||||
mb();
|
||||
}
|
||||
|
||||
void
|
||||
ahc_outsb(struct ahc_softc * ahc, long port, uint8_t *array, int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* There is probably a more efficient way to do this on Linux
|
||||
* but we don't use this for anything speed critical and this
|
||||
* should work.
|
||||
*/
|
||||
for (i = 0; i < count; i++)
|
||||
ahc_outb(ahc, port, *array++);
|
||||
}
|
||||
|
||||
void
|
||||
ahc_insb(struct ahc_softc * ahc, long port, uint8_t *array, int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* There is probably a more efficient way to do this on Linux
|
||||
* but we don't use this for anything speed critical and this
|
||||
* should work.
|
||||
*/
|
||||
for (i = 0; i < count; i++)
|
||||
*array++ = ahc_inb(ahc, port);
|
||||
}
|
||||
|
||||
/********************************* Inlines ************************************/
|
||||
static void ahc_linux_unmap_scb(struct ahc_softc*, struct scb*);
|
||||
|
||||
static 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 void
|
||||
static void
|
||||
ahc_linux_unmap_scb(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
struct scsi_cmnd *cmd;
|
||||
@ -406,7 +475,7 @@ ahc_linux_unmap_scb(struct ahc_softc *ahc, struct scb *scb)
|
||||
scsi_dma_unmap(cmd);
|
||||
}
|
||||
|
||||
static __inline int
|
||||
static 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)
|
||||
{
|
||||
@ -442,13 +511,11 @@ ahc_linux_info(struct Scsi_Host *host)
|
||||
bp = &buffer[0];
|
||||
ahc = *(struct ahc_softc **)host->hostdata;
|
||||
memset(bp, 0, sizeof(buffer));
|
||||
strcpy(bp, "Adaptec AIC7XXX EISA/VLB/PCI SCSI HBA DRIVER, Rev ");
|
||||
strcat(bp, AIC7XXX_DRIVER_VERSION);
|
||||
strcat(bp, "\n");
|
||||
strcat(bp, " <");
|
||||
strcpy(bp, "Adaptec AIC7XXX EISA/VLB/PCI SCSI HBA DRIVER, Rev " AIC7XXX_DRIVER_VERSION "\n"
|
||||
" <");
|
||||
strcat(bp, ahc->description);
|
||||
strcat(bp, ">\n");
|
||||
strcat(bp, " ");
|
||||
strcat(bp, ">\n"
|
||||
" ");
|
||||
ahc_controller_info(ahc, ahc_info);
|
||||
strcat(bp, ahc_info);
|
||||
strcat(bp, "\n");
|
||||
@ -964,7 +1031,7 @@ aic7xxx_setup(char *s)
|
||||
char *p;
|
||||
char *end;
|
||||
|
||||
static struct {
|
||||
static const struct {
|
||||
const char *name;
|
||||
uint32_t *flag;
|
||||
} options[] = {
|
||||
@ -2317,7 +2384,7 @@ static void ahc_linux_set_period(struct scsi_target *starget, int period)
|
||||
unsigned int ppr_options = tinfo->goal.ppr_options;
|
||||
unsigned long flags;
|
||||
unsigned long offset = tinfo->goal.offset;
|
||||
struct ahc_syncrate *syncrate;
|
||||
const struct ahc_syncrate *syncrate;
|
||||
|
||||
if (offset == 0)
|
||||
offset = MAX_OFFSET;
|
||||
@ -2361,7 +2428,7 @@ static void ahc_linux_set_offset(struct scsi_target *starget, int offset)
|
||||
unsigned int ppr_options = 0;
|
||||
unsigned int period = 0;
|
||||
unsigned long flags;
|
||||
struct ahc_syncrate *syncrate = NULL;
|
||||
const struct ahc_syncrate *syncrate = NULL;
|
||||
|
||||
ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
|
||||
starget->channel + 'A', ROLE_INITIATOR);
|
||||
@ -2391,7 +2458,7 @@ static void ahc_linux_set_dt(struct scsi_target *starget, int dt)
|
||||
unsigned int period = tinfo->goal.period;
|
||||
unsigned int width = tinfo->goal.width;
|
||||
unsigned long flags;
|
||||
struct ahc_syncrate *syncrate;
|
||||
const struct ahc_syncrate *syncrate;
|
||||
|
||||
if (dt && spi_max_width(starget)) {
|
||||
ppr_options |= MSG_EXT_PPR_DT_REQ;
|
||||
|
@ -365,7 +365,7 @@ struct ahc_platform_data {
|
||||
#define AHC_LINUX_NOIRQ ((uint32_t)~0)
|
||||
uint32_t irq; /* IRQ for this adapter */
|
||||
uint32_t bios_address;
|
||||
uint32_t mem_busaddr; /* Mem Base Addr */
|
||||
resource_size_t mem_busaddr; /* Mem Base Addr */
|
||||
};
|
||||
|
||||
/************************** OS Utility Wrappers *******************************/
|
||||
@ -375,82 +375,16 @@ struct ahc_platform_data {
|
||||
#define malloc(size, type, flags) kmalloc(size, flags)
|
||||
#define free(ptr, type) kfree(ptr)
|
||||
|
||||
static __inline void ahc_delay(long);
|
||||
static __inline void
|
||||
ahc_delay(long usec)
|
||||
{
|
||||
/*
|
||||
* udelay on Linux can have problems for
|
||||
* multi-millisecond waits. Wait at most
|
||||
* 1024us per call.
|
||||
*/
|
||||
while (usec > 0) {
|
||||
udelay(usec % 1024);
|
||||
usec -= 1024;
|
||||
}
|
||||
}
|
||||
void ahc_delay(long);
|
||||
|
||||
|
||||
/***************************** Low Level I/O **********************************/
|
||||
static __inline uint8_t ahc_inb(struct ahc_softc * ahc, long port);
|
||||
static __inline void ahc_outb(struct ahc_softc * ahc, long port, uint8_t val);
|
||||
static __inline void ahc_outsb(struct ahc_softc * ahc, long port,
|
||||
uint8_t *, int count);
|
||||
static __inline void ahc_insb(struct ahc_softc * ahc, long port,
|
||||
uint8_t *, int count);
|
||||
|
||||
static __inline uint8_t
|
||||
ahc_inb(struct ahc_softc * ahc, long port)
|
||||
{
|
||||
uint8_t x;
|
||||
|
||||
if (ahc->tag == BUS_SPACE_MEMIO) {
|
||||
x = readb(ahc->bsh.maddr + port);
|
||||
} else {
|
||||
x = inb(ahc->bsh.ioport + port);
|
||||
}
|
||||
mb();
|
||||
return (x);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_outb(struct ahc_softc * ahc, long port, uint8_t val)
|
||||
{
|
||||
if (ahc->tag == BUS_SPACE_MEMIO) {
|
||||
writeb(val, ahc->bsh.maddr + port);
|
||||
} else {
|
||||
outb(val, ahc->bsh.ioport + port);
|
||||
}
|
||||
mb();
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_outsb(struct ahc_softc * ahc, long port, uint8_t *array, int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* There is probably a more efficient way to do this on Linux
|
||||
* but we don't use this for anything speed critical and this
|
||||
* should work.
|
||||
*/
|
||||
for (i = 0; i < count; i++)
|
||||
ahc_outb(ahc, port, *array++);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_insb(struct ahc_softc * ahc, long port, uint8_t *array, int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* There is probably a more efficient way to do this on Linux
|
||||
* but we don't use this for anything speed critical and this
|
||||
* should work.
|
||||
*/
|
||||
for (i = 0; i < count; i++)
|
||||
*array++ = ahc_inb(ahc, port);
|
||||
}
|
||||
uint8_t ahc_inb(struct ahc_softc * ahc, long port);
|
||||
void ahc_outb(struct ahc_softc * ahc, long port, uint8_t val);
|
||||
void ahc_outsb(struct ahc_softc * ahc, long port,
|
||||
uint8_t *, int count);
|
||||
void ahc_insb(struct ahc_softc * ahc, long port,
|
||||
uint8_t *, int count);
|
||||
|
||||
/**************************** Initialization **********************************/
|
||||
int ahc_linux_register_host(struct ahc_softc *,
|
||||
@ -464,9 +398,6 @@ struct info_str {
|
||||
int pos;
|
||||
};
|
||||
|
||||
void ahc_format_transinfo(struct info_str *info,
|
||||
struct ahc_transinfo *tinfo);
|
||||
|
||||
/******************************** Locking *************************************/
|
||||
/* Lock protecting internal data structures */
|
||||
|
||||
@ -555,61 +486,12 @@ void ahc_linux_pci_exit(void);
|
||||
int ahc_pci_map_registers(struct ahc_softc *ahc);
|
||||
int ahc_pci_map_int(struct ahc_softc *ahc);
|
||||
|
||||
static __inline uint32_t ahc_pci_read_config(ahc_dev_softc_t pci,
|
||||
uint32_t ahc_pci_read_config(ahc_dev_softc_t pci,
|
||||
int reg, int width);
|
||||
|
||||
static __inline uint32_t
|
||||
ahc_pci_read_config(ahc_dev_softc_t pci, int reg, int width)
|
||||
{
|
||||
switch (width) {
|
||||
case 1:
|
||||
{
|
||||
uint8_t retval;
|
||||
|
||||
pci_read_config_byte(pci, reg, &retval);
|
||||
return (retval);
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
uint16_t retval;
|
||||
pci_read_config_word(pci, reg, &retval);
|
||||
return (retval);
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
uint32_t retval;
|
||||
pci_read_config_dword(pci, reg, &retval);
|
||||
return (retval);
|
||||
}
|
||||
default:
|
||||
panic("ahc_pci_read_config: Read size too big");
|
||||
/* NOTREACHED */
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
static __inline void ahc_pci_write_config(ahc_dev_softc_t pci,
|
||||
int reg, uint32_t value,
|
||||
int width);
|
||||
|
||||
static __inline void
|
||||
ahc_pci_write_config(ahc_dev_softc_t pci, int reg, uint32_t value, int width)
|
||||
{
|
||||
switch (width) {
|
||||
case 1:
|
||||
pci_write_config_byte(pci, reg, value);
|
||||
break;
|
||||
case 2:
|
||||
pci_write_config_word(pci, reg, value);
|
||||
break;
|
||||
case 4:
|
||||
pci_write_config_dword(pci, reg, value);
|
||||
break;
|
||||
default:
|
||||
panic("ahc_pci_write_config: Write size too big");
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
void ahc_pci_write_config(ahc_dev_softc_t pci,
|
||||
int reg, uint32_t value,
|
||||
int width);
|
||||
|
||||
static __inline int ahc_get_pci_function(ahc_dev_softc_t);
|
||||
static __inline int
|
||||
|
@ -46,7 +46,7 @@
|
||||
*/
|
||||
#define ID(x) ID_C(x, PCI_CLASS_STORAGE_SCSI)
|
||||
|
||||
static struct pci_device_id ahc_linux_pci_id_table[] = {
|
||||
static const struct pci_device_id ahc_linux_pci_id_table[] = {
|
||||
/* aic7850 based controllers */
|
||||
ID(ID_AHA_2902_04_10_15_20C_30C),
|
||||
/* aic7860 based controllers */
|
||||
@ -206,7 +206,7 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
const uint64_t mask_39bit = 0x7FFFFFFFFFULL;
|
||||
struct ahc_softc *ahc;
|
||||
ahc_dev_softc_t pci;
|
||||
struct ahc_pci_identity *entry;
|
||||
const struct ahc_pci_identity *entry;
|
||||
char *name;
|
||||
int error;
|
||||
struct device *dev = &pdev->dev;
|
||||
@ -269,6 +269,57 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/******************************* PCI Routines *********************************/
|
||||
uint32_t
|
||||
ahc_pci_read_config(ahc_dev_softc_t pci, int reg, int width)
|
||||
{
|
||||
switch (width) {
|
||||
case 1:
|
||||
{
|
||||
uint8_t retval;
|
||||
|
||||
pci_read_config_byte(pci, reg, &retval);
|
||||
return (retval);
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
uint16_t retval;
|
||||
pci_read_config_word(pci, reg, &retval);
|
||||
return (retval);
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
uint32_t retval;
|
||||
pci_read_config_dword(pci, reg, &retval);
|
||||
return (retval);
|
||||
}
|
||||
default:
|
||||
panic("ahc_pci_read_config: Read size too big");
|
||||
/* NOTREACHED */
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ahc_pci_write_config(ahc_dev_softc_t pci, int reg, uint32_t value, int width)
|
||||
{
|
||||
switch (width) {
|
||||
case 1:
|
||||
pci_write_config_byte(pci, reg, value);
|
||||
break;
|
||||
case 2:
|
||||
pci_write_config_word(pci, reg, value);
|
||||
break;
|
||||
case 4:
|
||||
pci_write_config_dword(pci, reg, value);
|
||||
break;
|
||||
default:
|
||||
panic("ahc_pci_write_config: Write size too big");
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct pci_driver aic7xxx_pci_driver = {
|
||||
.name = "aic7xxx",
|
||||
.probe = ahc_linux_pci_dev_probe,
|
||||
@ -293,7 +344,7 @@ ahc_linux_pci_exit(void)
|
||||
}
|
||||
|
||||
static int
|
||||
ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc, u_long *base)
|
||||
ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc, resource_size_t *base)
|
||||
{
|
||||
if (aic7xxx_allow_memio == 0)
|
||||
return (ENOMEM);
|
||||
@ -308,10 +359,10 @@ ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc, u_long *base)
|
||||
|
||||
static int
|
||||
ahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc,
|
||||
u_long *bus_addr,
|
||||
resource_size_t *bus_addr,
|
||||
uint8_t __iomem **maddr)
|
||||
{
|
||||
u_long start;
|
||||
resource_size_t start;
|
||||
int error;
|
||||
|
||||
error = 0;
|
||||
@ -336,7 +387,7 @@ int
|
||||
ahc_pci_map_registers(struct ahc_softc *ahc)
|
||||
{
|
||||
uint32_t command;
|
||||
u_long base;
|
||||
resource_size_t base;
|
||||
uint8_t __iomem *maddr;
|
||||
int error;
|
||||
|
||||
@ -374,12 +425,12 @@ ahc_pci_map_registers(struct ahc_softc *ahc)
|
||||
} else
|
||||
command |= PCIM_CMD_MEMEN;
|
||||
} else {
|
||||
printf("aic7xxx: PCI%d:%d:%d MEM region 0x%lx "
|
||||
printf("aic7xxx: PCI%d:%d:%d MEM region 0x%llx "
|
||||
"unavailable. Cannot memory map device.\n",
|
||||
ahc_get_pci_bus(ahc->dev_softc),
|
||||
ahc_get_pci_slot(ahc->dev_softc),
|
||||
ahc_get_pci_function(ahc->dev_softc),
|
||||
base);
|
||||
(unsigned long long)base);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -390,15 +441,15 @@ ahc_pci_map_registers(struct ahc_softc *ahc)
|
||||
error = ahc_linux_pci_reserve_io_region(ahc, &base);
|
||||
if (error == 0) {
|
||||
ahc->tag = BUS_SPACE_PIO;
|
||||
ahc->bsh.ioport = base;
|
||||
ahc->bsh.ioport = (u_long)base;
|
||||
command |= PCIM_CMD_PORTEN;
|
||||
} else {
|
||||
printf("aic7xxx: PCI%d:%d:%d IO region 0x%lx[0..255] "
|
||||
printf("aic7xxx: PCI%d:%d:%d IO region 0x%llx[0..255] "
|
||||
"unavailable. Cannot map device.\n",
|
||||
ahc_get_pci_bus(ahc->dev_softc),
|
||||
ahc_get_pci_slot(ahc->dev_softc),
|
||||
ahc_get_pci_function(ahc->dev_softc),
|
||||
base);
|
||||
(unsigned long long)base);
|
||||
}
|
||||
}
|
||||
ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, 4);
|
||||
|
@ -168,8 +168,7 @@ static ahc_device_setup_t ahc_aha394XX_setup;
|
||||
static ahc_device_setup_t ahc_aha494XX_setup;
|
||||
static ahc_device_setup_t ahc_aha398XX_setup;
|
||||
|
||||
static struct ahc_pci_identity ahc_pci_ident_table [] =
|
||||
{
|
||||
static const struct ahc_pci_identity ahc_pci_ident_table[] = {
|
||||
/* aic7850 based controllers */
|
||||
{
|
||||
ID_AHA_2902_04_10_15_20C_30C,
|
||||
@ -668,7 +667,7 @@ ahc_9005_subdevinfo_valid(uint16_t device, uint16_t vendor,
|
||||
return (result);
|
||||
}
|
||||
|
||||
struct ahc_pci_identity *
|
||||
const struct ahc_pci_identity *
|
||||
ahc_find_pci_device(ahc_dev_softc_t pci)
|
||||
{
|
||||
uint64_t full_id;
|
||||
@ -676,7 +675,7 @@ ahc_find_pci_device(ahc_dev_softc_t pci)
|
||||
uint16_t vendor;
|
||||
uint16_t subdevice;
|
||||
uint16_t subvendor;
|
||||
struct ahc_pci_identity *entry;
|
||||
const struct ahc_pci_identity *entry;
|
||||
u_int i;
|
||||
|
||||
vendor = ahc_pci_read_config(pci, PCIR_DEVVENDOR, /*bytes*/2);
|
||||
@ -710,7 +709,7 @@ ahc_find_pci_device(ahc_dev_softc_t pci)
|
||||
}
|
||||
|
||||
int
|
||||
ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
|
||||
ahc_pci_config(struct ahc_softc *ahc, const struct ahc_pci_identity *entry)
|
||||
{
|
||||
u_int command;
|
||||
u_int our_id;
|
||||
|
@ -58,7 +58,7 @@ static int ahc_proc_write_seeprom(struct ahc_softc *ahc,
|
||||
* Table of syncrates that don't follow the "divisible by 4"
|
||||
* rule. This table will be expanded in future SCSI specs.
|
||||
*/
|
||||
static struct {
|
||||
static const struct {
|
||||
u_int period_factor;
|
||||
u_int period; /* in 100ths of ns */
|
||||
} scsi_syncrates[] = {
|
||||
@ -137,7 +137,7 @@ copy_info(struct info_str *info, char *fmt, ...)
|
||||
return (len);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
ahc_format_transinfo(struct info_str *info, struct ahc_transinfo *tinfo)
|
||||
{
|
||||
u_int speed;
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
#include "aic7xxx_osm.h"
|
||||
|
||||
static ahc_reg_parse_entry_t SCSISEQ_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SCSISEQ_parse_table[] = {
|
||||
{ "SCSIRSTO", 0x01, 0x01 },
|
||||
{ "ENAUTOATNP", 0x02, 0x02 },
|
||||
{ "ENAUTOATNI", 0x04, 0x04 },
|
||||
@ -26,7 +26,7 @@ ahc_scsiseq_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x00, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SXFRCTL0_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SXFRCTL0_parse_table[] = {
|
||||
{ "CLRCHN", 0x02, 0x02 },
|
||||
{ "SCAMEN", 0x04, 0x04 },
|
||||
{ "SPIOEN", 0x08, 0x08 },
|
||||
@ -43,7 +43,7 @@ ahc_sxfrctl0_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x01, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SXFRCTL1_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SXFRCTL1_parse_table[] = {
|
||||
{ "STPWEN", 0x01, 0x01 },
|
||||
{ "ACTNEGEN", 0x02, 0x02 },
|
||||
{ "ENSTIMER", 0x04, 0x04 },
|
||||
@ -60,7 +60,7 @@ ahc_sxfrctl1_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x02, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SCSISIGO_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SCSISIGO_parse_table[] = {
|
||||
{ "ACKO", 0x01, 0x01 },
|
||||
{ "REQO", 0x02, 0x02 },
|
||||
{ "BSYO", 0x04, 0x04 },
|
||||
@ -85,7 +85,7 @@ ahc_scsisigo_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x03, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SCSISIGI_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SCSISIGI_parse_table[] = {
|
||||
{ "ACKI", 0x01, 0x01 },
|
||||
{ "REQI", 0x02, 0x02 },
|
||||
{ "BSYI", 0x04, 0x04 },
|
||||
@ -112,7 +112,7 @@ ahc_scsisigi_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x03, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SCSIRATE_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SCSIRATE_parse_table[] = {
|
||||
{ "SINGLE_EDGE", 0x10, 0x10 },
|
||||
{ "ENABLE_CRC", 0x40, 0x40 },
|
||||
{ "WIDEXFER", 0x80, 0x80 },
|
||||
@ -128,7 +128,7 @@ ahc_scsirate_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x04, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SCSIID_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SCSIID_parse_table[] = {
|
||||
{ "TWIN_CHNLB", 0x80, 0x80 },
|
||||
{ "OID", 0x0f, 0x0f },
|
||||
{ "TWIN_TID", 0x70, 0x70 },
|
||||
@ -150,13 +150,6 @@ ahc_scsidatl_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x06, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
int
|
||||
ahc_scsidath_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
{
|
||||
return (ahc_print_register(NULL, 0, "SCSIDATH",
|
||||
0x07, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
int
|
||||
ahc_stcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
{
|
||||
@ -164,7 +157,7 @@ ahc_stcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x08, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t OPTIONMODE_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t OPTIONMODE_parse_table[] = {
|
||||
{ "DIS_MSGIN_DUALEDGE", 0x01, 0x01 },
|
||||
{ "AUTO_MSGOUT_DE", 0x02, 0x02 },
|
||||
{ "SCSIDATL_IMGEN", 0x04, 0x04 },
|
||||
@ -190,7 +183,7 @@ ahc_targcrccnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x0a, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t CLRSINT0_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t CLRSINT0_parse_table[] = {
|
||||
{ "CLRSPIORDY", 0x02, 0x02 },
|
||||
{ "CLRSWRAP", 0x08, 0x08 },
|
||||
{ "CLRIOERR", 0x08, 0x08 },
|
||||
@ -206,7 +199,7 @@ ahc_clrsint0_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x0b, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SSTAT0_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SSTAT0_parse_table[] = {
|
||||
{ "DMADONE", 0x01, 0x01 },
|
||||
{ "SPIORDY", 0x02, 0x02 },
|
||||
{ "SDONE", 0x04, 0x04 },
|
||||
@ -225,7 +218,7 @@ ahc_sstat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x0b, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t CLRSINT1_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t CLRSINT1_parse_table[] = {
|
||||
{ "CLRREQINIT", 0x01, 0x01 },
|
||||
{ "CLRPHASECHG", 0x02, 0x02 },
|
||||
{ "CLRSCSIPERR", 0x04, 0x04 },
|
||||
@ -242,7 +235,7 @@ ahc_clrsint1_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x0c, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SSTAT1_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SSTAT1_parse_table[] = {
|
||||
{ "REQINIT", 0x01, 0x01 },
|
||||
{ "PHASECHG", 0x02, 0x02 },
|
||||
{ "SCSIPERR", 0x04, 0x04 },
|
||||
@ -260,7 +253,7 @@ ahc_sstat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x0c, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SSTAT2_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SSTAT2_parse_table[] = {
|
||||
{ "DUAL_EDGE_ERR", 0x01, 0x01 },
|
||||
{ "CRCREQERR", 0x02, 0x02 },
|
||||
{ "CRCENDERR", 0x04, 0x04 },
|
||||
@ -278,7 +271,7 @@ ahc_sstat2_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x0d, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SSTAT3_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SSTAT3_parse_table[] = {
|
||||
{ "OFFCNT", 0x0f, 0x0f },
|
||||
{ "U2OFFCNT", 0x7f, 0x7f },
|
||||
{ "SCSICNT", 0xf0, 0xf0 }
|
||||
@ -291,7 +284,7 @@ ahc_sstat3_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x0e, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SCSIID_ULTRA2_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SCSIID_ULTRA2_parse_table[] = {
|
||||
{ "OID", 0x0f, 0x0f },
|
||||
{ "TID", 0xf0, 0xf0 }
|
||||
};
|
||||
@ -303,7 +296,7 @@ ahc_scsiid_ultra2_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x0f, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SIMODE0_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SIMODE0_parse_table[] = {
|
||||
{ "ENDMADONE", 0x01, 0x01 },
|
||||
{ "ENSPIORDY", 0x02, 0x02 },
|
||||
{ "ENSDONE", 0x04, 0x04 },
|
||||
@ -321,7 +314,7 @@ ahc_simode0_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x10, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SIMODE1_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SIMODE1_parse_table[] = {
|
||||
{ "ENREQINIT", 0x01, 0x01 },
|
||||
{ "ENPHASECHG", 0x02, 0x02 },
|
||||
{ "ENSCSIPERR", 0x04, 0x04 },
|
||||
@ -346,26 +339,6 @@ ahc_scsibusl_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x12, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
int
|
||||
ahc_scsibush_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
{
|
||||
return (ahc_print_register(NULL, 0, "SCSIBUSH",
|
||||
0x13, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SXFRCTL2_parse_table[] = {
|
||||
{ "CMDDMAEN", 0x08, 0x08 },
|
||||
{ "AUTORSTDIS", 0x10, 0x10 },
|
||||
{ "ASYNC_SETUP", 0x07, 0x07 }
|
||||
};
|
||||
|
||||
int
|
||||
ahc_sxfrctl2_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
{
|
||||
return (ahc_print_register(SXFRCTL2_parse_table, 3, "SXFRCTL2",
|
||||
0x13, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
int
|
||||
ahc_shaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
{
|
||||
@ -373,7 +346,7 @@ ahc_shaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x14, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SELTIMER_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SELTIMER_parse_table[] = {
|
||||
{ "STAGE1", 0x01, 0x01 },
|
||||
{ "STAGE2", 0x02, 0x02 },
|
||||
{ "STAGE3", 0x04, 0x04 },
|
||||
@ -389,7 +362,7 @@ ahc_seltimer_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x18, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SELID_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SELID_parse_table[] = {
|
||||
{ "ONEBIT", 0x08, 0x08 },
|
||||
{ "SELID_MASK", 0xf0, 0xf0 }
|
||||
};
|
||||
@ -401,21 +374,6 @@ ahc_selid_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x19, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SCAMCTL_parse_table[] = {
|
||||
{ "DFLTTID", 0x10, 0x10 },
|
||||
{ "ALTSTIM", 0x20, 0x20 },
|
||||
{ "CLRSCAMSELID", 0x40, 0x40 },
|
||||
{ "ENSCAMSELO", 0x80, 0x80 },
|
||||
{ "SCAMLVL", 0x03, 0x03 }
|
||||
};
|
||||
|
||||
int
|
||||
ahc_scamctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
{
|
||||
return (ahc_print_register(SCAMCTL_parse_table, 5, "SCAMCTL",
|
||||
0x1a, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
int
|
||||
ahc_targid_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
{
|
||||
@ -423,7 +381,7 @@ ahc_targid_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x1b, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SPIOCAP_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SPIOCAP_parse_table[] = {
|
||||
{ "SSPIOCPS", 0x01, 0x01 },
|
||||
{ "ROM", 0x02, 0x02 },
|
||||
{ "EEPROM", 0x04, 0x04 },
|
||||
@ -441,7 +399,7 @@ ahc_spiocap_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x1b, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t BRDCTL_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t BRDCTL_parse_table[] = {
|
||||
{ "BRDCTL0", 0x01, 0x01 },
|
||||
{ "BRDSTB_ULTRA2", 0x01, 0x01 },
|
||||
{ "BRDCTL1", 0x02, 0x02 },
|
||||
@ -464,7 +422,7 @@ ahc_brdctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x1d, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SEECTL_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SEECTL_parse_table[] = {
|
||||
{ "SEEDI", 0x01, 0x01 },
|
||||
{ "SEEDO", 0x02, 0x02 },
|
||||
{ "SEECK", 0x04, 0x04 },
|
||||
@ -482,7 +440,7 @@ ahc_seectl_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x1e, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SBLKCTL_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SBLKCTL_parse_table[] = {
|
||||
{ "XCVR", 0x01, 0x01 },
|
||||
{ "SELWIDE", 0x02, 0x02 },
|
||||
{ "ENAB20", 0x04, 0x04 },
|
||||
@ -521,13 +479,6 @@ ahc_disc_dsb_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x32, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
int
|
||||
ahc_cmdsize_table_tail_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
{
|
||||
return (ahc_print_register(NULL, 0, "CMDSIZE_TABLE_TAIL",
|
||||
0x34, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
int
|
||||
ahc_mwi_residual_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
{
|
||||
@ -549,7 +500,7 @@ ahc_msg_out_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x3a, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t DMAPARAMS_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t DMAPARAMS_parse_table[] = {
|
||||
{ "FIFORESET", 0x01, 0x01 },
|
||||
{ "FIFOFLUSH", 0x02, 0x02 },
|
||||
{ "DIRECTION", 0x04, 0x04 },
|
||||
@ -569,7 +520,7 @@ ahc_dmaparams_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x3b, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SEQ_FLAGS_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SEQ_FLAGS_parse_table[] = {
|
||||
{ "NO_DISCONNECT", 0x01, 0x01 },
|
||||
{ "SPHASE_PENDING", 0x02, 0x02 },
|
||||
{ "DPHASE_PENDING", 0x04, 0x04 },
|
||||
@ -602,7 +553,7 @@ ahc_saved_lun_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x3e, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t LASTPHASE_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t LASTPHASE_parse_table[] = {
|
||||
{ "MSGI", 0x20, 0x20 },
|
||||
{ "IOI", 0x40, 0x40 },
|
||||
{ "CDI", 0x80, 0x80 },
|
||||
@ -644,13 +595,6 @@ ahc_free_scbh_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x42, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
int
|
||||
ahc_complete_scbh_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
{
|
||||
return (ahc_print_register(NULL, 0, "COMPLETE_SCBH",
|
||||
0x43, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
int
|
||||
ahc_hscb_addr_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
{
|
||||
@ -700,7 +644,7 @@ ahc_tqinpos_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x50, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t ARG_1_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t ARG_1_parse_table[] = {
|
||||
{ "CONT_TARG_SESSION", 0x02, 0x02 },
|
||||
{ "CONT_MSG_LOOP", 0x04, 0x04 },
|
||||
{ "EXIT_MSG_LOOP", 0x08, 0x08 },
|
||||
@ -731,7 +675,7 @@ ahc_last_msg_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x53, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SCSISEQ_TEMPLATE_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SCSISEQ_TEMPLATE_parse_table[] = {
|
||||
{ "ENAUTOATNP", 0x02, 0x02 },
|
||||
{ "ENAUTOATNI", 0x04, 0x04 },
|
||||
{ "ENAUTOATNO", 0x08, 0x08 },
|
||||
@ -747,7 +691,7 @@ ahc_scsiseq_template_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x54, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t HA_274_BIOSGLOBAL_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t HA_274_BIOSGLOBAL_parse_table[] = {
|
||||
{ "HA_274_EXTENDED_TRANS",0x01, 0x01 }
|
||||
};
|
||||
|
||||
@ -758,7 +702,7 @@ ahc_ha_274_biosglobal_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x56, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SEQ_FLAGS2_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SEQ_FLAGS2_parse_table[] = {
|
||||
{ "SCB_DMA", 0x01, 0x01 },
|
||||
{ "TARGET_MSG_PENDING", 0x02, 0x02 }
|
||||
};
|
||||
@ -770,7 +714,7 @@ ahc_seq_flags2_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x57, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SCSICONF_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SCSICONF_parse_table[] = {
|
||||
{ "ENSPCHK", 0x20, 0x20 },
|
||||
{ "RESET_SCSI", 0x40, 0x40 },
|
||||
{ "TERM_ENB", 0x80, 0x80 },
|
||||
@ -785,7 +729,7 @@ ahc_scsiconf_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x5a, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t INTDEF_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t INTDEF_parse_table[] = {
|
||||
{ "EDGE_TRIG", 0x80, 0x80 },
|
||||
{ "VECTOR", 0x0f, 0x0f }
|
||||
};
|
||||
@ -804,7 +748,7 @@ ahc_hostconf_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x5d, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t HA_274_BIOSCTRL_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t HA_274_BIOSCTRL_parse_table[] = {
|
||||
{ "CHANNEL_B_PRIMARY", 0x08, 0x08 },
|
||||
{ "BIOSMODE", 0x30, 0x30 },
|
||||
{ "BIOSDISABLED", 0x30, 0x30 }
|
||||
@ -817,7 +761,7 @@ ahc_ha_274_biosctrl_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x5f, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SEQCTL_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SEQCTL_parse_table[] = {
|
||||
{ "LOADRAM", 0x01, 0x01 },
|
||||
{ "SEQRESET", 0x02, 0x02 },
|
||||
{ "STEP", 0x04, 0x04 },
|
||||
@ -849,7 +793,7 @@ ahc_seqaddr0_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x62, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SEQADDR1_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SEQADDR1_parse_table[] = {
|
||||
{ "SEQADDR1_MASK", 0x01, 0x01 }
|
||||
};
|
||||
|
||||
@ -902,7 +846,7 @@ ahc_none_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x6a, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t FLAGS_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t FLAGS_parse_table[] = {
|
||||
{ "CARRY", 0x01, 0x01 },
|
||||
{ "ZERO", 0x02, 0x02 }
|
||||
};
|
||||
@ -928,13 +872,6 @@ ahc_dindir_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x6d, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
int
|
||||
ahc_function1_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
{
|
||||
return (ahc_print_register(NULL, 0, "FUNCTION1",
|
||||
0x6e, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
int
|
||||
ahc_stack_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
{
|
||||
@ -956,19 +893,7 @@ ahc_sram_base_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x70, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t BCTL_parse_table[] = {
|
||||
{ "ENABLE", 0x01, 0x01 },
|
||||
{ "ACE", 0x08, 0x08 }
|
||||
};
|
||||
|
||||
int
|
||||
ahc_bctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
{
|
||||
return (ahc_print_register(BCTL_parse_table, 2, "BCTL",
|
||||
0x84, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t DSCOMMAND0_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t DSCOMMAND0_parse_table[] = {
|
||||
{ "CIOPARCKEN", 0x01, 0x01 },
|
||||
{ "USCBSIZE32", 0x02, 0x02 },
|
||||
{ "RAMPS", 0x04, 0x04 },
|
||||
@ -986,7 +911,7 @@ ahc_dscommand0_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x84, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t BUSTIME_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t BUSTIME_parse_table[] = {
|
||||
{ "BON", 0x0f, 0x0f },
|
||||
{ "BOFF", 0xf0, 0xf0 }
|
||||
};
|
||||
@ -998,7 +923,7 @@ ahc_bustime_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x85, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t DSCOMMAND1_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t DSCOMMAND1_parse_table[] = {
|
||||
{ "HADDLDSEL0", 0x01, 0x01 },
|
||||
{ "HADDLDSEL1", 0x02, 0x02 },
|
||||
{ "DSLATT", 0xfc, 0xfc }
|
||||
@ -1011,7 +936,7 @@ ahc_dscommand1_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x85, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t BUSSPD_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t BUSSPD_parse_table[] = {
|
||||
{ "STBON", 0x07, 0x07 },
|
||||
{ "STBOFF", 0x38, 0x38 },
|
||||
{ "DFTHRSH_75", 0x80, 0x80 },
|
||||
@ -1026,7 +951,7 @@ ahc_busspd_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x86, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t HS_MAILBOX_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t HS_MAILBOX_parse_table[] = {
|
||||
{ "SEQ_MAILBOX", 0x0f, 0x0f },
|
||||
{ "HOST_TQINPOS", 0x80, 0x80 },
|
||||
{ "HOST_MAILBOX", 0xf0, 0xf0 }
|
||||
@ -1039,7 +964,7 @@ ahc_hs_mailbox_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x86, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t DSPCISTATUS_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t DSPCISTATUS_parse_table[] = {
|
||||
{ "DFTHRSH_100", 0xc0, 0xc0 }
|
||||
};
|
||||
|
||||
@ -1050,7 +975,7 @@ ahc_dspcistatus_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x86, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t HCNTRL_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t HCNTRL_parse_table[] = {
|
||||
{ "CHIPRST", 0x01, 0x01 },
|
||||
{ "CHIPRSTACK", 0x01, 0x01 },
|
||||
{ "INTEN", 0x02, 0x02 },
|
||||
@ -1088,7 +1013,7 @@ ahc_scbptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x90, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t INTSTAT_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t INTSTAT_parse_table[] = {
|
||||
{ "SEQINT", 0x01, 0x01 },
|
||||
{ "CMDCMPLT", 0x02, 0x02 },
|
||||
{ "SCSIINT", 0x04, 0x04 },
|
||||
@ -1119,7 +1044,7 @@ ahc_intstat_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x91, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t CLRINT_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t CLRINT_parse_table[] = {
|
||||
{ "CLRSEQINT", 0x01, 0x01 },
|
||||
{ "CLRCMDINT", 0x02, 0x02 },
|
||||
{ "CLRSCSIINT", 0x04, 0x04 },
|
||||
@ -1134,7 +1059,7 @@ ahc_clrint_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x92, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t ERROR_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t ERROR_parse_table[] = {
|
||||
{ "ILLHADDR", 0x01, 0x01 },
|
||||
{ "ILLSADDR", 0x02, 0x02 },
|
||||
{ "ILLOPCODE", 0x04, 0x04 },
|
||||
@ -1152,7 +1077,7 @@ ahc_error_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x92, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t DFCNTRL_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t DFCNTRL_parse_table[] = {
|
||||
{ "FIFORESET", 0x01, 0x01 },
|
||||
{ "FIFOFLUSH", 0x02, 0x02 },
|
||||
{ "DIRECTION", 0x04, 0x04 },
|
||||
@ -1172,7 +1097,7 @@ ahc_dfcntrl_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x93, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t DFSTATUS_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t DFSTATUS_parse_table[] = {
|
||||
{ "FIFOEMP", 0x01, 0x01 },
|
||||
{ "FIFOFULL", 0x02, 0x02 },
|
||||
{ "DFTHRESH", 0x04, 0x04 },
|
||||
@ -1197,13 +1122,6 @@ ahc_dfwaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x95, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
int
|
||||
ahc_dfraddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
{
|
||||
return (ahc_print_register(NULL, 0, "DFRADDR",
|
||||
0x97, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
int
|
||||
ahc_dfdat_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
{
|
||||
@ -1211,7 +1129,7 @@ ahc_dfdat_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x99, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SCBCNT_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SCBCNT_parse_table[] = {
|
||||
{ "SCBAUTO", 0x80, 0x80 },
|
||||
{ "SCBCNT_MASK", 0x1f, 0x1f }
|
||||
};
|
||||
@ -1230,13 +1148,6 @@ ahc_qinfifo_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x9b, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
int
|
||||
ahc_qincnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
{
|
||||
return (ahc_print_register(NULL, 0, "QINCNT",
|
||||
0x9c, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
int
|
||||
ahc_qoutfifo_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
{
|
||||
@ -1244,7 +1155,7 @@ ahc_qoutfifo_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x9d, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t CRCCONTROL1_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t CRCCONTROL1_parse_table[] = {
|
||||
{ "TARGCRCCNTEN", 0x04, 0x04 },
|
||||
{ "TARGCRCENDEN", 0x08, 0x08 },
|
||||
{ "CRCREQCHKEN", 0x10, 0x10 },
|
||||
@ -1260,14 +1171,7 @@ ahc_crccontrol1_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x9d, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
int
|
||||
ahc_qoutcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
{
|
||||
return (ahc_print_register(NULL, 0, "QOUTCNT",
|
||||
0x9e, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SCSIPHASE_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SCSIPHASE_parse_table[] = {
|
||||
{ "DATA_OUT_PHASE", 0x01, 0x01 },
|
||||
{ "DATA_IN_PHASE", 0x02, 0x02 },
|
||||
{ "MSG_OUT_PHASE", 0x04, 0x04 },
|
||||
@ -1284,7 +1188,7 @@ ahc_scsiphase_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0x9e, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SFUNCT_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SFUNCT_parse_table[] = {
|
||||
{ "ALT_MODE", 0x80, 0x80 }
|
||||
};
|
||||
|
||||
@ -1351,7 +1255,7 @@ ahc_scb_dataptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0xac, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SCB_DATACNT_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SCB_DATACNT_parse_table[] = {
|
||||
{ "SG_LAST_SEG", 0x80, 0x80 },
|
||||
{ "SG_HIGH_ADDR_BITS", 0x7f, 0x7f }
|
||||
};
|
||||
@ -1363,7 +1267,7 @@ ahc_scb_datacnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0xb0, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SCB_SGPTR_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SCB_SGPTR_parse_table[] = {
|
||||
{ "SG_LIST_NULL", 0x01, 0x01 },
|
||||
{ "SG_FULL_RESID", 0x02, 0x02 },
|
||||
{ "SG_RESID_VALID", 0x04, 0x04 }
|
||||
@ -1376,7 +1280,7 @@ ahc_scb_sgptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0xb4, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SCB_CONTROL_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SCB_CONTROL_parse_table[] = {
|
||||
{ "DISCONNECTED", 0x04, 0x04 },
|
||||
{ "ULTRAENB", 0x08, 0x08 },
|
||||
{ "MK_MESSAGE", 0x10, 0x10 },
|
||||
@ -1394,7 +1298,7 @@ ahc_scb_control_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0xb8, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SCB_SCSIID_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SCB_SCSIID_parse_table[] = {
|
||||
{ "TWIN_CHNLB", 0x80, 0x80 },
|
||||
{ "OID", 0x0f, 0x0f },
|
||||
{ "TWIN_TID", 0x70, 0x70 },
|
||||
@ -1408,7 +1312,7 @@ ahc_scb_scsiid_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0xb9, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SCB_LUN_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SCB_LUN_parse_table[] = {
|
||||
{ "SCB_XFERLEN_ODD", 0x80, 0x80 },
|
||||
{ "LID", 0x3f, 0x3f }
|
||||
};
|
||||
@ -1455,14 +1359,7 @@ ahc_scb_next_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0xbf, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
int
|
||||
ahc_scb_64_spare_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
{
|
||||
return (ahc_print_register(NULL, 0, "SCB_64_SPARE",
|
||||
0xc0, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SEECTL_2840_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SEECTL_2840_parse_table[] = {
|
||||
{ "DO_2840", 0x01, 0x01 },
|
||||
{ "CK_2840", 0x02, 0x02 },
|
||||
{ "CS_2840", 0x04, 0x04 }
|
||||
@ -1475,7 +1372,7 @@ ahc_seectl_2840_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0xc0, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t STATUS_2840_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t STATUS_2840_parse_table[] = {
|
||||
{ "DI_2840", 0x01, 0x01 },
|
||||
{ "EEPROM_TF", 0x80, 0x80 },
|
||||
{ "ADSEL", 0x1e, 0x1e },
|
||||
@ -1524,7 +1421,7 @@ ahc_ccsgaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0xea, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t CCSGCTL_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t CCSGCTL_parse_table[] = {
|
||||
{ "CCSGRESET", 0x01, 0x01 },
|
||||
{ "SG_FETCH_NEEDED", 0x02, 0x02 },
|
||||
{ "CCSGEN", 0x08, 0x08 },
|
||||
@ -1552,7 +1449,7 @@ ahc_ccscbaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0xed, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t CCSCBCTL_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t CCSCBCTL_parse_table[] = {
|
||||
{ "CCSCBRESET", 0x01, 0x01 },
|
||||
{ "CCSCBDIR", 0x04, 0x04 },
|
||||
{ "CCSCBEN", 0x08, 0x08 },
|
||||
@ -1610,7 +1507,7 @@ ahc_sdscb_qoff_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0xf8, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t QOFF_CTLSTA_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t QOFF_CTLSTA_parse_table[] = {
|
||||
{ "SDSCB_ROLLOVER", 0x10, 0x10 },
|
||||
{ "SNSCB_ROLLOVER", 0x20, 0x20 },
|
||||
{ "SCB_AVAIL", 0x40, 0x40 },
|
||||
@ -1625,7 +1522,7 @@ ahc_qoff_ctlsta_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0xfa, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t DFF_THRSH_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t DFF_THRSH_parse_table[] = {
|
||||
{ "RD_DFTHRSH_MIN", 0x00, 0x00 },
|
||||
{ "WR_DFTHRSH_MIN", 0x00, 0x00 },
|
||||
{ "RD_DFTHRSH_25", 0x01, 0x01 },
|
||||
@ -1653,7 +1550,7 @@ ahc_dff_thrsh_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0xfb, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SG_CACHE_SHADOW_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SG_CACHE_SHADOW_parse_table[] = {
|
||||
{ "LAST_SEG_DONE", 0x01, 0x01 },
|
||||
{ "LAST_SEG", 0x02, 0x02 },
|
||||
{ "SG_ADDR_MASK", 0xf8, 0xf8 }
|
||||
@ -1666,7 +1563,7 @@ ahc_sg_cache_shadow_print(u_int regvalue, u_int *cur_col, u_int wrap)
|
||||
0xfc, regvalue, cur_col, wrap));
|
||||
}
|
||||
|
||||
static ahc_reg_parse_entry_t SG_CACHE_PRE_parse_table[] = {
|
||||
static const ahc_reg_parse_entry_t SG_CACHE_PRE_parse_table[] = {
|
||||
{ "LAST_SEG_DONE", 0x01, 0x01 },
|
||||
{ "LAST_SEG", 0x02, 0x02 },
|
||||
{ "SG_ADDR_MASK", 0xf8, 0xf8 }
|
||||
|
@ -5,7 +5,7 @@
|
||||
* $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $
|
||||
* $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#40 $
|
||||
*/
|
||||
static uint8_t seqprog[] = {
|
||||
static const uint8_t seqprog[] = {
|
||||
0xb2, 0x00, 0x00, 0x08,
|
||||
0xf7, 0x11, 0x22, 0x08,
|
||||
0x00, 0x65, 0xee, 0x59,
|
||||
@ -1081,7 +1081,7 @@ ahc_patch0_func(struct ahc_softc *ahc)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static struct patch {
|
||||
static const struct patch {
|
||||
ahc_patch_func_t *patch_func;
|
||||
uint32_t begin :10,
|
||||
skip_instr :10,
|
||||
@ -1291,7 +1291,7 @@ static struct patch {
|
||||
{ ahc_patch4_func, 865, 12, 1 }
|
||||
};
|
||||
|
||||
static struct cs {
|
||||
static const struct cs {
|
||||
uint16_t begin;
|
||||
uint16_t end;
|
||||
} critical_sections[] = {
|
||||
|
@ -362,7 +362,7 @@ output_code()
|
||||
" *\n"
|
||||
"%s */\n", versions);
|
||||
|
||||
fprintf(ofile, "static uint8_t seqprog[] = {\n");
|
||||
fprintf(ofile, "static const uint8_t seqprog[] = {\n");
|
||||
for (cur_instr = STAILQ_FIRST(&seq_program);
|
||||
cur_instr != NULL;
|
||||
cur_instr = STAILQ_NEXT(cur_instr, links)) {
|
||||
@ -415,7 +415,7 @@ output_code()
|
||||
}
|
||||
|
||||
fprintf(ofile,
|
||||
"static struct patch {\n"
|
||||
"static const struct patch {\n"
|
||||
" %spatch_func_t *patch_func;\n"
|
||||
" uint32_t begin :10,\n"
|
||||
" skip_instr :10,\n"
|
||||
@ -435,7 +435,7 @@ output_code()
|
||||
fprintf(ofile, "\n};\n\n");
|
||||
|
||||
fprintf(ofile,
|
||||
"static struct cs {\n"
|
||||
"static const struct cs {\n"
|
||||
" uint16_t begin;\n"
|
||||
" uint16_t end;\n"
|
||||
"} critical_sections[] = {\n");
|
||||
|
@ -101,11 +101,12 @@ static void format_3_instr(int opcode, symbol_ref_t *src,
|
||||
expression_t *immed, symbol_ref_t *address);
|
||||
static void test_readable_symbol(symbol_t *symbol);
|
||||
static void test_writable_symbol(symbol_t *symbol);
|
||||
static void type_check(symbol_t *symbol, expression_t *expression, int and_op);
|
||||
static void type_check(symbol_ref_t *sym, expression_t *expression, int and_op);
|
||||
static void make_expression(expression_t *immed, int value);
|
||||
static void add_conditional(symbol_t *symbol);
|
||||
static void add_version(const char *verstring);
|
||||
static int is_download_const(expression_t *immed);
|
||||
static int is_location_address(symbol_t *symbol);
|
||||
void yyerror(const char *string);
|
||||
|
||||
#define SRAM_SYMNAME "SRAM_BASE"
|
||||
@ -142,6 +143,8 @@ void yyerror(const char *string);
|
||||
|
||||
%token <value> T_ADDRESS
|
||||
|
||||
%token T_COUNT
|
||||
|
||||
%token T_ACCESS_MODE
|
||||
|
||||
%token T_MODES
|
||||
@ -192,10 +195,10 @@ void yyerror(const char *string);
|
||||
|
||||
%token <value> T_OR
|
||||
|
||||
/* 16 bit extensions */
|
||||
%token <value> T_OR16 T_AND16 T_XOR16 T_ADD16
|
||||
%token <value> T_ADC16 T_MVI16 T_TEST16 T_CMP16 T_CMPXCHG
|
||||
|
||||
/* 16 bit extensions, not implemented
|
||||
* %token <value> T_OR16 T_AND16 T_XOR16 T_ADD16
|
||||
* %token <value> T_ADC16 T_MVI16 T_TEST16 T_CMP16 T_CMPXCHG
|
||||
*/
|
||||
%token T_RET
|
||||
|
||||
%token T_NOP
|
||||
@ -214,7 +217,7 @@ void yyerror(const char *string);
|
||||
|
||||
%type <expression> expression immediate immediate_or_a
|
||||
|
||||
%type <value> export ret f1_opcode f2_opcode f4_opcode jmp_jc_jnc_call jz_jnz je_jne
|
||||
%type <value> export ret f1_opcode f2_opcode jmp_jc_jnc_call jz_jnz je_jne
|
||||
|
||||
%type <value> mode_value mode_list macro_arglist
|
||||
|
||||
@ -313,13 +316,13 @@ reg_definition:
|
||||
stop("Register multiply defined", EX_DATAERR);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
cur_symbol = $1;
|
||||
cur_symbol = $1;
|
||||
cur_symbol->type = cur_symtype;
|
||||
initialize_symbol(cur_symbol);
|
||||
}
|
||||
reg_attribute_list
|
||||
'}'
|
||||
{
|
||||
{
|
||||
/*
|
||||
* Default to allowing everything in for registers
|
||||
* with no bit or mask definitions.
|
||||
@ -349,9 +352,10 @@ reg_attribute_list:
|
||||
| reg_attribute_list reg_attribute
|
||||
;
|
||||
|
||||
reg_attribute:
|
||||
reg_attribute:
|
||||
reg_address
|
||||
| size
|
||||
| count
|
||||
| access_mode
|
||||
| modes
|
||||
| field_defn
|
||||
@ -392,6 +396,13 @@ size:
|
||||
}
|
||||
;
|
||||
|
||||
count:
|
||||
T_COUNT T_NUMBER
|
||||
{
|
||||
cur_symbol->count += $2;
|
||||
}
|
||||
;
|
||||
|
||||
access_mode:
|
||||
T_ACCESS_MODE T_MODE
|
||||
{
|
||||
@ -641,14 +652,14 @@ expression:
|
||||
&($1.referenced_syms),
|
||||
&($3.referenced_syms));
|
||||
}
|
||||
| expression T_EXPR_LSHIFT expression
|
||||
| expression T_EXPR_LSHIFT expression
|
||||
{
|
||||
$$.value = $1.value << $3.value;
|
||||
symlist_merge(&$$.referenced_syms,
|
||||
&$1.referenced_syms,
|
||||
&$3.referenced_syms);
|
||||
}
|
||||
| expression T_EXPR_RSHIFT expression
|
||||
| expression T_EXPR_RSHIFT expression
|
||||
{
|
||||
$$.value = $1.value >> $3.value;
|
||||
symlist_merge(&$$.referenced_syms,
|
||||
@ -714,7 +725,7 @@ expression:
|
||||
;
|
||||
|
||||
constant:
|
||||
T_CONST T_SYMBOL expression
|
||||
T_CONST T_SYMBOL expression
|
||||
{
|
||||
if ($2->type != UNINITIALIZED) {
|
||||
stop("Re-definition of symbol as a constant",
|
||||
@ -800,6 +811,7 @@ scratch_ram:
|
||||
cur_symtype = SRAMLOC;
|
||||
cur_symbol->type = SRAMLOC;
|
||||
initialize_symbol(cur_symbol);
|
||||
cur_symbol->count += 1;
|
||||
}
|
||||
reg_address
|
||||
{
|
||||
@ -831,6 +843,7 @@ scb:
|
||||
initialize_symbol(cur_symbol);
|
||||
/* 64 bytes of SCB space */
|
||||
cur_symbol->info.rinfo->size = 64;
|
||||
cur_symbol->count += 1;
|
||||
}
|
||||
reg_address
|
||||
{
|
||||
@ -1311,14 +1324,18 @@ f2_opcode:
|
||||
| T_ROR { $$ = AIC_OP_ROR; }
|
||||
;
|
||||
|
||||
f4_opcode:
|
||||
T_OR16 { $$ = AIC_OP_OR16; }
|
||||
| T_AND16 { $$ = AIC_OP_AND16; }
|
||||
| T_XOR16 { $$ = AIC_OP_XOR16; }
|
||||
| T_ADD16 { $$ = AIC_OP_ADD16; }
|
||||
| T_ADC16 { $$ = AIC_OP_ADC16; }
|
||||
| T_MVI16 { $$ = AIC_OP_MVI16; }
|
||||
;
|
||||
/*
|
||||
* 16bit opcodes, not used
|
||||
*
|
||||
*f4_opcode:
|
||||
* T_OR16 { $$ = AIC_OP_OR16; }
|
||||
*| T_AND16 { $$ = AIC_OP_AND16; }
|
||||
*| T_XOR16 { $$ = AIC_OP_XOR16; }
|
||||
*| T_ADD16 { $$ = AIC_OP_ADD16; }
|
||||
*| T_ADC16 { $$ = AIC_OP_ADC16; }
|
||||
*| T_MVI16 { $$ = AIC_OP_MVI16; }
|
||||
*;
|
||||
*/
|
||||
|
||||
code:
|
||||
f2_opcode destination ',' expression opt_source ret ';'
|
||||
@ -1357,6 +1374,7 @@ code:
|
||||
code:
|
||||
T_OR reg_symbol ',' immediate jmp_jc_jnc_call address ';'
|
||||
{
|
||||
type_check(&$2, &$4, AIC_OP_OR);
|
||||
format_3_instr($5, &$2, &$4, &$6);
|
||||
}
|
||||
;
|
||||
@ -1528,7 +1546,7 @@ initialize_symbol(symbol_t *symbol)
|
||||
sizeof(struct cond_info));
|
||||
break;
|
||||
case MACRO:
|
||||
symbol->info.macroinfo =
|
||||
symbol->info.macroinfo =
|
||||
(struct macro_info *)malloc(sizeof(struct macro_info));
|
||||
if (symbol->info.macroinfo == NULL) {
|
||||
stop("Can't create macro info", EX_SOFTWARE);
|
||||
@ -1552,7 +1570,6 @@ add_macro_arg(const char *argtext, int argnum)
|
||||
struct macro_arg *marg;
|
||||
int i;
|
||||
int retval;
|
||||
|
||||
|
||||
if (cur_symbol == NULL || cur_symbol->type != MACRO) {
|
||||
stop("Invalid current symbol for adding macro arg",
|
||||
@ -1633,8 +1650,10 @@ format_1_instr(int opcode, symbol_ref_t *dest, expression_t *immed,
|
||||
test_writable_symbol(dest->symbol);
|
||||
test_readable_symbol(src->symbol);
|
||||
|
||||
/* Ensure that immediate makes sense for this destination */
|
||||
type_check(dest->symbol, immed, opcode);
|
||||
if (!is_location_address(dest->symbol)) {
|
||||
/* Ensure that immediate makes sense for this destination */
|
||||
type_check(dest, immed, opcode);
|
||||
}
|
||||
|
||||
/* Allocate sequencer space for the instruction and fill it out */
|
||||
instr = seq_alloc();
|
||||
@ -1766,9 +1785,6 @@ format_3_instr(int opcode, symbol_ref_t *src,
|
||||
/* Test register permissions */
|
||||
test_readable_symbol(src->symbol);
|
||||
|
||||
/* Ensure that immediate makes sense for this source */
|
||||
type_check(src->symbol, immed, opcode);
|
||||
|
||||
/* Allocate sequencer space for the instruction and fill it out */
|
||||
instr = seq_alloc();
|
||||
f3_instr = &instr->format.format3;
|
||||
@ -1797,7 +1813,6 @@ format_3_instr(int opcode, symbol_ref_t *src,
|
||||
static void
|
||||
test_readable_symbol(symbol_t *symbol)
|
||||
{
|
||||
|
||||
if ((symbol->info.rinfo->modes & (0x1 << src_mode)) == 0) {
|
||||
snprintf(errbuf, sizeof(errbuf),
|
||||
"Register %s unavailable in source reg mode %d",
|
||||
@ -1815,7 +1830,6 @@ test_readable_symbol(symbol_t *symbol)
|
||||
static void
|
||||
test_writable_symbol(symbol_t *symbol)
|
||||
{
|
||||
|
||||
if ((symbol->info.rinfo->modes & (0x1 << dst_mode)) == 0) {
|
||||
snprintf(errbuf, sizeof(errbuf),
|
||||
"Register %s unavailable in destination reg mode %d",
|
||||
@ -1831,25 +1845,34 @@ test_writable_symbol(symbol_t *symbol)
|
||||
}
|
||||
|
||||
static void
|
||||
type_check(symbol_t *symbol, expression_t *expression, int opcode)
|
||||
type_check(symbol_ref_t *sym, expression_t *expression, int opcode)
|
||||
{
|
||||
symbol_t *symbol = sym->symbol;
|
||||
symbol_node_t *node;
|
||||
int and_op;
|
||||
int8_t value, mask;
|
||||
|
||||
and_op = FALSE;
|
||||
if (opcode == AIC_OP_AND || opcode == AIC_OP_JNZ || opcode == AIC_OP_JZ)
|
||||
and_op = TRUE;
|
||||
|
||||
/*
|
||||
* Make sure that we aren't attempting to write something
|
||||
* that hasn't been defined. If this is an and operation,
|
||||
* this is a mask, so "undefined" bits are okay.
|
||||
*/
|
||||
if (and_op == FALSE
|
||||
&& (expression->value & ~symbol->info.rinfo->valid_bitmask) != 0) {
|
||||
if (opcode == AIC_OP_AND || opcode == AIC_OP_JNZ ||
|
||||
opcode == AIC_OP_JZ || opcode == AIC_OP_JNE ||
|
||||
opcode == AIC_OP_BMOV)
|
||||
and_op = TRUE;
|
||||
|
||||
/*
|
||||
* Defaulting to 8 bit logic
|
||||
*/
|
||||
mask = (int8_t)~symbol->info.rinfo->valid_bitmask;
|
||||
value = (int8_t)expression->value;
|
||||
|
||||
if (and_op == FALSE && (mask & value) != 0 ) {
|
||||
snprintf(errbuf, sizeof(errbuf),
|
||||
"Invalid bit(s) 0x%x in immediate written to %s",
|
||||
expression->value & ~symbol->info.rinfo->valid_bitmask,
|
||||
(mask & value),
|
||||
symbol->name);
|
||||
stop(errbuf, EX_DATAERR);
|
||||
/* NOTREACHED */
|
||||
@ -1959,3 +1982,13 @@ is_download_const(expression_t *immed)
|
||||
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
static int
|
||||
is_location_address(symbol_t *sym)
|
||||
{
|
||||
if (sym->type == SCBLOC ||
|
||||
sym->type == SRAMLOC)
|
||||
return (TRUE);
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
|
@ -162,6 +162,7 @@ register { return T_REGISTER; }
|
||||
const { yylval.value = FALSE; return T_CONST; }
|
||||
download { return T_DOWNLOAD; }
|
||||
address { return T_ADDRESS; }
|
||||
count { return T_COUNT; }
|
||||
access_mode { return T_ACCESS_MODE; }
|
||||
modes { return T_MODES; }
|
||||
RW|RO|WO {
|
||||
@ -228,15 +229,15 @@ ret { return T_RET; }
|
||||
nop { return T_NOP; }
|
||||
|
||||
/* ARP2 16bit extensions */
|
||||
or16 { return T_OR16; }
|
||||
and16 { return T_AND16; }
|
||||
xor16 { return T_XOR16; }
|
||||
add16 { return T_ADD16; }
|
||||
adc16 { return T_ADC16; }
|
||||
mvi16 { return T_MVI16; }
|
||||
test16 { return T_TEST16; }
|
||||
cmp16 { return T_CMP16; }
|
||||
cmpxchg { return T_CMPXCHG; }
|
||||
/* or16 { return T_OR16; } */
|
||||
/* and16 { return T_AND16; }*/
|
||||
/* xor16 { return T_XOR16; }*/
|
||||
/* add16 { return T_ADD16; }*/
|
||||
/* adc16 { return T_ADC16; }*/
|
||||
/* mvi16 { return T_MVI16; }*/
|
||||
/* test16 { return T_TEST16; }*/
|
||||
/* cmp16 { return T_CMP16; }*/
|
||||
/* cmpxchg { return T_CMPXCHG; }*/
|
||||
|
||||
/* Allowed Symbols */
|
||||
\<\< { return T_EXPR_LSHIFT; }
|
||||
|
@ -77,6 +77,7 @@ symbol_create(char *name)
|
||||
if (new_symbol->name == NULL)
|
||||
stop("Unable to strdup symbol name", EX_SOFTWARE);
|
||||
new_symbol->type = UNINITIALIZED;
|
||||
new_symbol->count = 1;
|
||||
return (new_symbol);
|
||||
}
|
||||
|
||||
@ -198,6 +199,12 @@ symtable_get(char *name)
|
||||
}
|
||||
}
|
||||
memcpy(&stored_ptr, data.data, sizeof(stored_ptr));
|
||||
stored_ptr->count++;
|
||||
data.data = &stored_ptr;
|
||||
if (symtable->put(symtable, &key, &data, /*flags*/0) !=0) {
|
||||
perror("Symtable put failed");
|
||||
exit(EX_SOFTWARE);
|
||||
}
|
||||
return (stored_ptr);
|
||||
}
|
||||
|
||||
@ -256,7 +263,7 @@ symlist_add(symlist_t *symlist, symbol_t *symbol, int how)
|
||||
&& (curnode->symbol->info.finfo->value >
|
||||
newnode->symbol->info.finfo->value))))
|
||||
|| (!field && (curnode->symbol->info.rinfo->address >
|
||||
newnode->symbol->info.rinfo->address))) {
|
||||
newnode->symbol->info.rinfo->address))) {
|
||||
SLIST_INSERT_HEAD(symlist, newnode, links);
|
||||
return;
|
||||
}
|
||||
@ -271,7 +278,7 @@ symlist_add(symlist_t *symlist, symbol_t *symbol, int how)
|
||||
|
||||
cursymbol = SLIST_NEXT(curnode, links)->symbol;
|
||||
if ((field
|
||||
&& (cursymbol->type > symbol->type
|
||||
&& (cursymbol->type > symbol->type
|
||||
|| (cursymbol->type == symbol->type
|
||||
&& (cursymbol->info.finfo->value >
|
||||
symbol->info.finfo->value))))
|
||||
@ -351,7 +358,7 @@ aic_print_reg_dump_types(FILE *ofile)
|
||||
{
|
||||
if (ofile == NULL)
|
||||
return;
|
||||
|
||||
|
||||
fprintf(ofile,
|
||||
"typedef int (%sreg_print_t)(u_int, u_int *, u_int);\n"
|
||||
"typedef struct %sreg_parse_entry {\n"
|
||||
@ -370,7 +377,7 @@ aic_print_reg_dump_start(FILE *dfile, symbol_node_t *regnode)
|
||||
return;
|
||||
|
||||
fprintf(dfile,
|
||||
"static %sreg_parse_entry_t %s_parse_table[] = {\n",
|
||||
"static const %sreg_parse_entry_t %s_parse_table[] = {\n",
|
||||
prefix,
|
||||
regnode->symbol->name);
|
||||
}
|
||||
@ -385,7 +392,7 @@ aic_print_reg_dump_end(FILE *ofile, FILE *dfile,
|
||||
lower_name = strdup(regnode->symbol->name);
|
||||
if (lower_name == NULL)
|
||||
stop("Unable to strdup symbol name", EX_SOFTWARE);
|
||||
|
||||
|
||||
for (letter = lower_name; *letter != '\0'; letter++)
|
||||
*letter = tolower(*letter);
|
||||
|
||||
@ -472,6 +479,7 @@ symtable_dump(FILE *ofile, FILE *dfile)
|
||||
DBT key;
|
||||
DBT data;
|
||||
int flag;
|
||||
int reg_count = 0, reg_used = 0;
|
||||
u_int i;
|
||||
|
||||
if (symtable == NULL)
|
||||
@ -541,6 +549,9 @@ symtable_dump(FILE *ofile, FILE *dfile)
|
||||
int num_entries;
|
||||
|
||||
num_entries = 0;
|
||||
reg_count++;
|
||||
if (curnode->symbol->count == 1)
|
||||
break;
|
||||
fields = &curnode->symbol->info.rinfo->fields;
|
||||
SLIST_FOREACH(fieldnode, fields, links) {
|
||||
if (num_entries == 0)
|
||||
@ -553,11 +564,14 @@ symtable_dump(FILE *ofile, FILE *dfile)
|
||||
}
|
||||
aic_print_reg_dump_end(ofile, dfile,
|
||||
curnode, num_entries);
|
||||
reg_used++;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "%s: %d of %d register definitions used\n", appname,
|
||||
reg_used, reg_count);
|
||||
|
||||
/* Fold in the masks and bits */
|
||||
while (SLIST_FIRST(&masks) != NULL) {
|
||||
@ -646,7 +660,6 @@ symtable_dump(FILE *ofile, FILE *dfile)
|
||||
free(curnode);
|
||||
}
|
||||
|
||||
|
||||
fprintf(ofile, "\n\n/* Downloaded Constant Definitions */\n");
|
||||
|
||||
for (i = 0; SLIST_FIRST(&download_constants) != NULL; i++) {
|
||||
|
@ -128,6 +128,7 @@ typedef struct expression_info {
|
||||
typedef struct symbol {
|
||||
char *name;
|
||||
symtype type;
|
||||
int count;
|
||||
union {
|
||||
struct reg_info *rinfo;
|
||||
struct field_info *finfo;
|
||||
|
@ -2286,17 +2286,14 @@ static void flush_dev(struct scsi_device *dev, unsigned long cursec,
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t ihdlr(int irq, struct Scsi_Host *shost)
|
||||
static irqreturn_t ihdlr(struct Scsi_Host *shost)
|
||||
{
|
||||
struct scsi_cmnd *SCpnt;
|
||||
unsigned int i, k, c, status, tstatus, reg;
|
||||
struct mssp *spp;
|
||||
struct mscp *cpp;
|
||||
struct hostdata *ha = (struct hostdata *)shost->hostdata;
|
||||
|
||||
if (shost->irq != irq)
|
||||
panic("%s: ihdlr, irq %d, shost->irq %d.\n", ha->board_name, irq,
|
||||
shost->irq);
|
||||
int irq = shost->irq;
|
||||
|
||||
/* Check if this board need to be serviced */
|
||||
if (!(inb(shost->io_port + REG_AUX_STATUS) & IRQ_ASSERTED))
|
||||
@ -2535,7 +2532,7 @@ static irqreturn_t ihdlr(int irq, struct Scsi_Host *shost)
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static irqreturn_t do_interrupt_handler(int irq, void *shap)
|
||||
static irqreturn_t do_interrupt_handler(int dummy, void *shap)
|
||||
{
|
||||
struct Scsi_Host *shost;
|
||||
unsigned int j;
|
||||
@ -2548,7 +2545,7 @@ static irqreturn_t do_interrupt_handler(int irq, void *shap)
|
||||
shost = sh[j];
|
||||
|
||||
spin_lock_irqsave(shost->host_lock, spin_flags);
|
||||
ret = ihdlr(irq, shost);
|
||||
ret = ihdlr(shost);
|
||||
spin_unlock_irqrestore(shost->host_lock, spin_flags);
|
||||
return ret;
|
||||
}
|
||||
|
@ -978,7 +978,7 @@ static int esp_check_spur_intr(struct esp *esp)
|
||||
*/
|
||||
if (!esp->ops->dma_error(esp)) {
|
||||
printk(KERN_ERR PFX "esp%d: Spurious irq, "
|
||||
"sreg=%x.\n",
|
||||
"sreg=%02x.\n",
|
||||
esp->host->unique_id, esp->sreg);
|
||||
return -1;
|
||||
}
|
||||
@ -1447,6 +1447,9 @@ static void esp_msgin_sdtr(struct esp *esp, struct esp_target_data *tp)
|
||||
if (offset > 15)
|
||||
goto do_reject;
|
||||
|
||||
if (esp->flags & ESP_FLAG_DISABLE_SYNC)
|
||||
offset = 0;
|
||||
|
||||
if (offset) {
|
||||
int rounded_up, one_clock;
|
||||
|
||||
@ -1697,7 +1700,12 @@ static int esp_process_event(struct esp *esp)
|
||||
else
|
||||
ent->flags &= ~ESP_CMD_FLAG_WRITE;
|
||||
|
||||
dma_len = esp_dma_length_limit(esp, dma_addr, dma_len);
|
||||
if (esp->ops->dma_length_limit)
|
||||
dma_len = esp->ops->dma_length_limit(esp, dma_addr,
|
||||
dma_len);
|
||||
else
|
||||
dma_len = esp_dma_length_limit(esp, dma_addr, dma_len);
|
||||
|
||||
esp->data_dma_len = dma_len;
|
||||
|
||||
if (!dma_len) {
|
||||
@ -1761,7 +1769,6 @@ static int esp_process_event(struct esp *esp)
|
||||
esp_advance_dma(esp, ent, cmd, bytes_sent);
|
||||
esp_event(esp, ESP_EVENT_CHECK_PHASE);
|
||||
goto again;
|
||||
break;
|
||||
}
|
||||
|
||||
case ESP_EVENT_STATUS: {
|
||||
@ -2235,7 +2242,7 @@ static void esp_bootup_reset(struct esp *esp)
|
||||
|
||||
static void esp_set_clock_params(struct esp *esp)
|
||||
{
|
||||
int fmhz;
|
||||
int fhz;
|
||||
u8 ccf;
|
||||
|
||||
/* This is getting messy but it has to be done correctly or else
|
||||
@ -2270,9 +2277,9 @@ static void esp_set_clock_params(struct esp *esp)
|
||||
* This entails the smallest and largest sync period we could ever
|
||||
* handle on this ESP.
|
||||
*/
|
||||
fmhz = esp->cfreq;
|
||||
fhz = esp->cfreq;
|
||||
|
||||
ccf = ((fmhz / 1000000) + 4) / 5;
|
||||
ccf = ((fhz / 1000000) + 4) / 5;
|
||||
if (ccf == 1)
|
||||
ccf = 2;
|
||||
|
||||
@ -2281,16 +2288,16 @@ static void esp_set_clock_params(struct esp *esp)
|
||||
* been unable to find the clock-frequency PROM property. All
|
||||
* other machines provide useful values it seems.
|
||||
*/
|
||||
if (fmhz <= 5000000 || ccf < 1 || ccf > 8) {
|
||||
fmhz = 20000000;
|
||||
if (fhz <= 5000000 || ccf < 1 || ccf > 8) {
|
||||
fhz = 20000000;
|
||||
ccf = 4;
|
||||
}
|
||||
|
||||
esp->cfact = (ccf == 8 ? 0 : ccf);
|
||||
esp->cfreq = fmhz;
|
||||
esp->ccycle = ESP_MHZ_TO_CYCLE(fmhz);
|
||||
esp->cfreq = fhz;
|
||||
esp->ccycle = ESP_HZ_TO_CYCLE(fhz);
|
||||
esp->ctick = ESP_TICK(ccf, esp->ccycle);
|
||||
esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf);
|
||||
esp->neg_defp = ESP_NEG_DEFP(fhz, ccf);
|
||||
esp->sync_defp = SYNC_DEFP_SLOW;
|
||||
}
|
||||
|
||||
@ -2382,6 +2389,12 @@ static int esp_slave_configure(struct scsi_device *dev)
|
||||
struct esp_target_data *tp = &esp->target[dev->id];
|
||||
int goal_tags, queue_depth;
|
||||
|
||||
if (esp->flags & ESP_FLAG_DISABLE_SYNC) {
|
||||
/* Bypass async domain validation */
|
||||
dev->ppr = 0;
|
||||
dev->sdtr = 0;
|
||||
}
|
||||
|
||||
goal_tags = 0;
|
||||
|
||||
if (dev->tagged_supported) {
|
||||
|
@ -224,7 +224,7 @@
|
||||
#define ESP_TIMEO_CONST 8192
|
||||
#define ESP_NEG_DEFP(mhz, cfact) \
|
||||
((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (8192 * (cfact)))
|
||||
#define ESP_MHZ_TO_CYCLE(mhertz) ((1000000000) / ((mhertz) / 1000))
|
||||
#define ESP_HZ_TO_CYCLE(hertz) ((1000000000) / ((hertz) / 1000))
|
||||
#define ESP_TICK(ccf, cycle) ((7682 * (ccf) * (cycle) / 1000))
|
||||
|
||||
/* For slow to medium speed input clock rates we shoot for 5mb/s, but for high
|
||||
@ -240,9 +240,9 @@ struct esp_cmd_priv {
|
||||
int num_sg;
|
||||
} u;
|
||||
|
||||
unsigned int cur_residue;
|
||||
int cur_residue;
|
||||
struct scatterlist *cur_sg;
|
||||
unsigned int tot_residue;
|
||||
int tot_residue;
|
||||
};
|
||||
#define ESP_CMD_PRIV(CMD) ((struct esp_cmd_priv *)(&(CMD)->SCp))
|
||||
|
||||
@ -368,6 +368,12 @@ struct esp_driver_ops {
|
||||
*/
|
||||
int (*irq_pending)(struct esp *esp);
|
||||
|
||||
/* Return the maximum allowable size of a DMA transfer for a
|
||||
* given buffer.
|
||||
*/
|
||||
u32 (*dma_length_limit)(struct esp *esp, u32 dma_addr,
|
||||
u32 dma_len);
|
||||
|
||||
/* Reset the DMA engine entirely. On return, ESP interrupts
|
||||
* should be enabled. Often the interrupt enabling is
|
||||
* controlled in the DMA engine.
|
||||
@ -471,6 +477,7 @@ struct esp {
|
||||
#define ESP_FLAG_DOING_SLOWCMD 0x00000004
|
||||
#define ESP_FLAG_WIDE_CAPABLE 0x00000008
|
||||
#define ESP_FLAG_QUICKIRQ_CHECK 0x00000010
|
||||
#define ESP_FLAG_DISABLE_SYNC 0x00000020
|
||||
|
||||
u8 select_state;
|
||||
#define ESP_SELECT_NONE 0x00 /* Not selecting */
|
||||
|
@ -199,9 +199,13 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
|
||||
if (!shost->can_queue) {
|
||||
printk(KERN_ERR "%s: can_queue = 0 no longer supported\n",
|
||||
sht->name);
|
||||
goto out;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
error = scsi_setup_command_freelist(shost);
|
||||
if (error)
|
||||
goto fail;
|
||||
|
||||
if (!shost->shost_gendev.parent)
|
||||
shost->shost_gendev.parent = dev ? dev : &platform_bus;
|
||||
|
||||
@ -255,6 +259,8 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
|
||||
out_del_gendev:
|
||||
device_del(&shost->shost_gendev);
|
||||
out:
|
||||
scsi_destroy_command_freelist(shost);
|
||||
fail:
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL(scsi_add_host);
|
||||
@ -284,6 +290,11 @@ static void scsi_host_dev_release(struct device *dev)
|
||||
kfree(shost);
|
||||
}
|
||||
|
||||
struct device_type scsi_host_type = {
|
||||
.name = "scsi_host",
|
||||
.release = scsi_host_dev_release,
|
||||
};
|
||||
|
||||
/**
|
||||
* scsi_host_alloc - register a scsi host adapter instance.
|
||||
* @sht: pointer to scsi host template
|
||||
@ -376,33 +387,31 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
|
||||
else
|
||||
shost->dma_boundary = 0xffffffff;
|
||||
|
||||
rval = scsi_setup_command_freelist(shost);
|
||||
if (rval)
|
||||
goto fail_kfree;
|
||||
|
||||
device_initialize(&shost->shost_gendev);
|
||||
snprintf(shost->shost_gendev.bus_id, BUS_ID_SIZE, "host%d",
|
||||
shost->host_no);
|
||||
shost->shost_gendev.release = scsi_host_dev_release;
|
||||
#ifndef CONFIG_SYSFS_DEPRECATED
|
||||
shost->shost_gendev.bus = &scsi_bus_type;
|
||||
#endif
|
||||
shost->shost_gendev.type = &scsi_host_type;
|
||||
|
||||
device_initialize(&shost->shost_dev);
|
||||
shost->shost_dev.parent = &shost->shost_gendev;
|
||||
shost->shost_dev.class = &shost_class;
|
||||
snprintf(shost->shost_dev.bus_id, BUS_ID_SIZE, "host%d",
|
||||
shost->host_no);
|
||||
shost->shost_dev.groups = scsi_sysfs_shost_attr_groups;
|
||||
|
||||
shost->ehandler = kthread_run(scsi_error_handler, shost,
|
||||
"scsi_eh_%d", shost->host_no);
|
||||
if (IS_ERR(shost->ehandler)) {
|
||||
rval = PTR_ERR(shost->ehandler);
|
||||
goto fail_destroy_freelist;
|
||||
goto fail_kfree;
|
||||
}
|
||||
|
||||
scsi_proc_hostdir_add(shost->hostt);
|
||||
return shost;
|
||||
|
||||
fail_destroy_freelist:
|
||||
scsi_destroy_command_freelist(shost);
|
||||
fail_kfree:
|
||||
kfree(shost);
|
||||
return NULL;
|
||||
@ -496,7 +505,7 @@ void scsi_exit_hosts(void)
|
||||
|
||||
int scsi_is_host_device(const struct device *dev)
|
||||
{
|
||||
return dev->release == scsi_host_dev_release;
|
||||
return dev->type == &scsi_host_type;
|
||||
}
|
||||
EXPORT_SYMBOL(scsi_is_host_device);
|
||||
|
||||
|
@ -217,11 +217,15 @@ static int __devexit esp_jazz_remove(struct platform_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* work with hotplug and coldplug */
|
||||
MODULE_ALIAS("platform:jazz_esp");
|
||||
|
||||
static struct platform_driver esp_jazz_driver = {
|
||||
.probe = esp_jazz_probe,
|
||||
.remove = __devexit_p(esp_jazz_remove),
|
||||
.driver = {
|
||||
.name = "jazz_esp",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -182,8 +182,8 @@ lpfc_option_rom_version_show(struct device *dev, struct device_attribute *attr,
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", phba->OptionROMVersion);
|
||||
}
|
||||
static ssize_t
|
||||
lpfc_state_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
lpfc_link_state_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct Scsi_Host *shost = class_to_shost(dev);
|
||||
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
|
||||
@ -936,7 +936,7 @@ static DEVICE_ATTR(programtype, S_IRUGO, lpfc_programtype_show, NULL);
|
||||
static DEVICE_ATTR(portnum, S_IRUGO, lpfc_vportnum_show, NULL);
|
||||
static DEVICE_ATTR(fwrev, S_IRUGO, lpfc_fwrev_show, NULL);
|
||||
static DEVICE_ATTR(hdw, S_IRUGO, lpfc_hdw_show, NULL);
|
||||
static DEVICE_ATTR(state, S_IRUGO, lpfc_state_show, NULL);
|
||||
static DEVICE_ATTR(link_state, S_IRUGO, lpfc_link_state_show, NULL);
|
||||
static DEVICE_ATTR(option_rom_version, S_IRUGO,
|
||||
lpfc_option_rom_version_show, NULL);
|
||||
static DEVICE_ATTR(num_discovered_ports, S_IRUGO,
|
||||
@ -1666,7 +1666,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
|
||||
&dev_attr_fwrev,
|
||||
&dev_attr_hdw,
|
||||
&dev_attr_option_rom_version,
|
||||
&dev_attr_state,
|
||||
&dev_attr_link_state,
|
||||
&dev_attr_num_discovered_ports,
|
||||
&dev_attr_lpfc_drvr_version,
|
||||
&dev_attr_lpfc_temp_sensor,
|
||||
@ -1714,7 +1714,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
|
||||
|
||||
struct device_attribute *lpfc_vport_attrs[] = {
|
||||
&dev_attr_info,
|
||||
&dev_attr_state,
|
||||
&dev_attr_link_state,
|
||||
&dev_attr_num_discovered_ports,
|
||||
&dev_attr_lpfc_drvr_version,
|
||||
&dev_attr_lpfc_log_verbose,
|
||||
|
657
drivers/scsi/mac_esp.c
Normal file
657
drivers/scsi/mac_esp.c
Normal file
@ -0,0 +1,657 @@
|
||||
/* mac_esp.c: ESP front-end for Macintosh Quadra systems.
|
||||
*
|
||||
* Adapted from jazz_esp.c and the old mac_esp.c.
|
||||
*
|
||||
* The pseudo DMA algorithm is based on the one used in NetBSD.
|
||||
* See sys/arch/mac68k/obio/esp.c for some background information.
|
||||
*
|
||||
* Copyright (C) 2007-2008 Finn Thain
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/nubus.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/dma.h>
|
||||
|
||||
#include <asm/macints.h>
|
||||
#include <asm/macintosh.h>
|
||||
|
||||
#include <scsi/scsi_host.h>
|
||||
|
||||
#include "esp_scsi.h"
|
||||
|
||||
#define DRV_MODULE_NAME "mac_esp"
|
||||
#define PFX DRV_MODULE_NAME ": "
|
||||
#define DRV_VERSION "1.000"
|
||||
#define DRV_MODULE_RELDATE "Sept 15, 2007"
|
||||
|
||||
#define MAC_ESP_IO_BASE 0x50F00000
|
||||
#define MAC_ESP_REGS_QUADRA (MAC_ESP_IO_BASE + 0x10000)
|
||||
#define MAC_ESP_REGS_QUADRA2 (MAC_ESP_IO_BASE + 0xF000)
|
||||
#define MAC_ESP_REGS_QUADRA3 (MAC_ESP_IO_BASE + 0x18000)
|
||||
#define MAC_ESP_REGS_SPACING 0x402
|
||||
#define MAC_ESP_PDMA_REG 0xF9800024
|
||||
#define MAC_ESP_PDMA_REG_SPACING 0x4
|
||||
#define MAC_ESP_PDMA_IO_OFFSET 0x100
|
||||
|
||||
#define esp_read8(REG) mac_esp_read8(esp, REG)
|
||||
#define esp_write8(VAL, REG) mac_esp_write8(esp, VAL, REG)
|
||||
|
||||
struct mac_esp_priv {
|
||||
struct esp *esp;
|
||||
void __iomem *pdma_regs;
|
||||
void __iomem *pdma_io;
|
||||
int error;
|
||||
};
|
||||
static struct platform_device *internal_esp, *external_esp;
|
||||
|
||||
#define MAC_ESP_GET_PRIV(esp) ((struct mac_esp_priv *) \
|
||||
platform_get_drvdata((struct platform_device *) \
|
||||
(esp->dev)))
|
||||
|
||||
static inline void mac_esp_write8(struct esp *esp, u8 val, unsigned long reg)
|
||||
{
|
||||
nubus_writeb(val, esp->regs + reg * 16);
|
||||
}
|
||||
|
||||
static inline u8 mac_esp_read8(struct esp *esp, unsigned long reg)
|
||||
{
|
||||
return nubus_readb(esp->regs + reg * 16);
|
||||
}
|
||||
|
||||
/* For pseudo DMA and PIO we need the virtual address
|
||||
* so this address mapping is the identity mapping.
|
||||
*/
|
||||
|
||||
static dma_addr_t mac_esp_map_single(struct esp *esp, void *buf,
|
||||
size_t sz, int dir)
|
||||
{
|
||||
return (dma_addr_t)buf;
|
||||
}
|
||||
|
||||
static int mac_esp_map_sg(struct esp *esp, struct scatterlist *sg,
|
||||
int num_sg, int dir)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_sg; i++)
|
||||
sg[i].dma_address = (u32)sg_virt(&sg[i]);
|
||||
return num_sg;
|
||||
}
|
||||
|
||||
static void mac_esp_unmap_single(struct esp *esp, dma_addr_t addr,
|
||||
size_t sz, int dir)
|
||||
{
|
||||
/* Nothing to do. */
|
||||
}
|
||||
|
||||
static void mac_esp_unmap_sg(struct esp *esp, struct scatterlist *sg,
|
||||
int num_sg, int dir)
|
||||
{
|
||||
/* Nothing to do. */
|
||||
}
|
||||
|
||||
static void mac_esp_reset_dma(struct esp *esp)
|
||||
{
|
||||
/* Nothing to do. */
|
||||
}
|
||||
|
||||
static void mac_esp_dma_drain(struct esp *esp)
|
||||
{
|
||||
/* Nothing to do. */
|
||||
}
|
||||
|
||||
static void mac_esp_dma_invalidate(struct esp *esp)
|
||||
{
|
||||
/* Nothing to do. */
|
||||
}
|
||||
|
||||
static int mac_esp_dma_error(struct esp *esp)
|
||||
{
|
||||
return MAC_ESP_GET_PRIV(esp)->error;
|
||||
}
|
||||
|
||||
static inline int mac_esp_wait_for_empty_fifo(struct esp *esp)
|
||||
{
|
||||
struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp);
|
||||
int i = 500000;
|
||||
|
||||
do {
|
||||
if (!(esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES))
|
||||
return 0;
|
||||
|
||||
if (esp_read8(ESP_STATUS) & ESP_STAT_INTR)
|
||||
return 1;
|
||||
|
||||
udelay(2);
|
||||
} while (--i);
|
||||
|
||||
printk(KERN_ERR PFX "FIFO is not empty (sreg %02x)\n",
|
||||
esp_read8(ESP_STATUS));
|
||||
mep->error = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int mac_esp_wait_for_dreq(struct esp *esp)
|
||||
{
|
||||
struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp);
|
||||
int i = 500000;
|
||||
|
||||
do {
|
||||
if (mep->pdma_regs == NULL) {
|
||||
if (mac_irq_pending(IRQ_MAC_SCSIDRQ))
|
||||
return 0;
|
||||
} else {
|
||||
if (nubus_readl(mep->pdma_regs) & 0x200)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (esp_read8(ESP_STATUS) & ESP_STAT_INTR)
|
||||
return 1;
|
||||
|
||||
udelay(2);
|
||||
} while (--i);
|
||||
|
||||
printk(KERN_ERR PFX "PDMA timeout (sreg %02x)\n",
|
||||
esp_read8(ESP_STATUS));
|
||||
mep->error = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define MAC_ESP_PDMA_LOOP(operands) \
|
||||
asm volatile ( \
|
||||
" tstw %2 \n" \
|
||||
" jbeq 20f \n" \
|
||||
"1: movew " operands " \n" \
|
||||
"2: movew " operands " \n" \
|
||||
"3: movew " operands " \n" \
|
||||
"4: movew " operands " \n" \
|
||||
"5: movew " operands " \n" \
|
||||
"6: movew " operands " \n" \
|
||||
"7: movew " operands " \n" \
|
||||
"8: movew " operands " \n" \
|
||||
"9: movew " operands " \n" \
|
||||
"10: movew " operands " \n" \
|
||||
"11: movew " operands " \n" \
|
||||
"12: movew " operands " \n" \
|
||||
"13: movew " operands " \n" \
|
||||
"14: movew " operands " \n" \
|
||||
"15: movew " operands " \n" \
|
||||
"16: movew " operands " \n" \
|
||||
" subqw #1,%2 \n" \
|
||||
" jbne 1b \n" \
|
||||
"20: tstw %3 \n" \
|
||||
" jbeq 30f \n" \
|
||||
"21: movew " operands " \n" \
|
||||
" subqw #1,%3 \n" \
|
||||
" jbne 21b \n" \
|
||||
"30: tstw %4 \n" \
|
||||
" jbeq 40f \n" \
|
||||
"31: moveb " operands " \n" \
|
||||
"32: nop \n" \
|
||||
"40: \n" \
|
||||
" \n" \
|
||||
" .section __ex_table,\"a\" \n" \
|
||||
" .align 4 \n" \
|
||||
" .long 1b,40b \n" \
|
||||
" .long 2b,40b \n" \
|
||||
" .long 3b,40b \n" \
|
||||
" .long 4b,40b \n" \
|
||||
" .long 5b,40b \n" \
|
||||
" .long 6b,40b \n" \
|
||||
" .long 7b,40b \n" \
|
||||
" .long 8b,40b \n" \
|
||||
" .long 9b,40b \n" \
|
||||
" .long 10b,40b \n" \
|
||||
" .long 11b,40b \n" \
|
||||
" .long 12b,40b \n" \
|
||||
" .long 13b,40b \n" \
|
||||
" .long 14b,40b \n" \
|
||||
" .long 15b,40b \n" \
|
||||
" .long 16b,40b \n" \
|
||||
" .long 21b,40b \n" \
|
||||
" .long 31b,40b \n" \
|
||||
" .long 32b,40b \n" \
|
||||
" .previous \n" \
|
||||
: "+a" (addr) \
|
||||
: "a" (mep->pdma_io), "r" (count32), "r" (count2), "g" (esp_count))
|
||||
|
||||
static void mac_esp_send_pdma_cmd(struct esp *esp, u32 addr, u32 esp_count,
|
||||
u32 dma_count, int write, u8 cmd)
|
||||
{
|
||||
struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp);
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
mep->error = 0;
|
||||
|
||||
if (!write)
|
||||
scsi_esp_cmd(esp, ESP_CMD_FLUSH);
|
||||
|
||||
esp_write8((esp_count >> 0) & 0xFF, ESP_TCLOW);
|
||||
esp_write8((esp_count >> 8) & 0xFF, ESP_TCMED);
|
||||
|
||||
scsi_esp_cmd(esp, cmd);
|
||||
|
||||
do {
|
||||
unsigned int count32 = esp_count >> 5;
|
||||
unsigned int count2 = (esp_count & 0x1F) >> 1;
|
||||
unsigned int start_addr = addr;
|
||||
|
||||
if (mac_esp_wait_for_dreq(esp))
|
||||
break;
|
||||
|
||||
if (write) {
|
||||
MAC_ESP_PDMA_LOOP("%1@,%0@+");
|
||||
|
||||
esp_count -= addr - start_addr;
|
||||
} else {
|
||||
unsigned int n;
|
||||
|
||||
MAC_ESP_PDMA_LOOP("%0@+,%1@");
|
||||
|
||||
if (mac_esp_wait_for_empty_fifo(esp))
|
||||
break;
|
||||
|
||||
n = (esp_read8(ESP_TCMED) << 8) + esp_read8(ESP_TCLOW);
|
||||
addr = start_addr + esp_count - n;
|
||||
esp_count = n;
|
||||
}
|
||||
} while (esp_count);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Programmed IO routines follow.
|
||||
*/
|
||||
|
||||
static inline int mac_esp_wait_for_fifo(struct esp *esp)
|
||||
{
|
||||
int i = 500000;
|
||||
|
||||
do {
|
||||
if (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES)
|
||||
return 0;
|
||||
|
||||
udelay(2);
|
||||
} while (--i);
|
||||
|
||||
printk(KERN_ERR PFX "FIFO is empty (sreg %02x)\n",
|
||||
esp_read8(ESP_STATUS));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int mac_esp_wait_for_intr(struct esp *esp)
|
||||
{
|
||||
int i = 500000;
|
||||
|
||||
do {
|
||||
esp->sreg = esp_read8(ESP_STATUS);
|
||||
if (esp->sreg & ESP_STAT_INTR)
|
||||
return 0;
|
||||
|
||||
udelay(2);
|
||||
} while (--i);
|
||||
|
||||
printk(KERN_ERR PFX "IRQ timeout (sreg %02x)\n", esp->sreg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define MAC_ESP_PIO_LOOP(operands, reg1) \
|
||||
asm volatile ( \
|
||||
"1: moveb " operands " \n" \
|
||||
" subqw #1,%1 \n" \
|
||||
" jbne 1b \n" \
|
||||
: "+a" (addr), "+r" (reg1) \
|
||||
: "a" (fifo))
|
||||
|
||||
#define MAC_ESP_PIO_FILL(operands, reg1) \
|
||||
asm volatile ( \
|
||||
" moveb " operands " \n" \
|
||||
" moveb " operands " \n" \
|
||||
" moveb " operands " \n" \
|
||||
" moveb " operands " \n" \
|
||||
" moveb " operands " \n" \
|
||||
" moveb " operands " \n" \
|
||||
" moveb " operands " \n" \
|
||||
" moveb " operands " \n" \
|
||||
" moveb " operands " \n" \
|
||||
" moveb " operands " \n" \
|
||||
" moveb " operands " \n" \
|
||||
" moveb " operands " \n" \
|
||||
" moveb " operands " \n" \
|
||||
" moveb " operands " \n" \
|
||||
" moveb " operands " \n" \
|
||||
" moveb " operands " \n" \
|
||||
" subqw #8,%1 \n" \
|
||||
" subqw #8,%1 \n" \
|
||||
: "+a" (addr), "+r" (reg1) \
|
||||
: "a" (fifo))
|
||||
|
||||
#define MAC_ESP_FIFO_SIZE 16
|
||||
|
||||
static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count,
|
||||
u32 dma_count, int write, u8 cmd)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp);
|
||||
u8 *fifo = esp->regs + ESP_FDATA * 16;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
cmd &= ~ESP_CMD_DMA;
|
||||
mep->error = 0;
|
||||
|
||||
if (write) {
|
||||
scsi_esp_cmd(esp, cmd);
|
||||
|
||||
if (!mac_esp_wait_for_intr(esp)) {
|
||||
if (mac_esp_wait_for_fifo(esp))
|
||||
esp_count = 0;
|
||||
} else {
|
||||
esp_count = 0;
|
||||
}
|
||||
} else {
|
||||
scsi_esp_cmd(esp, ESP_CMD_FLUSH);
|
||||
|
||||
if (esp_count >= MAC_ESP_FIFO_SIZE)
|
||||
MAC_ESP_PIO_FILL("%0@+,%2@", esp_count);
|
||||
else
|
||||
MAC_ESP_PIO_LOOP("%0@+,%2@", esp_count);
|
||||
|
||||
scsi_esp_cmd(esp, cmd);
|
||||
}
|
||||
|
||||
while (esp_count) {
|
||||
unsigned int n;
|
||||
|
||||
if (mac_esp_wait_for_intr(esp)) {
|
||||
mep->error = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (esp->sreg & ESP_STAT_SPAM) {
|
||||
printk(KERN_ERR PFX "gross error\n");
|
||||
mep->error = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
n = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES;
|
||||
|
||||
if (write) {
|
||||
if (n > esp_count)
|
||||
n = esp_count;
|
||||
esp_count -= n;
|
||||
|
||||
MAC_ESP_PIO_LOOP("%2@,%0@+", n);
|
||||
|
||||
if ((esp->sreg & ESP_STAT_PMASK) == ESP_STATP)
|
||||
break;
|
||||
|
||||
if (esp_count) {
|
||||
esp->ireg = esp_read8(ESP_INTRPT);
|
||||
if (esp->ireg & ESP_INTR_DC)
|
||||
break;
|
||||
|
||||
scsi_esp_cmd(esp, ESP_CMD_TI);
|
||||
}
|
||||
} else {
|
||||
esp->ireg = esp_read8(ESP_INTRPT);
|
||||
if (esp->ireg & ESP_INTR_DC)
|
||||
break;
|
||||
|
||||
n = MAC_ESP_FIFO_SIZE - n;
|
||||
if (n > esp_count)
|
||||
n = esp_count;
|
||||
|
||||
if (n == MAC_ESP_FIFO_SIZE) {
|
||||
MAC_ESP_PIO_FILL("%0@+,%2@", esp_count);
|
||||
} else {
|
||||
esp_count -= n;
|
||||
MAC_ESP_PIO_LOOP("%0@+,%2@", n);
|
||||
}
|
||||
|
||||
scsi_esp_cmd(esp, ESP_CMD_TI);
|
||||
}
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static int mac_esp_irq_pending(struct esp *esp)
|
||||
{
|
||||
if (esp_read8(ESP_STATUS) & ESP_STAT_INTR)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 mac_esp_dma_length_limit(struct esp *esp, u32 dma_addr, u32 dma_len)
|
||||
{
|
||||
return dma_len > 0xFFFF ? 0xFFFF : dma_len;
|
||||
}
|
||||
|
||||
static struct esp_driver_ops mac_esp_ops = {
|
||||
.esp_write8 = mac_esp_write8,
|
||||
.esp_read8 = mac_esp_read8,
|
||||
.map_single = mac_esp_map_single,
|
||||
.map_sg = mac_esp_map_sg,
|
||||
.unmap_single = mac_esp_unmap_single,
|
||||
.unmap_sg = mac_esp_unmap_sg,
|
||||
.irq_pending = mac_esp_irq_pending,
|
||||
.dma_length_limit = mac_esp_dma_length_limit,
|
||||
.reset_dma = mac_esp_reset_dma,
|
||||
.dma_drain = mac_esp_dma_drain,
|
||||
.dma_invalidate = mac_esp_dma_invalidate,
|
||||
.send_dma_cmd = mac_esp_send_pdma_cmd,
|
||||
.dma_error = mac_esp_dma_error,
|
||||
};
|
||||
|
||||
static int __devinit esp_mac_probe(struct platform_device *dev)
|
||||
{
|
||||
struct scsi_host_template *tpnt = &scsi_esp_template;
|
||||
struct Scsi_Host *host;
|
||||
struct esp *esp;
|
||||
int err;
|
||||
int chips_present;
|
||||
struct mac_esp_priv *mep;
|
||||
|
||||
if (!MACH_IS_MAC)
|
||||
return -ENODEV;
|
||||
|
||||
switch (macintosh_config->scsi_type) {
|
||||
case MAC_SCSI_QUADRA:
|
||||
case MAC_SCSI_QUADRA3:
|
||||
chips_present = 1;
|
||||
break;
|
||||
case MAC_SCSI_QUADRA2:
|
||||
if ((macintosh_config->ident == MAC_MODEL_Q900) ||
|
||||
(macintosh_config->ident == MAC_MODEL_Q950))
|
||||
chips_present = 2;
|
||||
else
|
||||
chips_present = 1;
|
||||
break;
|
||||
default:
|
||||
chips_present = 0;
|
||||
}
|
||||
|
||||
if (dev->id + 1 > chips_present)
|
||||
return -ENODEV;
|
||||
|
||||
host = scsi_host_alloc(tpnt, sizeof(struct esp));
|
||||
|
||||
err = -ENOMEM;
|
||||
if (!host)
|
||||
goto fail;
|
||||
|
||||
host->max_id = 8;
|
||||
host->use_clustering = DISABLE_CLUSTERING;
|
||||
esp = shost_priv(host);
|
||||
|
||||
esp->host = host;
|
||||
esp->dev = dev;
|
||||
|
||||
esp->command_block = kzalloc(16, GFP_KERNEL);
|
||||
if (!esp->command_block)
|
||||
goto fail_unlink;
|
||||
esp->command_block_dma = (dma_addr_t)esp->command_block;
|
||||
|
||||
esp->scsi_id = 7;
|
||||
host->this_id = esp->scsi_id;
|
||||
esp->scsi_id_mask = 1 << esp->scsi_id;
|
||||
|
||||
mep = kzalloc(sizeof(struct mac_esp_priv), GFP_KERNEL);
|
||||
if (!mep)
|
||||
goto fail_free_command_block;
|
||||
mep->esp = esp;
|
||||
platform_set_drvdata(dev, mep);
|
||||
|
||||
switch (macintosh_config->scsi_type) {
|
||||
case MAC_SCSI_QUADRA:
|
||||
esp->cfreq = 16500000;
|
||||
esp->regs = (void __iomem *)MAC_ESP_REGS_QUADRA;
|
||||
mep->pdma_io = esp->regs + MAC_ESP_PDMA_IO_OFFSET;
|
||||
mep->pdma_regs = NULL;
|
||||
break;
|
||||
case MAC_SCSI_QUADRA2:
|
||||
esp->cfreq = 25000000;
|
||||
esp->regs = (void __iomem *)(MAC_ESP_REGS_QUADRA2 +
|
||||
dev->id * MAC_ESP_REGS_SPACING);
|
||||
mep->pdma_io = esp->regs + MAC_ESP_PDMA_IO_OFFSET;
|
||||
mep->pdma_regs = (void __iomem *)(MAC_ESP_PDMA_REG +
|
||||
dev->id * MAC_ESP_PDMA_REG_SPACING);
|
||||
nubus_writel(0x1d1, mep->pdma_regs);
|
||||
break;
|
||||
case MAC_SCSI_QUADRA3:
|
||||
/* These quadras have a real DMA controller (the PSC) but we
|
||||
* don't know how to drive it so we must use PIO instead.
|
||||
*/
|
||||
esp->cfreq = 25000000;
|
||||
esp->regs = (void __iomem *)MAC_ESP_REGS_QUADRA3;
|
||||
mep->pdma_io = NULL;
|
||||
mep->pdma_regs = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
esp->ops = &mac_esp_ops;
|
||||
if (mep->pdma_io == NULL) {
|
||||
printk(KERN_INFO PFX "using PIO for controller %d\n", dev->id);
|
||||
esp_write8(0, ESP_TCLOW);
|
||||
esp_write8(0, ESP_TCMED);
|
||||
esp->flags = ESP_FLAG_DISABLE_SYNC;
|
||||
mac_esp_ops.send_dma_cmd = mac_esp_send_pio_cmd;
|
||||
} else {
|
||||
printk(KERN_INFO PFX "using PDMA for controller %d\n", dev->id);
|
||||
}
|
||||
|
||||
host->irq = IRQ_MAC_SCSI;
|
||||
err = request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "Mac ESP",
|
||||
esp);
|
||||
if (err < 0)
|
||||
goto fail_free_priv;
|
||||
|
||||
err = scsi_esp_register(esp, &dev->dev);
|
||||
if (err)
|
||||
goto fail_free_irq;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_free_irq:
|
||||
free_irq(host->irq, esp);
|
||||
fail_free_priv:
|
||||
kfree(mep);
|
||||
fail_free_command_block:
|
||||
kfree(esp->command_block);
|
||||
fail_unlink:
|
||||
scsi_host_put(host);
|
||||
fail:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devexit esp_mac_remove(struct platform_device *dev)
|
||||
{
|
||||
struct mac_esp_priv *mep = platform_get_drvdata(dev);
|
||||
struct esp *esp = mep->esp;
|
||||
unsigned int irq = esp->host->irq;
|
||||
|
||||
scsi_esp_unregister(esp);
|
||||
|
||||
free_irq(irq, esp);
|
||||
|
||||
kfree(mep);
|
||||
|
||||
kfree(esp->command_block);
|
||||
|
||||
scsi_host_put(esp->host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver esp_mac_driver = {
|
||||
.probe = esp_mac_probe,
|
||||
.remove = __devexit_p(esp_mac_remove),
|
||||
.driver = {
|
||||
.name = DRV_MODULE_NAME,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init mac_esp_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = platform_driver_register(&esp_mac_driver);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
internal_esp = platform_device_alloc(DRV_MODULE_NAME, 0);
|
||||
if (internal_esp && platform_device_add(internal_esp)) {
|
||||
platform_device_put(internal_esp);
|
||||
internal_esp = NULL;
|
||||
}
|
||||
|
||||
external_esp = platform_device_alloc(DRV_MODULE_NAME, 1);
|
||||
if (external_esp && platform_device_add(external_esp)) {
|
||||
platform_device_put(external_esp);
|
||||
external_esp = NULL;
|
||||
}
|
||||
|
||||
if (internal_esp || external_esp) {
|
||||
return 0;
|
||||
} else {
|
||||
platform_driver_unregister(&esp_mac_driver);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
static void __exit mac_esp_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&esp_mac_driver);
|
||||
|
||||
if (internal_esp) {
|
||||
platform_device_unregister(internal_esp);
|
||||
internal_esp = NULL;
|
||||
}
|
||||
if (external_esp) {
|
||||
platform_device_unregister(external_esp);
|
||||
external_esp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
MODULE_DESCRIPTION("Mac ESP SCSI driver");
|
||||
MODULE_AUTHOR("Finn Thain <fthain@telegraphics.com.au>");
|
||||
MODULE_LICENSE("GPLv2");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
|
||||
module_init(mac_esp_init);
|
||||
module_exit(mac_esp_exit);
|
@ -609,8 +609,8 @@ qla2x00_pci_info_show(struct device *dev, struct device_attribute *attr,
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
qla2x00_state_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
qla2x00_link_state_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));
|
||||
int len = 0;
|
||||
@ -814,7 +814,7 @@ static DEVICE_ATTR(isp_id, S_IRUGO, qla2x00_isp_id_show, NULL);
|
||||
static DEVICE_ATTR(model_name, S_IRUGO, qla2x00_model_name_show, NULL);
|
||||
static DEVICE_ATTR(model_desc, S_IRUGO, qla2x00_model_desc_show, NULL);
|
||||
static DEVICE_ATTR(pci_info, S_IRUGO, qla2x00_pci_info_show, NULL);
|
||||
static DEVICE_ATTR(state, S_IRUGO, qla2x00_state_show, NULL);
|
||||
static DEVICE_ATTR(link_state, S_IRUGO, qla2x00_link_state_show, NULL);
|
||||
static DEVICE_ATTR(zio, S_IRUGO | S_IWUSR, qla2x00_zio_show, qla2x00_zio_store);
|
||||
static DEVICE_ATTR(zio_timer, S_IRUGO | S_IWUSR, qla2x00_zio_timer_show,
|
||||
qla2x00_zio_timer_store);
|
||||
@ -838,7 +838,7 @@ struct device_attribute *qla2x00_host_attrs[] = {
|
||||
&dev_attr_model_name,
|
||||
&dev_attr_model_desc,
|
||||
&dev_attr_pci_info,
|
||||
&dev_attr_state,
|
||||
&dev_attr_link_state,
|
||||
&dev_attr_zio,
|
||||
&dev_attr_zio_timer,
|
||||
&dev_attr_beacon,
|
||||
|
@ -38,28 +38,38 @@ qla2xxx_copy_queues(scsi_qla_host_t *ha, void *ptr)
|
||||
}
|
||||
|
||||
static int
|
||||
qla24xx_dump_memory(scsi_qla_host_t *ha, uint32_t *code_ram,
|
||||
uint32_t cram_size, uint32_t *ext_mem, void **nxt)
|
||||
qla24xx_dump_ram(scsi_qla_host_t *ha, uint32_t addr, uint32_t *ram,
|
||||
uint32_t ram_dwords, void **nxt)
|
||||
{
|
||||
int rval;
|
||||
uint32_t cnt, stat, timer, risc_address, ext_mem_cnt;
|
||||
uint16_t mb[4];
|
||||
uint32_t cnt, stat, timer, dwords, idx;
|
||||
uint16_t mb0;
|
||||
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
|
||||
dma_addr_t dump_dma = ha->gid_list_dma;
|
||||
uint32_t *dump = (uint32_t *)ha->gid_list;
|
||||
|
||||
rval = QLA_SUCCESS;
|
||||
risc_address = ext_mem_cnt = 0;
|
||||
memset(mb, 0, sizeof(mb));
|
||||
mb0 = 0;
|
||||
|
||||
/* Code RAM. */
|
||||
risc_address = 0x20000;
|
||||
WRT_REG_WORD(®->mailbox0, MBC_READ_RAM_EXTENDED);
|
||||
WRT_REG_WORD(®->mailbox0, MBC_DUMP_RISC_RAM_EXTENDED);
|
||||
clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
|
||||
|
||||
for (cnt = 0; cnt < cram_size / 4 && rval == QLA_SUCCESS;
|
||||
cnt++, risc_address++) {
|
||||
WRT_REG_WORD(®->mailbox1, LSW(risc_address));
|
||||
WRT_REG_WORD(®->mailbox8, MSW(risc_address));
|
||||
RD_REG_WORD(®->mailbox8);
|
||||
dwords = GID_LIST_SIZE / 4;
|
||||
for (cnt = 0; cnt < ram_dwords && rval == QLA_SUCCESS;
|
||||
cnt += dwords, addr += dwords) {
|
||||
if (cnt + dwords > ram_dwords)
|
||||
dwords = ram_dwords - cnt;
|
||||
|
||||
WRT_REG_WORD(®->mailbox1, LSW(addr));
|
||||
WRT_REG_WORD(®->mailbox8, MSW(addr));
|
||||
|
||||
WRT_REG_WORD(®->mailbox2, MSW(dump_dma));
|
||||
WRT_REG_WORD(®->mailbox3, LSW(dump_dma));
|
||||
WRT_REG_WORD(®->mailbox6, MSW(MSD(dump_dma)));
|
||||
WRT_REG_WORD(®->mailbox7, LSW(MSD(dump_dma)));
|
||||
|
||||
WRT_REG_WORD(®->mailbox4, MSW(dwords));
|
||||
WRT_REG_WORD(®->mailbox5, LSW(dwords));
|
||||
WRT_REG_DWORD(®->hccr, HCCRX_SET_HOST_INT);
|
||||
|
||||
for (timer = 6000000; timer; timer--) {
|
||||
@ -73,9 +83,7 @@ qla24xx_dump_memory(scsi_qla_host_t *ha, uint32_t *code_ram,
|
||||
set_bit(MBX_INTERRUPT,
|
||||
&ha->mbx_cmd_flags);
|
||||
|
||||
mb[0] = RD_REG_WORD(®->mailbox0);
|
||||
mb[2] = RD_REG_WORD(®->mailbox2);
|
||||
mb[3] = RD_REG_WORD(®->mailbox3);
|
||||
mb0 = RD_REG_WORD(®->mailbox0);
|
||||
|
||||
WRT_REG_DWORD(®->hccr,
|
||||
HCCRX_CLR_RISC_INT);
|
||||
@ -91,67 +99,34 @@ qla24xx_dump_memory(scsi_qla_host_t *ha, uint32_t *code_ram,
|
||||
}
|
||||
|
||||
if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
|
||||
rval = mb[0] & MBS_MASK;
|
||||
code_ram[cnt] = htonl((mb[3] << 16) | mb[2]);
|
||||
rval = mb0 & MBS_MASK;
|
||||
for (idx = 0; idx < dwords; idx++)
|
||||
ram[cnt + idx] = swab32(dump[idx]);
|
||||
} else {
|
||||
rval = QLA_FUNCTION_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
if (rval == QLA_SUCCESS) {
|
||||
/* External Memory. */
|
||||
risc_address = 0x100000;
|
||||
ext_mem_cnt = ha->fw_memory_size - 0x100000 + 1;
|
||||
WRT_REG_WORD(®->mailbox0, MBC_READ_RAM_EXTENDED);
|
||||
clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
|
||||
}
|
||||
for (cnt = 0; cnt < ext_mem_cnt && rval == QLA_SUCCESS;
|
||||
cnt++, risc_address++) {
|
||||
WRT_REG_WORD(®->mailbox1, LSW(risc_address));
|
||||
WRT_REG_WORD(®->mailbox8, MSW(risc_address));
|
||||
RD_REG_WORD(®->mailbox8);
|
||||
WRT_REG_DWORD(®->hccr, HCCRX_SET_HOST_INT);
|
||||
|
||||
for (timer = 6000000; timer; timer--) {
|
||||
/* Check for pending interrupts. */
|
||||
stat = RD_REG_DWORD(®->host_status);
|
||||
if (stat & HSRX_RISC_INT) {
|
||||
stat &= 0xff;
|
||||
|
||||
if (stat == 0x1 || stat == 0x2 ||
|
||||
stat == 0x10 || stat == 0x11) {
|
||||
set_bit(MBX_INTERRUPT,
|
||||
&ha->mbx_cmd_flags);
|
||||
|
||||
mb[0] = RD_REG_WORD(®->mailbox0);
|
||||
mb[2] = RD_REG_WORD(®->mailbox2);
|
||||
mb[3] = RD_REG_WORD(®->mailbox3);
|
||||
|
||||
WRT_REG_DWORD(®->hccr,
|
||||
HCCRX_CLR_RISC_INT);
|
||||
RD_REG_DWORD(®->hccr);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Clear this intr; it wasn't a mailbox intr */
|
||||
WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT);
|
||||
RD_REG_DWORD(®->hccr);
|
||||
}
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
|
||||
rval = mb[0] & MBS_MASK;
|
||||
ext_mem[cnt] = htonl((mb[3] << 16) | mb[2]);
|
||||
} else {
|
||||
rval = QLA_FUNCTION_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
*nxt = rval == QLA_SUCCESS ? &ext_mem[cnt]: NULL;
|
||||
*nxt = rval == QLA_SUCCESS ? &ram[cnt]: NULL;
|
||||
return rval;
|
||||
}
|
||||
|
||||
static int
|
||||
qla24xx_dump_memory(scsi_qla_host_t *ha, uint32_t *code_ram,
|
||||
uint32_t cram_size, void **nxt)
|
||||
{
|
||||
int rval;
|
||||
|
||||
/* Code RAM. */
|
||||
rval = qla24xx_dump_ram(ha, 0x20000, code_ram, cram_size / 4, nxt);
|
||||
if (rval != QLA_SUCCESS)
|
||||
return rval;
|
||||
|
||||
/* External Memory. */
|
||||
return qla24xx_dump_ram(ha, 0x100000, *nxt,
|
||||
ha->fw_memory_size - 0x100000 + 1, nxt);
|
||||
}
|
||||
|
||||
static uint32_t *
|
||||
qla24xx_read_window(struct device_reg_24xx __iomem *reg, uint32_t iobase,
|
||||
uint32_t count, uint32_t *buf)
|
||||
@ -239,6 +214,90 @@ qla24xx_soft_reset(scsi_qla_host_t *ha)
|
||||
return rval;
|
||||
}
|
||||
|
||||
static int
|
||||
qla2xxx_dump_ram(scsi_qla_host_t *ha, uint32_t addr, uint16_t *ram,
|
||||
uint16_t ram_words, void **nxt)
|
||||
{
|
||||
int rval;
|
||||
uint32_t cnt, stat, timer, words, idx;
|
||||
uint16_t mb0;
|
||||
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
|
||||
dma_addr_t dump_dma = ha->gid_list_dma;
|
||||
uint16_t *dump = (uint16_t *)ha->gid_list;
|
||||
|
||||
rval = QLA_SUCCESS;
|
||||
mb0 = 0;
|
||||
|
||||
WRT_MAILBOX_REG(ha, reg, 0, MBC_DUMP_RISC_RAM_EXTENDED);
|
||||
clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
|
||||
|
||||
words = GID_LIST_SIZE / 2;
|
||||
for (cnt = 0; cnt < ram_words && rval == QLA_SUCCESS;
|
||||
cnt += words, addr += words) {
|
||||
if (cnt + words > ram_words)
|
||||
words = ram_words - cnt;
|
||||
|
||||
WRT_MAILBOX_REG(ha, reg, 1, LSW(addr));
|
||||
WRT_MAILBOX_REG(ha, reg, 8, MSW(addr));
|
||||
|
||||
WRT_MAILBOX_REG(ha, reg, 2, MSW(dump_dma));
|
||||
WRT_MAILBOX_REG(ha, reg, 3, LSW(dump_dma));
|
||||
WRT_MAILBOX_REG(ha, reg, 6, MSW(MSD(dump_dma)));
|
||||
WRT_MAILBOX_REG(ha, reg, 7, LSW(MSD(dump_dma)));
|
||||
|
||||
WRT_MAILBOX_REG(ha, reg, 4, words);
|
||||
WRT_REG_WORD(®->hccr, HCCR_SET_HOST_INT);
|
||||
|
||||
for (timer = 6000000; timer; timer--) {
|
||||
/* Check for pending interrupts. */
|
||||
stat = RD_REG_DWORD(®->u.isp2300.host_status);
|
||||
if (stat & HSR_RISC_INT) {
|
||||
stat &= 0xff;
|
||||
|
||||
if (stat == 0x1 || stat == 0x2) {
|
||||
set_bit(MBX_INTERRUPT,
|
||||
&ha->mbx_cmd_flags);
|
||||
|
||||
mb0 = RD_MAILBOX_REG(ha, reg, 0);
|
||||
|
||||
/* Release mailbox registers. */
|
||||
WRT_REG_WORD(®->semaphore, 0);
|
||||
WRT_REG_WORD(®->hccr,
|
||||
HCCR_CLR_RISC_INT);
|
||||
RD_REG_WORD(®->hccr);
|
||||
break;
|
||||
} else if (stat == 0x10 || stat == 0x11) {
|
||||
set_bit(MBX_INTERRUPT,
|
||||
&ha->mbx_cmd_flags);
|
||||
|
||||
mb0 = RD_MAILBOX_REG(ha, reg, 0);
|
||||
|
||||
WRT_REG_WORD(®->hccr,
|
||||
HCCR_CLR_RISC_INT);
|
||||
RD_REG_WORD(®->hccr);
|
||||
break;
|
||||
}
|
||||
|
||||
/* clear this intr; it wasn't a mailbox intr */
|
||||
WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT);
|
||||
RD_REG_WORD(®->hccr);
|
||||
}
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
|
||||
rval = mb0 & MBS_MASK;
|
||||
for (idx = 0; idx < words; idx++)
|
||||
ram[cnt + idx] = swab16(dump[idx]);
|
||||
} else {
|
||||
rval = QLA_FUNCTION_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
*nxt = rval == QLA_SUCCESS ? &ram[cnt]: NULL;
|
||||
return rval;
|
||||
}
|
||||
|
||||
static inline void
|
||||
qla2xxx_read_window(struct device_reg_2xxx __iomem *reg, uint32_t count,
|
||||
uint16_t *buf)
|
||||
@ -258,19 +317,14 @@ void
|
||||
qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
|
||||
{
|
||||
int rval;
|
||||
uint32_t cnt, timer;
|
||||
uint32_t risc_address;
|
||||
uint16_t mb0, mb2;
|
||||
uint32_t cnt;
|
||||
|
||||
uint32_t stat;
|
||||
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
|
||||
uint16_t __iomem *dmp_reg;
|
||||
unsigned long flags;
|
||||
struct qla2300_fw_dump *fw;
|
||||
uint32_t data_ram_cnt;
|
||||
void *nxt;
|
||||
|
||||
risc_address = data_ram_cnt = 0;
|
||||
mb0 = mb2 = 0;
|
||||
flags = 0;
|
||||
|
||||
if (!hardware_locked)
|
||||
@ -388,185 +442,23 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
|
||||
}
|
||||
}
|
||||
|
||||
if (rval == QLA_SUCCESS) {
|
||||
/* Get RISC SRAM. */
|
||||
risc_address = 0x800;
|
||||
WRT_MAILBOX_REG(ha, reg, 0, MBC_READ_RAM_WORD);
|
||||
clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
|
||||
}
|
||||
for (cnt = 0; cnt < sizeof(fw->risc_ram) / 2 && rval == QLA_SUCCESS;
|
||||
cnt++, risc_address++) {
|
||||
WRT_MAILBOX_REG(ha, reg, 1, (uint16_t)risc_address);
|
||||
WRT_REG_WORD(®->hccr, HCCR_SET_HOST_INT);
|
||||
/* Get RISC SRAM. */
|
||||
if (rval == QLA_SUCCESS)
|
||||
rval = qla2xxx_dump_ram(ha, 0x800, fw->risc_ram,
|
||||
sizeof(fw->risc_ram) / 2, &nxt);
|
||||
|
||||
for (timer = 6000000; timer; timer--) {
|
||||
/* Check for pending interrupts. */
|
||||
stat = RD_REG_DWORD(®->u.isp2300.host_status);
|
||||
if (stat & HSR_RISC_INT) {
|
||||
stat &= 0xff;
|
||||
/* Get stack SRAM. */
|
||||
if (rval == QLA_SUCCESS)
|
||||
rval = qla2xxx_dump_ram(ha, 0x10000, fw->stack_ram,
|
||||
sizeof(fw->stack_ram) / 2, &nxt);
|
||||
|
||||
if (stat == 0x1 || stat == 0x2) {
|
||||
set_bit(MBX_INTERRUPT,
|
||||
&ha->mbx_cmd_flags);
|
||||
|
||||
mb0 = RD_MAILBOX_REG(ha, reg, 0);
|
||||
mb2 = RD_MAILBOX_REG(ha, reg, 2);
|
||||
|
||||
/* Release mailbox registers. */
|
||||
WRT_REG_WORD(®->semaphore, 0);
|
||||
WRT_REG_WORD(®->hccr,
|
||||
HCCR_CLR_RISC_INT);
|
||||
RD_REG_WORD(®->hccr);
|
||||
break;
|
||||
} else if (stat == 0x10 || stat == 0x11) {
|
||||
set_bit(MBX_INTERRUPT,
|
||||
&ha->mbx_cmd_flags);
|
||||
|
||||
mb0 = RD_MAILBOX_REG(ha, reg, 0);
|
||||
mb2 = RD_MAILBOX_REG(ha, reg, 2);
|
||||
|
||||
WRT_REG_WORD(®->hccr,
|
||||
HCCR_CLR_RISC_INT);
|
||||
RD_REG_WORD(®->hccr);
|
||||
break;
|
||||
}
|
||||
|
||||
/* clear this intr; it wasn't a mailbox intr */
|
||||
WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT);
|
||||
RD_REG_WORD(®->hccr);
|
||||
}
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
|
||||
rval = mb0 & MBS_MASK;
|
||||
fw->risc_ram[cnt] = htons(mb2);
|
||||
} else {
|
||||
rval = QLA_FUNCTION_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
if (rval == QLA_SUCCESS) {
|
||||
/* Get stack SRAM. */
|
||||
risc_address = 0x10000;
|
||||
WRT_MAILBOX_REG(ha, reg, 0, MBC_READ_RAM_EXTENDED);
|
||||
clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
|
||||
}
|
||||
for (cnt = 0; cnt < sizeof(fw->stack_ram) / 2 && rval == QLA_SUCCESS;
|
||||
cnt++, risc_address++) {
|
||||
WRT_MAILBOX_REG(ha, reg, 1, LSW(risc_address));
|
||||
WRT_MAILBOX_REG(ha, reg, 8, MSW(risc_address));
|
||||
WRT_REG_WORD(®->hccr, HCCR_SET_HOST_INT);
|
||||
|
||||
for (timer = 6000000; timer; timer--) {
|
||||
/* Check for pending interrupts. */
|
||||
stat = RD_REG_DWORD(®->u.isp2300.host_status);
|
||||
if (stat & HSR_RISC_INT) {
|
||||
stat &= 0xff;
|
||||
|
||||
if (stat == 0x1 || stat == 0x2) {
|
||||
set_bit(MBX_INTERRUPT,
|
||||
&ha->mbx_cmd_flags);
|
||||
|
||||
mb0 = RD_MAILBOX_REG(ha, reg, 0);
|
||||
mb2 = RD_MAILBOX_REG(ha, reg, 2);
|
||||
|
||||
/* Release mailbox registers. */
|
||||
WRT_REG_WORD(®->semaphore, 0);
|
||||
WRT_REG_WORD(®->hccr,
|
||||
HCCR_CLR_RISC_INT);
|
||||
RD_REG_WORD(®->hccr);
|
||||
break;
|
||||
} else if (stat == 0x10 || stat == 0x11) {
|
||||
set_bit(MBX_INTERRUPT,
|
||||
&ha->mbx_cmd_flags);
|
||||
|
||||
mb0 = RD_MAILBOX_REG(ha, reg, 0);
|
||||
mb2 = RD_MAILBOX_REG(ha, reg, 2);
|
||||
|
||||
WRT_REG_WORD(®->hccr,
|
||||
HCCR_CLR_RISC_INT);
|
||||
RD_REG_WORD(®->hccr);
|
||||
break;
|
||||
}
|
||||
|
||||
/* clear this intr; it wasn't a mailbox intr */
|
||||
WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT);
|
||||
RD_REG_WORD(®->hccr);
|
||||
}
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
|
||||
rval = mb0 & MBS_MASK;
|
||||
fw->stack_ram[cnt] = htons(mb2);
|
||||
} else {
|
||||
rval = QLA_FUNCTION_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
if (rval == QLA_SUCCESS) {
|
||||
/* Get data SRAM. */
|
||||
risc_address = 0x11000;
|
||||
data_ram_cnt = ha->fw_memory_size - risc_address + 1;
|
||||
WRT_MAILBOX_REG(ha, reg, 0, MBC_READ_RAM_EXTENDED);
|
||||
clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
|
||||
}
|
||||
for (cnt = 0; cnt < data_ram_cnt && rval == QLA_SUCCESS;
|
||||
cnt++, risc_address++) {
|
||||
WRT_MAILBOX_REG(ha, reg, 1, LSW(risc_address));
|
||||
WRT_MAILBOX_REG(ha, reg, 8, MSW(risc_address));
|
||||
WRT_REG_WORD(®->hccr, HCCR_SET_HOST_INT);
|
||||
|
||||
for (timer = 6000000; timer; timer--) {
|
||||
/* Check for pending interrupts. */
|
||||
stat = RD_REG_DWORD(®->u.isp2300.host_status);
|
||||
if (stat & HSR_RISC_INT) {
|
||||
stat &= 0xff;
|
||||
|
||||
if (stat == 0x1 || stat == 0x2) {
|
||||
set_bit(MBX_INTERRUPT,
|
||||
&ha->mbx_cmd_flags);
|
||||
|
||||
mb0 = RD_MAILBOX_REG(ha, reg, 0);
|
||||
mb2 = RD_MAILBOX_REG(ha, reg, 2);
|
||||
|
||||
/* Release mailbox registers. */
|
||||
WRT_REG_WORD(®->semaphore, 0);
|
||||
WRT_REG_WORD(®->hccr,
|
||||
HCCR_CLR_RISC_INT);
|
||||
RD_REG_WORD(®->hccr);
|
||||
break;
|
||||
} else if (stat == 0x10 || stat == 0x11) {
|
||||
set_bit(MBX_INTERRUPT,
|
||||
&ha->mbx_cmd_flags);
|
||||
|
||||
mb0 = RD_MAILBOX_REG(ha, reg, 0);
|
||||
mb2 = RD_MAILBOX_REG(ha, reg, 2);
|
||||
|
||||
WRT_REG_WORD(®->hccr,
|
||||
HCCR_CLR_RISC_INT);
|
||||
RD_REG_WORD(®->hccr);
|
||||
break;
|
||||
}
|
||||
|
||||
/* clear this intr; it wasn't a mailbox intr */
|
||||
WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT);
|
||||
RD_REG_WORD(®->hccr);
|
||||
}
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
|
||||
rval = mb0 & MBS_MASK;
|
||||
fw->data_ram[cnt] = htons(mb2);
|
||||
} else {
|
||||
rval = QLA_FUNCTION_FAILED;
|
||||
}
|
||||
}
|
||||
/* Get data SRAM. */
|
||||
if (rval == QLA_SUCCESS)
|
||||
rval = qla2xxx_dump_ram(ha, 0x11000, fw->data_ram,
|
||||
ha->fw_memory_size - 0x11000 + 1, &nxt);
|
||||
|
||||
if (rval == QLA_SUCCESS)
|
||||
qla2xxx_copy_queues(ha, &fw->data_ram[cnt]);
|
||||
qla2xxx_copy_queues(ha, nxt);
|
||||
|
||||
if (rval != QLA_SUCCESS) {
|
||||
qla_printk(KERN_WARNING, ha,
|
||||
@ -1010,7 +902,7 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
|
||||
goto qla24xx_fw_dump_failed_0;
|
||||
|
||||
rval = qla24xx_dump_memory(ha, fw->code_ram, sizeof(fw->code_ram),
|
||||
fw->ext_mem, &nxt);
|
||||
&nxt);
|
||||
if (rval != QLA_SUCCESS)
|
||||
goto qla24xx_fw_dump_failed_0;
|
||||
|
||||
@ -1318,7 +1210,7 @@ qla25xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
|
||||
goto qla25xx_fw_dump_failed_0;
|
||||
|
||||
rval = qla24xx_dump_memory(ha, fw->code_ram, sizeof(fw->code_ram),
|
||||
fw->ext_mem, &nxt);
|
||||
&nxt);
|
||||
if (rval != QLA_SUCCESS)
|
||||
goto qla25xx_fw_dump_failed_0;
|
||||
|
||||
|
@ -1036,22 +1036,6 @@ struct mid_db_entry_24xx {
|
||||
uint8_t reserved_1;
|
||||
};
|
||||
|
||||
/*
|
||||
* Virtual Fabric ID type definition.
|
||||
*/
|
||||
typedef struct vf_id {
|
||||
uint16_t id : 12;
|
||||
uint16_t priority : 4;
|
||||
} vf_id_t;
|
||||
|
||||
/*
|
||||
* Virtual Fabric HopCt type definition.
|
||||
*/
|
||||
typedef struct vf_hopct {
|
||||
uint16_t reserved : 8;
|
||||
uint16_t hopct : 8;
|
||||
} vf_hopct_t;
|
||||
|
||||
/*
|
||||
* Virtual Port Control IOCB
|
||||
*/
|
||||
@ -1082,10 +1066,10 @@ struct vp_ctrl_entry_24xx {
|
||||
|
||||
uint8_t vp_idx_map[16];
|
||||
uint16_t flags;
|
||||
struct vf_id id;
|
||||
uint16_t id;
|
||||
uint16_t reserved_4;
|
||||
struct vf_hopct hopct;
|
||||
uint8_t reserved_5[8];
|
||||
uint16_t hopct;
|
||||
uint8_t reserved_5[24];
|
||||
};
|
||||
|
||||
/*
|
||||
@ -1132,9 +1116,9 @@ struct vp_config_entry_24xx {
|
||||
uint16_t reserved_vp2;
|
||||
uint8_t port_name_idx2[WWN_SIZE];
|
||||
uint8_t node_name_idx2[WWN_SIZE];
|
||||
struct vf_id id;
|
||||
uint16_t id;
|
||||
uint16_t reserved_4;
|
||||
struct vf_hopct hopct;
|
||||
uint16_t hopct;
|
||||
uint8_t reserved_5;
|
||||
};
|
||||
|
||||
|
@ -151,10 +151,6 @@ qla2x00_verify_checksum(scsi_qla_host_t *, uint32_t);
|
||||
extern int
|
||||
qla2x00_issue_iocb(scsi_qla_host_t *, void *, dma_addr_t, size_t);
|
||||
|
||||
extern int
|
||||
qla2x00_issue_iocb_timeout(scsi_qla_host_t *, void *, dma_addr_t, size_t,
|
||||
uint32_t);
|
||||
|
||||
extern int
|
||||
qla2x00_abort_command(scsi_qla_host_t *, srb_t *);
|
||||
|
||||
|
@ -1583,8 +1583,8 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
|
||||
eiter->type = __constant_cpu_to_be16(FDMI_PORT_MAX_FRAME_SIZE);
|
||||
eiter->len = __constant_cpu_to_be16(4 + 4);
|
||||
max_frame_size = IS_FWI2_CAPABLE(ha) ?
|
||||
(uint32_t) icb24->frame_payload_size:
|
||||
(uint32_t) ha->init_cb->frame_payload_size;
|
||||
le16_to_cpu(icb24->frame_payload_size):
|
||||
le16_to_cpu(ha->init_cb->frame_payload_size);
|
||||
eiter->a.max_frame_size = cpu_to_be32(max_frame_size);
|
||||
size += 4 + 4;
|
||||
|
||||
|
@ -3645,7 +3645,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
|
||||
if (le16_to_cpu(nv->login_timeout) < 4)
|
||||
nv->login_timeout = __constant_cpu_to_le16(4);
|
||||
ha->login_timeout = le16_to_cpu(nv->login_timeout);
|
||||
icb->login_timeout = cpu_to_le16(nv->login_timeout);
|
||||
icb->login_timeout = nv->login_timeout;
|
||||
|
||||
/* Set minimum RATOV to 100 tenths of a second. */
|
||||
ha->r_a_tov = 100;
|
||||
|
@ -409,6 +409,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
|
||||
}
|
||||
|
||||
set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags);
|
||||
set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
|
||||
|
||||
ha->flags.management_server_logged_in = 0;
|
||||
qla2x00_post_aen_work(ha, FCH_EVT_LIP, mb[1]);
|
||||
@ -454,8 +455,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
|
||||
|
||||
ha->flags.management_server_logged_in = 0;
|
||||
ha->link_data_rate = PORT_SPEED_UNKNOWN;
|
||||
if (ql2xfdmienable)
|
||||
set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
|
||||
qla2x00_post_aen_work(ha, FCH_EVT_LINKDOWN, 0);
|
||||
break;
|
||||
|
||||
@ -511,6 +510,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
|
||||
set_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
|
||||
}
|
||||
set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags);
|
||||
set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
|
||||
|
||||
ha->flags.gpsc_supported = 1;
|
||||
ha->flags.management_server_logged_in = 0;
|
||||
|
@ -681,7 +681,7 @@ qla2x00_verify_checksum(scsi_qla_host_t *ha, uint32_t risc_addr)
|
||||
* Context:
|
||||
* Kernel context.
|
||||
*/
|
||||
int
|
||||
static int
|
||||
qla2x00_issue_iocb_timeout(scsi_qla_host_t *ha, void *buffer,
|
||||
dma_addr_t phys_addr, size_t size, uint32_t tov)
|
||||
{
|
||||
@ -784,7 +784,6 @@ qla2x00_abort_command(scsi_qla_host_t *ha, srb_t *sp)
|
||||
DEBUG2_3_11(printk("qla2x00_abort_command(%ld): failed=%x.\n",
|
||||
ha->host_no, rval));
|
||||
} else {
|
||||
sp->flags |= SRB_ABORT_PENDING;
|
||||
DEBUG11(printk("qla2x00_abort_command(%ld): done.\n",
|
||||
ha->host_no));
|
||||
}
|
||||
@ -1469,7 +1468,7 @@ qla24xx_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
|
||||
lg->port_id[0] = al_pa;
|
||||
lg->port_id[1] = area;
|
||||
lg->port_id[2] = domain;
|
||||
lg->vp_index = cpu_to_le16(ha->vp_idx);
|
||||
lg->vp_index = ha->vp_idx;
|
||||
rval = qla2x00_issue_iocb(ha, lg, lg_dma, 0);
|
||||
if (rval != QLA_SUCCESS) {
|
||||
DEBUG2_3_11(printk("%s(%ld): failed to issue Login IOCB "
|
||||
@ -1724,7 +1723,7 @@ qla24xx_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
|
||||
lg->port_id[0] = al_pa;
|
||||
lg->port_id[1] = area;
|
||||
lg->port_id[2] = domain;
|
||||
lg->vp_index = cpu_to_le16(ha->vp_idx);
|
||||
lg->vp_index = ha->vp_idx;
|
||||
rval = qla2x00_issue_iocb(ha, lg, lg_dma, 0);
|
||||
if (rval != QLA_SUCCESS) {
|
||||
DEBUG2_3_11(printk("%s(%ld): failed to issue Logout IOCB "
|
||||
@ -2210,7 +2209,6 @@ qla24xx_abort_command(scsi_qla_host_t *ha, srb_t *sp)
|
||||
rval = QLA_FUNCTION_FAILED;
|
||||
} else {
|
||||
DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
|
||||
sp->flags |= SRB_ABORT_PENDING;
|
||||
}
|
||||
|
||||
dma_pool_free(ha->s_dma_pool, abt, abt_dma);
|
||||
@ -2644,12 +2642,11 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *ha,
|
||||
struct vp_rpt_id_entry_24xx *rptid_entry)
|
||||
{
|
||||
uint8_t vp_idx;
|
||||
uint16_t stat = le16_to_cpu(rptid_entry->vp_idx);
|
||||
scsi_qla_host_t *vha;
|
||||
|
||||
if (rptid_entry->entry_status != 0)
|
||||
return;
|
||||
if (rptid_entry->entry_status != __constant_cpu_to_le16(CS_COMPLETE))
|
||||
return;
|
||||
|
||||
if (rptid_entry->format == 0) {
|
||||
DEBUG15(printk("%s:format 0 : scsi(%ld) number of VPs setup %d,"
|
||||
@ -2659,17 +2656,17 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *ha,
|
||||
rptid_entry->port_id[2], rptid_entry->port_id[1],
|
||||
rptid_entry->port_id[0]));
|
||||
} else if (rptid_entry->format == 1) {
|
||||
vp_idx = LSB(rptid_entry->vp_idx);
|
||||
vp_idx = LSB(stat);
|
||||
DEBUG15(printk("%s:format 1: scsi(%ld): VP[%d] enabled "
|
||||
"- status %d - "
|
||||
"with port id %02x%02x%02x\n",__func__,ha->host_no,
|
||||
vp_idx, MSB(rptid_entry->vp_idx),
|
||||
vp_idx, MSB(stat),
|
||||
rptid_entry->port_id[2], rptid_entry->port_id[1],
|
||||
rptid_entry->port_id[0]));
|
||||
if (vp_idx == 0)
|
||||
return;
|
||||
|
||||
if (MSB(rptid_entry->vp_idx) == 1)
|
||||
if (MSB(stat) == 1)
|
||||
return;
|
||||
|
||||
list_for_each_entry(vha, &ha->vp_list, vp_list)
|
||||
@ -2982,8 +2979,8 @@ qla84xx_verify_chip(struct scsi_qla_host *ha, uint16_t *status)
|
||||
/* We update the firmware with only one data sequence. */
|
||||
options |= VCO_END_OF_DATA;
|
||||
|
||||
retry = 0;
|
||||
do {
|
||||
retry = 0;
|
||||
memset(mn, 0, sizeof(*mn));
|
||||
mn->p.req.entry_type = VERIFY_CHIP_IOCB_TYPE;
|
||||
mn->p.req.entry_count = 1;
|
||||
|
@ -67,7 +67,7 @@ static void qla2x00_free_device(scsi_qla_host_t *);
|
||||
|
||||
static void qla2x00_config_dma_addressing(scsi_qla_host_t *ha);
|
||||
|
||||
int ql2xfdmienable;
|
||||
int ql2xfdmienable=1;
|
||||
module_param(ql2xfdmienable, int, S_IRUGO|S_IRUSR);
|
||||
MODULE_PARM_DESC(ql2xfdmienable,
|
||||
"Enables FDMI registratons "
|
||||
@ -2135,7 +2135,7 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
|
||||
kfree(ha->nvram);
|
||||
}
|
||||
|
||||
struct qla_work_evt *
|
||||
static struct qla_work_evt *
|
||||
qla2x00_alloc_work(struct scsi_qla_host *ha, enum qla_work_type type,
|
||||
int locked)
|
||||
{
|
||||
@ -2152,7 +2152,7 @@ qla2x00_alloc_work(struct scsi_qla_host *ha, enum qla_work_type type,
|
||||
return e;
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
qla2x00_post_work(struct scsi_qla_host *ha, struct qla_work_evt *e, int locked)
|
||||
{
|
||||
unsigned long flags;
|
||||
@ -2373,7 +2373,7 @@ qla2x00_do_dpc(void *data)
|
||||
} else {
|
||||
fcport->login_retry = 0;
|
||||
}
|
||||
if (fcport->login_retry == 0)
|
||||
if (fcport->login_retry == 0 && status != QLA_SUCCESS)
|
||||
fcport->loop_id = FC_NO_LOOP_ID;
|
||||
}
|
||||
if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
|
||||
@ -2599,6 +2599,10 @@ qla2x00_timer(scsi_qla_host_t *ha)
|
||||
start_dpc++;
|
||||
}
|
||||
|
||||
/* Process any deferred work. */
|
||||
if (!list_empty(&ha->work_list))
|
||||
start_dpc++;
|
||||
|
||||
/* Schedule the DPC routine if needed */
|
||||
if ((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) ||
|
||||
test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) ||
|
||||
|
@ -7,7 +7,7 @@
|
||||
/*
|
||||
* Driver version
|
||||
*/
|
||||
#define QLA2XXX_VERSION "8.02.01-k1"
|
||||
#define QLA2XXX_VERSION "8.02.01-k2"
|
||||
|
||||
#define QLA_DRIVER_MAJOR_VER 8
|
||||
#define QLA_DRIVER_MINOR_VER 2
|
||||
|
@ -121,6 +121,7 @@ extern struct scsi_transport_template blank_transport_template;
|
||||
extern void __scsi_remove_device(struct scsi_device *);
|
||||
|
||||
extern struct bus_type scsi_bus_type;
|
||||
extern struct attribute_group *scsi_sysfs_shost_attr_groups[];
|
||||
|
||||
/* scsi_netlink.c */
|
||||
#ifdef CONFIG_SCSI_NETLINK
|
||||
|
@ -190,10 +190,14 @@ void scsi_proc_host_rm(struct Scsi_Host *shost)
|
||||
*/
|
||||
static int proc_print_scsidevice(struct device *dev, void *data)
|
||||
{
|
||||
struct scsi_device *sdev = to_scsi_device(dev);
|
||||
struct scsi_device *sdev;
|
||||
struct seq_file *s = data;
|
||||
int i;
|
||||
|
||||
if (!scsi_is_sdev_device(dev))
|
||||
goto out;
|
||||
|
||||
sdev = to_scsi_device(dev);
|
||||
seq_printf(s,
|
||||
"Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n Vendor: ",
|
||||
sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
|
||||
@ -230,6 +234,7 @@ static int proc_print_scsidevice(struct device *dev, void *data)
|
||||
else
|
||||
seq_printf(s, "\n");
|
||||
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -322,6 +322,21 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void scsi_target_destroy(struct scsi_target *starget)
|
||||
{
|
||||
struct device *dev = &starget->dev;
|
||||
struct Scsi_Host *shost = dev_to_shost(dev->parent);
|
||||
unsigned long flags;
|
||||
|
||||
transport_destroy_device(dev);
|
||||
spin_lock_irqsave(shost->host_lock, flags);
|
||||
if (shost->hostt->target_destroy)
|
||||
shost->hostt->target_destroy(starget);
|
||||
list_del_init(&starget->siblings);
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
put_device(dev);
|
||||
}
|
||||
|
||||
static void scsi_target_dev_release(struct device *dev)
|
||||
{
|
||||
struct device *parent = dev->parent;
|
||||
@ -331,9 +346,14 @@ static void scsi_target_dev_release(struct device *dev)
|
||||
put_device(parent);
|
||||
}
|
||||
|
||||
struct device_type scsi_target_type = {
|
||||
.name = "scsi_target",
|
||||
.release = scsi_target_dev_release,
|
||||
};
|
||||
|
||||
int scsi_is_target_device(const struct device *dev)
|
||||
{
|
||||
return dev->release == scsi_target_dev_release;
|
||||
return dev->type == &scsi_target_type;
|
||||
}
|
||||
EXPORT_SYMBOL(scsi_is_target_device);
|
||||
|
||||
@ -391,14 +411,17 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
|
||||
device_initialize(dev);
|
||||
starget->reap_ref = 1;
|
||||
dev->parent = get_device(parent);
|
||||
dev->release = scsi_target_dev_release;
|
||||
sprintf(dev->bus_id, "target%d:%d:%d",
|
||||
shost->host_no, channel, id);
|
||||
#ifndef CONFIG_SYSFS_DEPRECATED
|
||||
dev->bus = &scsi_bus_type;
|
||||
#endif
|
||||
dev->type = &scsi_target_type;
|
||||
starget->id = id;
|
||||
starget->channel = channel;
|
||||
INIT_LIST_HEAD(&starget->siblings);
|
||||
INIT_LIST_HEAD(&starget->devices);
|
||||
starget->state = STARGET_RUNNING;
|
||||
starget->state = STARGET_CREATED;
|
||||
starget->scsi_level = SCSI_2;
|
||||
retry:
|
||||
spin_lock_irqsave(shost->host_lock, flags);
|
||||
@ -411,18 +434,6 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
/* allocate and add */
|
||||
transport_setup_device(dev);
|
||||
error = device_add(dev);
|
||||
if (error) {
|
||||
dev_err(dev, "target device_add failed, error %d\n", error);
|
||||
spin_lock_irqsave(shost->host_lock, flags);
|
||||
list_del_init(&starget->siblings);
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
transport_destroy_device(dev);
|
||||
put_device(parent);
|
||||
kfree(starget);
|
||||
return NULL;
|
||||
}
|
||||
transport_add_device(dev);
|
||||
if (shost->hostt->target_alloc) {
|
||||
error = shost->hostt->target_alloc(starget);
|
||||
|
||||
@ -430,9 +441,7 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
|
||||
dev_printk(KERN_ERR, dev, "target allocation failed, error %d\n", error);
|
||||
/* don't want scsi_target_reap to do the final
|
||||
* put because it will be under the host lock */
|
||||
get_device(dev);
|
||||
scsi_target_reap(starget);
|
||||
put_device(dev);
|
||||
scsi_target_destroy(starget);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@ -459,18 +468,10 @@ static void scsi_target_reap_usercontext(struct work_struct *work)
|
||||
{
|
||||
struct scsi_target *starget =
|
||||
container_of(work, struct scsi_target, ew.work);
|
||||
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
|
||||
unsigned long flags;
|
||||
|
||||
transport_remove_device(&starget->dev);
|
||||
device_del(&starget->dev);
|
||||
transport_destroy_device(&starget->dev);
|
||||
spin_lock_irqsave(shost->host_lock, flags);
|
||||
if (shost->hostt->target_destroy)
|
||||
shost->hostt->target_destroy(starget);
|
||||
list_del_init(&starget->siblings);
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
put_device(&starget->dev);
|
||||
scsi_target_destroy(starget);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -485,21 +486,25 @@ void scsi_target_reap(struct scsi_target *starget)
|
||||
{
|
||||
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
|
||||
unsigned long flags;
|
||||
enum scsi_target_state state;
|
||||
int empty;
|
||||
|
||||
spin_lock_irqsave(shost->host_lock, flags);
|
||||
|
||||
if (--starget->reap_ref == 0 && list_empty(&starget->devices)) {
|
||||
BUG_ON(starget->state == STARGET_DEL);
|
||||
starget->state = STARGET_DEL;
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
execute_in_process_context(scsi_target_reap_usercontext,
|
||||
&starget->ew);
|
||||
return;
|
||||
|
||||
}
|
||||
state = starget->state;
|
||||
empty = --starget->reap_ref == 0 &&
|
||||
list_empty(&starget->devices) ? 1 : 0;
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
|
||||
return;
|
||||
if (!empty)
|
||||
return;
|
||||
|
||||
BUG_ON(state == STARGET_DEL);
|
||||
starget->state = STARGET_DEL;
|
||||
if (state == STARGET_CREATED)
|
||||
scsi_target_destroy(starget);
|
||||
else
|
||||
execute_in_process_context(scsi_target_reap_usercontext,
|
||||
&starget->ew);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1048,8 +1053,9 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
|
||||
scsi_inq_str(vend, result, 8, 16),
|
||||
scsi_inq_str(mod, result, 16, 32));
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
res = SCSI_SCAN_TARGET_PRESENT;
|
||||
goto out_free_result;
|
||||
}
|
||||
@ -1489,7 +1495,6 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
|
||||
if (scsi_host_scan_allowed(shost))
|
||||
scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
|
||||
mutex_unlock(&shost->scan_mutex);
|
||||
transport_configure_device(&starget->dev);
|
||||
scsi_target_reap(starget);
|
||||
put_device(&starget->dev);
|
||||
|
||||
@ -1570,7 +1575,6 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel,
|
||||
out_reap:
|
||||
/* now determine if the target has any children at all
|
||||
* and if not, nuke it */
|
||||
transport_configure_device(&starget->dev);
|
||||
scsi_target_reap(starget);
|
||||
|
||||
put_device(&starget->dev);
|
||||
|
@ -21,6 +21,8 @@
|
||||
#include "scsi_priv.h"
|
||||
#include "scsi_logging.h"
|
||||
|
||||
static struct device_type scsi_dev_type;
|
||||
|
||||
static const struct {
|
||||
enum scsi_device_state value;
|
||||
char *name;
|
||||
@ -249,18 +251,27 @@ shost_rd_attr(sg_tablesize, "%hu\n");
|
||||
shost_rd_attr(unchecked_isa_dma, "%d\n");
|
||||
shost_rd_attr2(proc_name, hostt->proc_name, "%s\n");
|
||||
|
||||
static struct device_attribute *scsi_sysfs_shost_attrs[] = {
|
||||
&dev_attr_unique_id,
|
||||
&dev_attr_host_busy,
|
||||
&dev_attr_cmd_per_lun,
|
||||
&dev_attr_can_queue,
|
||||
&dev_attr_sg_tablesize,
|
||||
&dev_attr_unchecked_isa_dma,
|
||||
&dev_attr_proc_name,
|
||||
&dev_attr_scan,
|
||||
&dev_attr_hstate,
|
||||
&dev_attr_supported_mode,
|
||||
&dev_attr_active_mode,
|
||||
static struct attribute *scsi_sysfs_shost_attrs[] = {
|
||||
&dev_attr_unique_id.attr,
|
||||
&dev_attr_host_busy.attr,
|
||||
&dev_attr_cmd_per_lun.attr,
|
||||
&dev_attr_can_queue.attr,
|
||||
&dev_attr_sg_tablesize.attr,
|
||||
&dev_attr_unchecked_isa_dma.attr,
|
||||
&dev_attr_proc_name.attr,
|
||||
&dev_attr_scan.attr,
|
||||
&dev_attr_hstate.attr,
|
||||
&dev_attr_supported_mode.attr,
|
||||
&dev_attr_active_mode.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
struct attribute_group scsi_shost_attr_group = {
|
||||
.attrs = scsi_sysfs_shost_attrs,
|
||||
};
|
||||
|
||||
struct attribute_group *scsi_sysfs_shost_attr_groups[] = {
|
||||
&scsi_shost_attr_group,
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -335,7 +346,12 @@ static struct class sdev_class = {
|
||||
/* all probing is done in the individual ->probe routines */
|
||||
static int scsi_bus_match(struct device *dev, struct device_driver *gendrv)
|
||||
{
|
||||
struct scsi_device *sdp = to_scsi_device(dev);
|
||||
struct scsi_device *sdp;
|
||||
|
||||
if (dev->type != &scsi_dev_type)
|
||||
return 0;
|
||||
|
||||
sdp = to_scsi_device(dev);
|
||||
if (sdp->no_uld_attach)
|
||||
return 0;
|
||||
return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0;
|
||||
@ -351,10 +367,16 @@ static int scsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
|
||||
static int scsi_bus_suspend(struct device * dev, pm_message_t state)
|
||||
{
|
||||
struct device_driver *drv = dev->driver;
|
||||
struct scsi_device *sdev = to_scsi_device(dev);
|
||||
struct device_driver *drv;
|
||||
struct scsi_device *sdev;
|
||||
int err;
|
||||
|
||||
if (dev->type != &scsi_dev_type)
|
||||
return 0;
|
||||
|
||||
drv = dev->driver;
|
||||
sdev = to_scsi_device(dev);
|
||||
|
||||
err = scsi_device_quiesce(sdev);
|
||||
if (err)
|
||||
return err;
|
||||
@ -370,10 +392,16 @@ static int scsi_bus_suspend(struct device * dev, pm_message_t state)
|
||||
|
||||
static int scsi_bus_resume(struct device * dev)
|
||||
{
|
||||
struct device_driver *drv = dev->driver;
|
||||
struct scsi_device *sdev = to_scsi_device(dev);
|
||||
struct device_driver *drv;
|
||||
struct scsi_device *sdev;
|
||||
int err = 0;
|
||||
|
||||
if (dev->type != &scsi_dev_type)
|
||||
return 0;
|
||||
|
||||
drv = dev->driver;
|
||||
sdev = to_scsi_device(dev);
|
||||
|
||||
if (drv && drv->resume)
|
||||
err = drv->resume(dev);
|
||||
|
||||
@ -781,6 +809,27 @@ sdev_store_queue_type_rw(struct device *dev, struct device_attribute *attr,
|
||||
return count;
|
||||
}
|
||||
|
||||
static int scsi_target_add(struct scsi_target *starget)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (starget->state != STARGET_CREATED)
|
||||
return 0;
|
||||
|
||||
error = device_add(&starget->dev);
|
||||
if (error) {
|
||||
dev_err(&starget->dev, "target device_add failed, error %d\n", error);
|
||||
get_device(&starget->dev);
|
||||
scsi_target_reap(starget);
|
||||
put_device(&starget->dev);
|
||||
return error;
|
||||
}
|
||||
transport_add_device(&starget->dev);
|
||||
starget->state = STARGET_RUNNING;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct device_attribute sdev_attr_queue_type_rw =
|
||||
__ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field,
|
||||
sdev_store_queue_type_rw);
|
||||
@ -796,10 +845,16 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
|
||||
{
|
||||
int error, i;
|
||||
struct request_queue *rq = sdev->request_queue;
|
||||
struct scsi_target *starget = sdev->sdev_target;
|
||||
|
||||
if ((error = scsi_device_set_state(sdev, SDEV_RUNNING)) != 0)
|
||||
return error;
|
||||
|
||||
error = scsi_target_add(starget);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
transport_configure_device(&starget->dev);
|
||||
error = device_add(&sdev->sdev_gendev);
|
||||
if (error) {
|
||||
put_device(sdev->sdev_gendev.parent);
|
||||
@ -834,7 +889,7 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
|
||||
goto out;
|
||||
}
|
||||
|
||||
error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL);
|
||||
error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL, NULL);
|
||||
|
||||
if (error)
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
@ -971,44 +1026,6 @@ int scsi_register_interface(struct class_interface *intf)
|
||||
}
|
||||
EXPORT_SYMBOL(scsi_register_interface);
|
||||
|
||||
|
||||
static struct device_attribute *class_attr_overridden(
|
||||
struct device_attribute **attrs,
|
||||
struct device_attribute *attr)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!attrs)
|
||||
return NULL;
|
||||
for (i = 0; attrs[i]; i++)
|
||||
if (!strcmp(attrs[i]->attr.name, attr->attr.name))
|
||||
return attrs[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int class_attr_add(struct device *classdev,
|
||||
struct device_attribute *attr)
|
||||
{
|
||||
struct device_attribute *base_attr;
|
||||
|
||||
/*
|
||||
* Spare the caller from having to copy things it's not interested in.
|
||||
*/
|
||||
base_attr = class_attr_overridden(scsi_sysfs_shost_attrs, attr);
|
||||
if (base_attr) {
|
||||
/* extend permissions */
|
||||
attr->attr.mode |= base_attr->attr.mode;
|
||||
|
||||
/* override null show/store with default */
|
||||
if (!attr->show)
|
||||
attr->show = base_attr->show;
|
||||
if (!attr->store)
|
||||
attr->store = base_attr->store;
|
||||
}
|
||||
|
||||
return device_create_file(classdev, attr);
|
||||
}
|
||||
|
||||
/**
|
||||
* scsi_sysfs_add_host - add scsi host to subsystem
|
||||
* @shost: scsi host struct to add to subsystem
|
||||
@ -1018,20 +1035,11 @@ int scsi_sysfs_add_host(struct Scsi_Host *shost)
|
||||
{
|
||||
int error, i;
|
||||
|
||||
/* add host specific attributes */
|
||||
if (shost->hostt->shost_attrs) {
|
||||
for (i = 0; shost->hostt->shost_attrs[i]; i++) {
|
||||
error = class_attr_add(&shost->shost_dev,
|
||||
shost->hostt->shost_attrs[i]);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; scsi_sysfs_shost_attrs[i]; i++) {
|
||||
if (!class_attr_overridden(shost->hostt->shost_attrs,
|
||||
scsi_sysfs_shost_attrs[i])) {
|
||||
error = device_create_file(&shost->shost_dev,
|
||||
scsi_sysfs_shost_attrs[i]);
|
||||
shost->hostt->shost_attrs[i]);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
@ -1961,12 +1961,17 @@ fc_timed_out(struct scsi_cmnd *scmd)
|
||||
}
|
||||
|
||||
/*
|
||||
* Must be called with shost->host_lock held
|
||||
* Called by fc_user_scan to locate an rport on the shost that
|
||||
* matches the channel and target id, and invoke scsi_scan_target()
|
||||
* on the rport.
|
||||
*/
|
||||
static int fc_user_scan(struct Scsi_Host *shost, uint channel,
|
||||
uint id, uint lun)
|
||||
static void
|
||||
fc_user_scan_tgt(struct Scsi_Host *shost, uint channel, uint id, uint lun)
|
||||
{
|
||||
struct fc_rport *rport;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(shost->host_lock, flags);
|
||||
|
||||
list_for_each_entry(rport, &fc_host_rports(shost), peers) {
|
||||
if (rport->scsi_target_id == -1)
|
||||
@ -1975,13 +1980,54 @@ static int fc_user_scan(struct Scsi_Host *shost, uint channel,
|
||||
if (rport->port_state != FC_PORTSTATE_ONLINE)
|
||||
continue;
|
||||
|
||||
if ((channel == SCAN_WILD_CARD || channel == rport->channel) &&
|
||||
(id == SCAN_WILD_CARD || id == rport->scsi_target_id)) {
|
||||
scsi_scan_target(&rport->dev, rport->channel,
|
||||
rport->scsi_target_id, lun, 1);
|
||||
if ((channel == rport->channel) &&
|
||||
(id == rport->scsi_target_id)) {
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
scsi_scan_target(&rport->dev, channel, id, lun, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called via sysfs scan routines. Necessary, as the FC transport
|
||||
* wants to place all target objects below the rport object. So this
|
||||
* routine must invoke the scsi_scan_target() routine with the rport
|
||||
* object as the parent.
|
||||
*/
|
||||
static int
|
||||
fc_user_scan(struct Scsi_Host *shost, uint channel, uint id, uint lun)
|
||||
{
|
||||
uint chlo, chhi;
|
||||
uint tgtlo, tgthi;
|
||||
|
||||
if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) ||
|
||||
((id != SCAN_WILD_CARD) && (id >= shost->max_id)) ||
|
||||
((lun != SCAN_WILD_CARD) && (lun > shost->max_lun)))
|
||||
return -EINVAL;
|
||||
|
||||
if (channel == SCAN_WILD_CARD) {
|
||||
chlo = 0;
|
||||
chhi = shost->max_channel + 1;
|
||||
} else {
|
||||
chlo = channel;
|
||||
chhi = channel + 1;
|
||||
}
|
||||
|
||||
if (id == SCAN_WILD_CARD) {
|
||||
tgtlo = 0;
|
||||
tgthi = shost->max_id;
|
||||
} else {
|
||||
tgtlo = id;
|
||||
tgthi = id + 1;
|
||||
}
|
||||
|
||||
for ( ; chlo < chhi; chlo++)
|
||||
for ( ; tgtlo < tgthi; tgtlo++)
|
||||
fc_user_scan_tgt(shost, chlo, tgtlo, lun);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -192,6 +192,16 @@ static void sas_non_host_smp_request(struct request_queue *q)
|
||||
sas_smp_request(q, rphy_to_shost(rphy), rphy);
|
||||
}
|
||||
|
||||
static void sas_host_release(struct device *dev)
|
||||
{
|
||||
struct Scsi_Host *shost = dev_to_shost(dev);
|
||||
struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
|
||||
struct request_queue *q = sas_host->q;
|
||||
|
||||
if (q)
|
||||
blk_cleanup_queue(q);
|
||||
}
|
||||
|
||||
static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
|
||||
{
|
||||
struct request_queue *q;
|
||||
@ -199,6 +209,7 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
|
||||
struct device *dev;
|
||||
char namebuf[BUS_ID_SIZE];
|
||||
const char *name;
|
||||
void (*release)(struct device *);
|
||||
|
||||
if (!to_sas_internal(shost->transportt)->f->smp_handler) {
|
||||
printk("%s can't handle SMP requests\n", shost->hostt->name);
|
||||
@ -209,17 +220,19 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
|
||||
q = blk_init_queue(sas_non_host_smp_request, NULL);
|
||||
dev = &rphy->dev;
|
||||
name = dev->bus_id;
|
||||
release = NULL;
|
||||
} else {
|
||||
q = blk_init_queue(sas_host_smp_request, NULL);
|
||||
dev = &shost->shost_gendev;
|
||||
snprintf(namebuf, sizeof(namebuf),
|
||||
"sas_host%d", shost->host_no);
|
||||
name = namebuf;
|
||||
release = sas_host_release;
|
||||
}
|
||||
if (!q)
|
||||
return -ENOMEM;
|
||||
|
||||
error = bsg_register_queue(q, dev, name);
|
||||
error = bsg_register_queue(q, dev, name, release);
|
||||
if (error) {
|
||||
blk_cleanup_queue(q);
|
||||
return -ENOMEM;
|
||||
@ -253,7 +266,6 @@ static void sas_bsg_remove(struct Scsi_Host *shost, struct sas_rphy *rphy)
|
||||
return;
|
||||
|
||||
bsg_unregister_queue(q);
|
||||
blk_cleanup_queue(q);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1301,6 +1313,9 @@ static void sas_expander_release(struct device *dev)
|
||||
struct sas_rphy *rphy = dev_to_rphy(dev);
|
||||
struct sas_expander_device *edev = rphy_to_expander_device(rphy);
|
||||
|
||||
if (rphy->q)
|
||||
blk_cleanup_queue(rphy->q);
|
||||
|
||||
put_device(dev->parent);
|
||||
kfree(edev);
|
||||
}
|
||||
@ -1310,6 +1325,9 @@ static void sas_end_device_release(struct device *dev)
|
||||
struct sas_rphy *rphy = dev_to_rphy(dev);
|
||||
struct sas_end_device *edev = rphy_to_end_device(rphy);
|
||||
|
||||
if (rphy->q)
|
||||
blk_cleanup_queue(rphy->q);
|
||||
|
||||
put_device(dev->parent);
|
||||
kfree(edev);
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <scsi/scsi.h>
|
||||
#include "scsi_priv.h"
|
||||
#include <scsi/scsi_device.h>
|
||||
@ -1374,11 +1375,11 @@ static int spi_host_configure(struct transport_container *tc,
|
||||
* overloads the return by setting 1<<1 if the attribute should
|
||||
* be writeable */
|
||||
#define TARGET_ATTRIBUTE_HELPER(name) \
|
||||
(si->f->show_##name ? 1 : 0) + \
|
||||
(si->f->set_##name ? 2 : 0)
|
||||
(si->f->show_##name ? S_IRUGO : 0) | \
|
||||
(si->f->set_##name ? S_IWUSR : 0)
|
||||
|
||||
static int target_attribute_is_visible(struct kobject *kobj,
|
||||
struct attribute *attr, int i)
|
||||
static mode_t target_attribute_is_visible(struct kobject *kobj,
|
||||
struct attribute *attr, int i)
|
||||
{
|
||||
struct device *cdev = container_of(kobj, struct device, kobj);
|
||||
struct scsi_target *starget = transport_class_to_starget(cdev);
|
||||
@ -1428,7 +1429,7 @@ static int target_attribute_is_visible(struct kobject *kobj,
|
||||
spi_support_ius(starget))
|
||||
return TARGET_ATTRIBUTE_HELPER(hold_mcs);
|
||||
else if (attr == &dev_attr_revalidate.attr)
|
||||
return 1;
|
||||
return S_IWUSR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1462,25 +1463,9 @@ static int spi_target_configure(struct transport_container *tc,
|
||||
struct device *cdev)
|
||||
{
|
||||
struct kobject *kobj = &cdev->kobj;
|
||||
int i;
|
||||
struct attribute *attr;
|
||||
int rc;
|
||||
|
||||
for (i = 0; (attr = target_attributes[i]) != NULL; i++) {
|
||||
int j = target_attribute_group.is_visible(kobj, attr, i);
|
||||
|
||||
/* FIXME: as well as returning -EEXIST, which we'd like
|
||||
* to ignore, sysfs also does a WARN_ON and dumps a trace,
|
||||
* which is bad, so temporarily, skip attributes that are
|
||||
* already visible (the revalidate one) */
|
||||
if (j && attr != &dev_attr_revalidate.attr)
|
||||
rc = sysfs_add_file_to_group(kobj, attr,
|
||||
target_attribute_group.name);
|
||||
/* and make the attribute writeable if we have a set
|
||||
* function */
|
||||
if ((j & 1))
|
||||
rc = sysfs_chmod_file(kobj, attr, attr->mode | S_IWUSR);
|
||||
}
|
||||
/* force an update based on parameters read from the device */
|
||||
sysfs_update_group(kobj, &target_attribute_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -313,7 +313,8 @@ static struct platform_driver sgiwd93_driver = {
|
||||
.probe = sgiwd93_probe,
|
||||
.remove = __devexit_p(sgiwd93_remove),
|
||||
.driver = {
|
||||
.name = "sgiwd93"
|
||||
.name = "sgiwd93",
|
||||
.owner = THIS_MODULE,
|
||||
}
|
||||
};
|
||||
|
||||
@ -333,3 +334,4 @@ module_exit(sgiwd93_module_exit);
|
||||
MODULE_DESCRIPTION("SGI WD33C93 driver");
|
||||
MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:sgiwd93");
|
||||
|
@ -53,6 +53,7 @@
|
||||
MODULE_AUTHOR("Thomas Bogendörfer");
|
||||
MODULE_DESCRIPTION("SNI RM 53c710 SCSI Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:snirm_53c710");
|
||||
|
||||
#define SNIRM710_CLOCK 32
|
||||
|
||||
@ -136,6 +137,7 @@ static struct platform_driver snirm710_driver = {
|
||||
.remove = __devexit_p(snirm710_driver_remove),
|
||||
.driver = {
|
||||
.name = "snirm_53c710",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -4322,7 +4322,7 @@ static void do_remove_sysfs_files(void)
|
||||
static ssize_t
|
||||
st_defined_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct st_modedef *STm = (struct st_modedef *)dev_get_drvdata(dev);
|
||||
struct st_modedef *STm = dev_get_drvdata(dev);
|
||||
ssize_t l = 0;
|
||||
|
||||
l = snprintf(buf, PAGE_SIZE, "%d\n", STm->defined);
|
||||
@ -4334,7 +4334,7 @@ DEVICE_ATTR(defined, S_IRUGO, st_defined_show, NULL);
|
||||
static ssize_t
|
||||
st_defblk_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct st_modedef *STm = (struct st_modedef *)dev_get_drvdata(dev);
|
||||
struct st_modedef *STm = dev_get_drvdata(dev);
|
||||
ssize_t l = 0;
|
||||
|
||||
l = snprintf(buf, PAGE_SIZE, "%d\n", STm->default_blksize);
|
||||
@ -4346,7 +4346,7 @@ DEVICE_ATTR(default_blksize, S_IRUGO, st_defblk_show, NULL);
|
||||
static ssize_t
|
||||
st_defdensity_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct st_modedef *STm = (struct st_modedef *)dev_get_drvdata(dev);
|
||||
struct st_modedef *STm = dev_get_drvdata(dev);
|
||||
ssize_t l = 0;
|
||||
char *fmt;
|
||||
|
||||
@ -4361,7 +4361,7 @@ static ssize_t
|
||||
st_defcompression_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct st_modedef *STm = (struct st_modedef *)dev_get_drvdata(dev);
|
||||
struct st_modedef *STm = dev_get_drvdata(dev);
|
||||
ssize_t l = 0;
|
||||
|
||||
l = snprintf(buf, PAGE_SIZE, "%d\n", STm->default_compression - 1);
|
||||
@ -4373,7 +4373,7 @@ DEVICE_ATTR(default_compression, S_IRUGO, st_defcompression_show, NULL);
|
||||
static ssize_t
|
||||
st_options_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct st_modedef *STm = (struct st_modedef *)dev_get_drvdata(dev);
|
||||
struct st_modedef *STm = dev_get_drvdata(dev);
|
||||
struct scsi_tape *STp;
|
||||
int i, j, options;
|
||||
ssize_t l = 0;
|
||||
|
@ -294,6 +294,7 @@ static struct platform_driver esp_sun3x_driver = {
|
||||
.remove = __devexit_p(esp_sun3x_remove),
|
||||
.driver = {
|
||||
.name = "sun3x_esp",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
@ -314,3 +315,4 @@ MODULE_VERSION(DRV_VERSION);
|
||||
|
||||
module_init(sun3x_esp_init);
|
||||
module_exit(sun3x_esp_exit);
|
||||
MODULE_ALIAS("platform:sun3x_esp");
|
||||
|
@ -1715,13 +1715,12 @@ static void flush_dev(struct scsi_device *dev, unsigned long cursec, unsigned in
|
||||
|
||||
}
|
||||
|
||||
static irqreturn_t ihdlr(int irq, unsigned int j) {
|
||||
static irqreturn_t ihdlr(unsigned int j)
|
||||
{
|
||||
struct scsi_cmnd *SCpnt;
|
||||
unsigned int i, k, c, status, tstatus, reg, ret;
|
||||
struct mscp *spp, *cpp;
|
||||
|
||||
if (sh[j]->irq != irq)
|
||||
panic("%s: ihdlr, irq %d, sh[j]->irq %d.\n", BN(j), irq, sh[j]->irq);
|
||||
int irq = sh[j]->irq;
|
||||
|
||||
/* Check if this board need to be serviced */
|
||||
if (!((reg = inb(sh[j]->io_port + REG_SYS_INTR)) & IRQ_ASSERTED)) goto none;
|
||||
@ -1935,7 +1934,7 @@ static irqreturn_t do_interrupt_handler(int irq, void *shap) {
|
||||
if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return IRQ_NONE;
|
||||
|
||||
spin_lock_irqsave(sh[j]->host_lock, spin_flags);
|
||||
ret = ihdlr(irq, j);
|
||||
ret = ihdlr(j);
|
||||
spin_unlock_irqrestore(sh[j]->host_lock, spin_flags);
|
||||
return ret;
|
||||
}
|
||||
|
@ -477,11 +477,10 @@ const struct file_operations sysfs_file_operations = {
|
||||
.poll = sysfs_poll,
|
||||
};
|
||||
|
||||
|
||||
int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
|
||||
int type)
|
||||
int sysfs_add_file_mode(struct sysfs_dirent *dir_sd,
|
||||
const struct attribute *attr, int type, mode_t amode)
|
||||
{
|
||||
umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG;
|
||||
umode_t mode = (amode & S_IALLUGO) | S_IFREG;
|
||||
struct sysfs_addrm_cxt acxt;
|
||||
struct sysfs_dirent *sd;
|
||||
int rc;
|
||||
@ -502,6 +501,13 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
|
||||
}
|
||||
|
||||
|
||||
int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
|
||||
int type)
|
||||
{
|
||||
return sysfs_add_file_mode(dir_sd, attr, type, attr->mode);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* sysfs_create_file - create an attribute file for an object.
|
||||
* @kobj: object we're creating for.
|
||||
|
@ -23,35 +23,50 @@ static void remove_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
|
||||
int i;
|
||||
|
||||
for (i = 0, attr = grp->attrs; *attr; i++, attr++)
|
||||
if (!grp->is_visible ||
|
||||
grp->is_visible(kobj, *attr, i))
|
||||
sysfs_hash_and_remove(dir_sd, (*attr)->name);
|
||||
sysfs_hash_and_remove(dir_sd, (*attr)->name);
|
||||
}
|
||||
|
||||
static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
|
||||
const struct attribute_group *grp)
|
||||
const struct attribute_group *grp, int update)
|
||||
{
|
||||
struct attribute *const* attr;
|
||||
int error = 0, i;
|
||||
|
||||
for (i = 0, attr = grp->attrs; *attr && !error; i++, attr++)
|
||||
if (!grp->is_visible ||
|
||||
grp->is_visible(kobj, *attr, i))
|
||||
error |=
|
||||
sysfs_add_file(dir_sd, *attr, SYSFS_KOBJ_ATTR);
|
||||
for (i = 0, attr = grp->attrs; *attr && !error; i++, attr++) {
|
||||
mode_t mode = 0;
|
||||
|
||||
/* in update mode, we're changing the permissions or
|
||||
* visibility. Do this by first removing then
|
||||
* re-adding (if required) the file */
|
||||
if (update)
|
||||
sysfs_hash_and_remove(dir_sd, (*attr)->name);
|
||||
if (grp->is_visible) {
|
||||
mode = grp->is_visible(kobj, *attr, i);
|
||||
if (!mode)
|
||||
continue;
|
||||
}
|
||||
error = sysfs_add_file_mode(dir_sd, *attr, SYSFS_KOBJ_ATTR,
|
||||
(*attr)->mode | mode);
|
||||
if (unlikely(error))
|
||||
break;
|
||||
}
|
||||
if (error)
|
||||
remove_files(dir_sd, kobj, grp);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int sysfs_create_group(struct kobject * kobj,
|
||||
const struct attribute_group * grp)
|
||||
static int internal_create_group(struct kobject *kobj, int update,
|
||||
const struct attribute_group *grp)
|
||||
{
|
||||
struct sysfs_dirent *sd;
|
||||
int error;
|
||||
|
||||
BUG_ON(!kobj || !kobj->sd);
|
||||
BUG_ON(!kobj || (!update && !kobj->sd));
|
||||
|
||||
/* Updates may happen before the object has been instantiated */
|
||||
if (unlikely(update && !kobj->sd))
|
||||
return -EINVAL;
|
||||
|
||||
if (grp->name) {
|
||||
error = sysfs_create_subdir(kobj, grp->name, &sd);
|
||||
@ -60,7 +75,7 @@ int sysfs_create_group(struct kobject * kobj,
|
||||
} else
|
||||
sd = kobj->sd;
|
||||
sysfs_get(sd);
|
||||
error = create_files(sd, kobj, grp);
|
||||
error = create_files(sd, kobj, grp, update);
|
||||
if (error) {
|
||||
if (grp->name)
|
||||
sysfs_remove_subdir(sd);
|
||||
@ -69,6 +84,47 @@ int sysfs_create_group(struct kobject * kobj,
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_create_group - given a directory kobject, create an attribute group
|
||||
* @kobj: The kobject to create the group on
|
||||
* @grp: The attribute group to create
|
||||
*
|
||||
* This function creates a group for the first time. It will explicitly
|
||||
* warn and error if any of the attribute files being created already exist.
|
||||
*
|
||||
* Returns 0 on success or error.
|
||||
*/
|
||||
int sysfs_create_group(struct kobject *kobj,
|
||||
const struct attribute_group *grp)
|
||||
{
|
||||
return internal_create_group(kobj, 0, grp);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysfs_update_group - given a directory kobject, create an attribute group
|
||||
* @kobj: The kobject to create the group on
|
||||
* @grp: The attribute group to create
|
||||
*
|
||||
* This function updates an attribute group. Unlike
|
||||
* sysfs_create_group(), it will explicitly not warn or error if any
|
||||
* of the attribute files being created already exist. Furthermore,
|
||||
* if the visibility of the files has changed through the is_visible()
|
||||
* callback, it will update the permissions and add or remove the
|
||||
* relevant files.
|
||||
*
|
||||
* The primary use for this function is to call it after making a change
|
||||
* that affects group visibility.
|
||||
*
|
||||
* Returns 0 on success or error.
|
||||
*/
|
||||
int sysfs_update_group(struct kobject *kobj,
|
||||
const struct attribute_group *grp)
|
||||
{
|
||||
return internal_create_group(kobj, 1, grp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void sysfs_remove_group(struct kobject * kobj,
|
||||
const struct attribute_group * grp)
|
||||
{
|
||||
@ -95,4 +151,5 @@ void sysfs_remove_group(struct kobject * kobj,
|
||||
|
||||
|
||||
EXPORT_SYMBOL_GPL(sysfs_create_group);
|
||||
EXPORT_SYMBOL_GPL(sysfs_update_group);
|
||||
EXPORT_SYMBOL_GPL(sysfs_remove_group);
|
||||
|
@ -154,6 +154,8 @@ extern const struct file_operations sysfs_file_operations;
|
||||
int sysfs_add_file(struct sysfs_dirent *dir_sd,
|
||||
const struct attribute *attr, int type);
|
||||
|
||||
int sysfs_add_file_mode(struct sysfs_dirent *dir_sd,
|
||||
const struct attribute *attr, int type, mode_t amode);
|
||||
/*
|
||||
* bin.c
|
||||
*/
|
||||
|
@ -56,19 +56,25 @@ struct sg_io_v4 {
|
||||
#if defined(CONFIG_BLK_DEV_BSG)
|
||||
struct bsg_class_device {
|
||||
struct device *class_dev;
|
||||
struct device *dev;
|
||||
struct device *parent;
|
||||
int minor;
|
||||
struct request_queue *queue;
|
||||
struct kref ref;
|
||||
void (*release)(struct device *);
|
||||
};
|
||||
|
||||
extern int bsg_register_queue(struct request_queue *, struct device *, const char *);
|
||||
extern int bsg_register_queue(struct request_queue *q,
|
||||
struct device *parent, const char *name,
|
||||
void (*release)(struct device *));
|
||||
extern void bsg_unregister_queue(struct request_queue *);
|
||||
#else
|
||||
static inline int bsg_register_queue(struct request_queue * rq, struct device *dev, const char *name)
|
||||
static inline int bsg_register_queue(struct request_queue *q,
|
||||
struct device *parent, const char *name,
|
||||
void (*release)(struct device *))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void bsg_unregister_queue(struct request_queue *rq)
|
||||
static inline void bsg_unregister_queue(struct request_queue *q)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
@ -32,7 +32,7 @@ struct attribute {
|
||||
|
||||
struct attribute_group {
|
||||
const char *name;
|
||||
int (*is_visible)(struct kobject *,
|
||||
mode_t (*is_visible)(struct kobject *,
|
||||
struct attribute *, int);
|
||||
struct attribute **attrs;
|
||||
};
|
||||
@ -105,6 +105,8 @@ void sysfs_remove_link(struct kobject *kobj, const char *name);
|
||||
|
||||
int __must_check sysfs_create_group(struct kobject *kobj,
|
||||
const struct attribute_group *grp);
|
||||
int sysfs_update_group(struct kobject *kobj,
|
||||
const struct attribute_group *grp);
|
||||
void sysfs_remove_group(struct kobject *kobj,
|
||||
const struct attribute_group *grp);
|
||||
int sysfs_add_file_to_group(struct kobject *kobj,
|
||||
|
@ -181,7 +181,8 @@ struct scsi_device {
|
||||
sdev_printk(prefix, (scmd)->device, fmt, ##a)
|
||||
|
||||
enum scsi_target_state {
|
||||
STARGET_RUNNING = 1,
|
||||
STARGET_CREATED = 1,
|
||||
STARGET_RUNNING,
|
||||
STARGET_DEL,
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user