mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-15 05:11:32 +00:00
[SCSI] qlogicpti: Convert to new SBUS device framework.
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
7bd5ed5dd4
commit
3d4253d9af
@ -1,6 +1,6 @@
|
|||||||
/* qlogicpti.c: Performance Technologies QlogicISP sbus card driver.
|
/* qlogicpti.c: Performance Technologies QlogicISP sbus card driver.
|
||||||
*
|
*
|
||||||
* Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu)
|
* Copyright (C) 1996, 2006 David S. Miller (davem@davemloft.net)
|
||||||
*
|
*
|
||||||
* A lot of this driver was directly stolen from Erik H. Moe's PCI
|
* A lot of this driver was directly stolen from Erik H. Moe's PCI
|
||||||
* Qlogic ISP driver. Mucho kudos to him for this code.
|
* Qlogic ISP driver. Mucho kudos to him for this code.
|
||||||
@ -46,8 +46,6 @@
|
|||||||
#include <scsi/scsi_tcq.h>
|
#include <scsi/scsi_tcq.h>
|
||||||
#include <scsi/scsi_host.h>
|
#include <scsi/scsi_host.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define MAX_TARGETS 16
|
#define MAX_TARGETS 16
|
||||||
#define MAX_LUNS 8 /* 32 for 1.31 F/W */
|
#define MAX_LUNS 8 /* 32 for 1.31 F/W */
|
||||||
|
|
||||||
@ -57,7 +55,6 @@
|
|||||||
|
|
||||||
static struct qlogicpti *qptichain = NULL;
|
static struct qlogicpti *qptichain = NULL;
|
||||||
static DEFINE_SPINLOCK(qptichain_lock);
|
static DEFINE_SPINLOCK(qptichain_lock);
|
||||||
static int qptis_running = 0;
|
|
||||||
|
|
||||||
#define PACKB(a, b) (((a)<<4)|(b))
|
#define PACKB(a, b) (((a)<<4)|(b))
|
||||||
|
|
||||||
@ -815,173 +812,6 @@ static int __init qpti_map_queues(struct qlogicpti *qpti)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Detect all PTI Qlogic ISP's in the machine. */
|
|
||||||
static int __init qlogicpti_detect(struct scsi_host_template *tpnt)
|
|
||||||
{
|
|
||||||
struct qlogicpti *qpti;
|
|
||||||
struct Scsi_Host *qpti_host;
|
|
||||||
struct sbus_bus *sbus;
|
|
||||||
struct sbus_dev *sdev;
|
|
||||||
int nqptis = 0, nqptis_in_use = 0;
|
|
||||||
|
|
||||||
tpnt->proc_name = "qlogicpti";
|
|
||||||
for_each_sbus(sbus) {
|
|
||||||
for_each_sbusdev(sdev, sbus) {
|
|
||||||
/* Is this a red snapper? */
|
|
||||||
if (strcmp(sdev->prom_name, "ptisp") &&
|
|
||||||
strcmp(sdev->prom_name, "PTI,ptisp") &&
|
|
||||||
strcmp(sdev->prom_name, "QLGC,isp") &&
|
|
||||||
strcmp(sdev->prom_name, "SUNW,isp"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Sometimes Antares cards come up not completely
|
|
||||||
* setup, and we get a report of a zero IRQ.
|
|
||||||
* Skip over them in such cases so we survive.
|
|
||||||
*/
|
|
||||||
if (sdev->irqs[0] == 0) {
|
|
||||||
printk("qpti%d: Adapter reports no interrupt, "
|
|
||||||
"skipping over this card.", nqptis);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Yep, register and allocate software state. */
|
|
||||||
qpti_host = scsi_register(tpnt, sizeof(struct qlogicpti));
|
|
||||||
if (!qpti_host) {
|
|
||||||
printk("QPTI: Cannot register PTI Qlogic ISP SCSI host");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
qpti = (struct qlogicpti *) qpti_host->hostdata;
|
|
||||||
|
|
||||||
/* We are wide capable, 16 targets. */
|
|
||||||
qpti_host->max_id = MAX_TARGETS;
|
|
||||||
|
|
||||||
/* Setup back pointers and misc. state. */
|
|
||||||
qpti->qhost = qpti_host;
|
|
||||||
qpti->sdev = sdev;
|
|
||||||
qpti->qpti_id = nqptis++;
|
|
||||||
qpti->prom_node = sdev->prom_node;
|
|
||||||
prom_getstring(qpti->prom_node, "name",
|
|
||||||
qpti->prom_name,
|
|
||||||
sizeof(qpti->prom_name));
|
|
||||||
|
|
||||||
/* This is not correct, actually. There's a switch
|
|
||||||
* on the PTI cards that put them into "emulation"
|
|
||||||
* mode- i.e., report themselves as QLGC,isp
|
|
||||||
* instead of PTI,ptisp. The only real substantive
|
|
||||||
* difference between non-pti and pti cards is
|
|
||||||
* the tmon register. Which is possibly even
|
|
||||||
* there for Qlogic cards, but non-functional.
|
|
||||||
*/
|
|
||||||
qpti->is_pti = (strcmp (qpti->prom_name, "QLGC,isp") != 0);
|
|
||||||
|
|
||||||
qpti_chain_add(qpti);
|
|
||||||
if (qpti_map_regs(qpti) < 0)
|
|
||||||
goto fail_unlink;
|
|
||||||
|
|
||||||
if (qpti_register_irq(qpti) < 0)
|
|
||||||
goto fail_unmap_regs;
|
|
||||||
|
|
||||||
qpti_get_scsi_id(qpti);
|
|
||||||
qpti_get_bursts(qpti);
|
|
||||||
qpti_get_clock(qpti);
|
|
||||||
|
|
||||||
/* Clear out scsi_cmnd array. */
|
|
||||||
memset(qpti->cmd_slots, 0, sizeof(qpti->cmd_slots));
|
|
||||||
|
|
||||||
if (qpti_map_queues(qpti) < 0)
|
|
||||||
goto fail_free_irq;
|
|
||||||
|
|
||||||
/* Load the firmware. */
|
|
||||||
if (qlogicpti_load_firmware(qpti))
|
|
||||||
goto fail_unmap_queues;
|
|
||||||
if (qpti->is_pti) {
|
|
||||||
/* Check the PTI status reg. */
|
|
||||||
if (qlogicpti_verify_tmon(qpti))
|
|
||||||
goto fail_unmap_queues;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reset the ISP and init res/req queues. */
|
|
||||||
if (qlogicpti_reset_hardware(qpti_host))
|
|
||||||
goto fail_unmap_queues;
|
|
||||||
|
|
||||||
printk("(Firmware v%d.%d.%d)", qpti->fware_majrev,
|
|
||||||
qpti->fware_minrev, qpti->fware_micrev);
|
|
||||||
{
|
|
||||||
char buffer[60];
|
|
||||||
|
|
||||||
prom_getstring (qpti->prom_node,
|
|
||||||
"isp-fcode", buffer, 60);
|
|
||||||
if (buffer[0])
|
|
||||||
printk("(Firmware %s)", buffer);
|
|
||||||
if (prom_getbool(qpti->prom_node, "differential"))
|
|
||||||
qpti->differential = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
printk (" [%s Wide, using %s interface]\n",
|
|
||||||
(qpti->ultra ? "Ultra" : "Fast"),
|
|
||||||
(qpti->differential ? "differential" : "single ended"));
|
|
||||||
|
|
||||||
nqptis_in_use++;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
fail_unmap_queues:
|
|
||||||
#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
|
|
||||||
sbus_free_consistent(qpti->sdev,
|
|
||||||
QSIZE(RES_QUEUE_LEN),
|
|
||||||
qpti->res_cpu, qpti->res_dvma);
|
|
||||||
sbus_free_consistent(qpti->sdev,
|
|
||||||
QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
|
|
||||||
qpti->req_cpu, qpti->req_dvma);
|
|
||||||
#undef QSIZE
|
|
||||||
fail_free_irq:
|
|
||||||
free_irq(qpti->irq, qpti);
|
|
||||||
|
|
||||||
fail_unmap_regs:
|
|
||||||
sbus_iounmap(qpti->qregs,
|
|
||||||
qpti->sdev->reg_addrs[0].reg_size);
|
|
||||||
if (qpti->is_pti)
|
|
||||||
sbus_iounmap(qpti->sreg, sizeof(unsigned char));
|
|
||||||
fail_unlink:
|
|
||||||
qpti_chain_del(qpti);
|
|
||||||
scsi_unregister(qpti->qhost);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (nqptis)
|
|
||||||
printk("QPTI: Total of %d PTI Qlogic/ISP hosts found, %d actually in use.\n",
|
|
||||||
nqptis, nqptis_in_use);
|
|
||||||
qptis_running = nqptis_in_use;
|
|
||||||
return nqptis;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int qlogicpti_release(struct Scsi_Host *host)
|
|
||||||
{
|
|
||||||
struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
|
|
||||||
|
|
||||||
/* Remove visibility from IRQ handlers. */
|
|
||||||
qpti_chain_del(qpti);
|
|
||||||
|
|
||||||
/* Shut up the card. */
|
|
||||||
sbus_writew(0, qpti->qregs + SBUS_CTRL);
|
|
||||||
|
|
||||||
/* Free IRQ handler and unmap Qlogic,ISP and PTI status regs. */
|
|
||||||
free_irq(qpti->irq, qpti);
|
|
||||||
|
|
||||||
#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
|
|
||||||
sbus_free_consistent(qpti->sdev,
|
|
||||||
QSIZE(RES_QUEUE_LEN),
|
|
||||||
qpti->res_cpu, qpti->res_dvma);
|
|
||||||
sbus_free_consistent(qpti->sdev,
|
|
||||||
QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
|
|
||||||
qpti->req_cpu, qpti->req_dvma);
|
|
||||||
#undef QSIZE
|
|
||||||
|
|
||||||
sbus_iounmap(qpti->qregs, qpti->sdev->reg_addrs[0].reg_size);
|
|
||||||
if (qpti->is_pti)
|
|
||||||
sbus_iounmap(qpti->sreg, sizeof(unsigned char));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *qlogicpti_info(struct Scsi_Host *host)
|
const char *qlogicpti_info(struct Scsi_Host *host)
|
||||||
{
|
{
|
||||||
static char buf[80];
|
static char buf[80];
|
||||||
@ -1551,9 +1381,9 @@ static int qlogicpti_reset(struct scsi_cmnd *Cmnd)
|
|||||||
return return_status;
|
return return_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct scsi_host_template driver_template = {
|
static struct scsi_host_template qpti_template = {
|
||||||
.detect = qlogicpti_detect,
|
.module = THIS_MODULE,
|
||||||
.release = qlogicpti_release,
|
.name = "qlogicpti",
|
||||||
.info = qlogicpti_info,
|
.info = qlogicpti_info,
|
||||||
.queuecommand = qlogicpti_queuecommand_slow,
|
.queuecommand = qlogicpti_queuecommand_slow,
|
||||||
.eh_abort_handler = qlogicpti_abort,
|
.eh_abort_handler = qlogicpti_abort,
|
||||||
@ -1565,8 +1395,189 @@ static struct scsi_host_template driver_template = {
|
|||||||
.use_clustering = ENABLE_CLUSTERING,
|
.use_clustering = ENABLE_CLUSTERING,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int __devinit qpti_sbus_probe(struct of_device *dev, const struct of_device_id *match)
|
||||||
|
{
|
||||||
|
static int nqptis;
|
||||||
|
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
|
||||||
|
struct device_node *dp = dev->node;
|
||||||
|
struct scsi_host_template *tpnt = match->data;
|
||||||
|
struct Scsi_Host *host;
|
||||||
|
struct qlogicpti *qpti;
|
||||||
|
char *fcode;
|
||||||
|
|
||||||
#include "scsi_module.c"
|
/* Sometimes Antares cards come up not completely
|
||||||
|
* setup, and we get a report of a zero IRQ.
|
||||||
|
*/
|
||||||
|
if (sdev->irqs[0] == 0)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
host = scsi_host_alloc(tpnt, sizeof(struct qlogicpti));
|
||||||
|
if (!host)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
qpti = (struct qlogicpti *) host->hostdata;
|
||||||
|
|
||||||
|
host->max_id = MAX_TARGETS;
|
||||||
|
qpti->qhost = host;
|
||||||
|
qpti->sdev = sdev;
|
||||||
|
qpti->qpti_id = nqptis;
|
||||||
|
qpti->prom_node = sdev->prom_node;
|
||||||
|
strcpy(qpti->prom_name, sdev->ofdev.node->name);
|
||||||
|
qpti->is_pti = strcmp(qpti->prom_name, "QLGC,isp");
|
||||||
|
|
||||||
|
if (qpti_map_regs(qpti) < 0)
|
||||||
|
goto fail_unlink;
|
||||||
|
|
||||||
|
if (qpti_register_irq(qpti) < 0)
|
||||||
|
goto fail_unmap_regs;
|
||||||
|
|
||||||
|
qpti_get_scsi_id(qpti);
|
||||||
|
qpti_get_bursts(qpti);
|
||||||
|
qpti_get_clock(qpti);
|
||||||
|
|
||||||
|
/* Clear out scsi_cmnd array. */
|
||||||
|
memset(qpti->cmd_slots, 0, sizeof(qpti->cmd_slots));
|
||||||
|
|
||||||
|
if (qpti_map_queues(qpti) < 0)
|
||||||
|
goto fail_free_irq;
|
||||||
|
|
||||||
|
/* Load the firmware. */
|
||||||
|
if (qlogicpti_load_firmware(qpti))
|
||||||
|
goto fail_unmap_queues;
|
||||||
|
if (qpti->is_pti) {
|
||||||
|
/* Check the PTI status reg. */
|
||||||
|
if (qlogicpti_verify_tmon(qpti))
|
||||||
|
goto fail_unmap_queues;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset the ISP and init res/req queues. */
|
||||||
|
if (qlogicpti_reset_hardware(host))
|
||||||
|
goto fail_unmap_queues;
|
||||||
|
|
||||||
|
if (scsi_add_host(host, &dev->dev))
|
||||||
|
goto fail_unmap_queues;
|
||||||
|
|
||||||
|
printk("(Firmware v%d.%d.%d)", qpti->fware_majrev,
|
||||||
|
qpti->fware_minrev, qpti->fware_micrev);
|
||||||
|
|
||||||
|
fcode = of_get_property(dp, "isp-fcode", NULL);
|
||||||
|
if (fcode && fcode[0])
|
||||||
|
printk("(Firmware %s)", fcode);
|
||||||
|
if (of_find_property(dp, "differential", NULL) != NULL)
|
||||||
|
qpti->differential = 1;
|
||||||
|
|
||||||
|
printk (" [%s Wide, using %s interface]\n",
|
||||||
|
(qpti->ultra ? "Ultra" : "Fast"),
|
||||||
|
(qpti->differential ? "differential" : "single ended"));
|
||||||
|
|
||||||
|
dev_set_drvdata(&sdev->ofdev.dev, qpti);
|
||||||
|
|
||||||
|
qpti_chain_add(qpti);
|
||||||
|
|
||||||
|
scsi_scan_host(host);
|
||||||
|
nqptis++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail_unmap_queues:
|
||||||
|
#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
|
||||||
|
sbus_free_consistent(qpti->sdev,
|
||||||
|
QSIZE(RES_QUEUE_LEN),
|
||||||
|
qpti->res_cpu, qpti->res_dvma);
|
||||||
|
sbus_free_consistent(qpti->sdev,
|
||||||
|
QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
|
||||||
|
qpti->req_cpu, qpti->req_dvma);
|
||||||
|
#undef QSIZE
|
||||||
|
|
||||||
|
fail_unmap_regs:
|
||||||
|
sbus_iounmap(qpti->qregs,
|
||||||
|
qpti->sdev->reg_addrs[0].reg_size);
|
||||||
|
if (qpti->is_pti)
|
||||||
|
sbus_iounmap(qpti->sreg, sizeof(unsigned char));
|
||||||
|
|
||||||
|
fail_free_irq:
|
||||||
|
free_irq(qpti->irq, qpti);
|
||||||
|
|
||||||
|
fail_unlink:
|
||||||
|
scsi_host_put(host);
|
||||||
|
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __devexit qpti_sbus_remove(struct of_device *dev)
|
||||||
|
{
|
||||||
|
struct qlogicpti *qpti = dev_get_drvdata(&dev->dev);
|
||||||
|
|
||||||
|
qpti_chain_del(qpti);
|
||||||
|
|
||||||
|
scsi_remove_host(qpti->qhost);
|
||||||
|
|
||||||
|
/* Shut up the card. */
|
||||||
|
sbus_writew(0, qpti->qregs + SBUS_CTRL);
|
||||||
|
|
||||||
|
/* Free IRQ handler and unmap Qlogic,ISP and PTI status regs. */
|
||||||
|
free_irq(qpti->irq, qpti);
|
||||||
|
|
||||||
|
#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
|
||||||
|
sbus_free_consistent(qpti->sdev,
|
||||||
|
QSIZE(RES_QUEUE_LEN),
|
||||||
|
qpti->res_cpu, qpti->res_dvma);
|
||||||
|
sbus_free_consistent(qpti->sdev,
|
||||||
|
QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
|
||||||
|
qpti->req_cpu, qpti->req_dvma);
|
||||||
|
#undef QSIZE
|
||||||
|
|
||||||
|
sbus_iounmap(qpti->qregs, qpti->sdev->reg_addrs[0].reg_size);
|
||||||
|
if (qpti->is_pti)
|
||||||
|
sbus_iounmap(qpti->sreg, sizeof(unsigned char));
|
||||||
|
|
||||||
|
scsi_host_put(qpti->qhost);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct of_device_id qpti_match[] = {
|
||||||
|
{
|
||||||
|
.name = "ptisp",
|
||||||
|
.data = &qpti_template,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "PTI,ptisp",
|
||||||
|
.data = &qpti_template,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "QLGC,isp",
|
||||||
|
.data = &qpti_template,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "SUNW,isp",
|
||||||
|
.data = &qpti_template,
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, qpti_match);
|
||||||
|
|
||||||
|
static struct of_platform_driver qpti_sbus_driver = {
|
||||||
|
.name = "qpti",
|
||||||
|
.match_table = qpti_match,
|
||||||
|
.probe = qpti_sbus_probe,
|
||||||
|
.remove = __devexit_p(qpti_sbus_remove),
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init qpti_init(void)
|
||||||
|
{
|
||||||
|
return of_register_driver(&qpti_sbus_driver, &sbus_bus_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit qpti_exit(void)
|
||||||
|
{
|
||||||
|
of_unregister_driver(&qpti_sbus_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("QlogicISP SBUS driver");
|
||||||
|
MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_VERSION("2.0");
|
||||||
|
|
||||||
|
module_init(qpti_init);
|
||||||
|
module_exit(qpti_exit);
|
||||||
|
Loading…
Reference in New Issue
Block a user