X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fscsi%2Fqlogicpti.c;h=9f10689905a8d68c3eb7be4b00561c52f7f6ac23;hb=refs%2Fheads%2Fvserver;hp=c3ba6c22623a6b45141230f24e2328aa73d05429;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index c3ba6c226..9f1068990 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -1,6 +1,6 @@ /* 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 * Qlogic ISP driver. Mucho kudos to him for this code. @@ -23,11 +23,11 @@ #include #include #include +#include +#include #include -#include "scsi.h" -#include "hosts.h" #include "qlogicpti.h" #include @@ -39,7 +39,12 @@ #include #include -#include +#include +#include +#include +#include +#include +#include #define MAX_TARGETS 16 #define MAX_LUNS 8 /* 32 for 1.31 F/W */ @@ -49,8 +54,7 @@ #include "qlogicpti_asm.c" static struct qlogicpti *qptichain = NULL; -static spinlock_t qptichain_lock = SPIN_LOCK_UNLOCKED; -static int qptis_running = 0; +static DEFINE_SPINLOCK(qptichain_lock); #define PACKB(a, b) (((a)<<4)|(b)) @@ -124,7 +128,7 @@ static const u_char mbox_param[] = { PACKB(0, 0) /* 0x0042 */ }; -#define MAX_MBOX_COMMAND (sizeof(mbox_param)/sizeof(u_short)) +#define MAX_MBOX_COMMAND ARRAY_SIZE(mbox_param) /* queue length's _must_ be power of two: */ #define QUEUE_DEPTH(in, out, ql) ((in - out) & (ql)) @@ -457,7 +461,7 @@ static int qlogicpti_reset_hardware(struct Scsi_Host *host) #define PTI_RESET_LIMIT 400 -static int __init qlogicpti_load_firmware(struct qlogicpti *qpti) +static int __devinit qlogicpti_load_firmware(struct qlogicpti *qpti) { struct Scsi_Host *host = qpti->qhost; unsigned short csum = 0; @@ -645,7 +649,7 @@ static int qlogicpti_verify_tmon(struct qlogicpti *qpti) return 0; } -static irqreturn_t qpti_intr(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t qpti_intr(int irq, void *dev_id); static void __init qpti_chain_add(struct qlogicpti *qpti) { @@ -714,10 +718,10 @@ static int __init qpti_register_irq(struct qlogicpti *qpti) * sanely maintain. */ if (request_irq(qpti->irq, qpti_intr, - SA_SHIRQ, "Qlogic/PTI", qpti)) + IRQF_SHARED, "Qlogic/PTI", qpti)) goto fail; - printk("qpti%d: IRQ %s ", qpti->qpti_id, __irq_itoa(qpti->irq)); + printk("qpti%d: IRQ %d ", qpti->qpti_id, qpti->irq); return 0; @@ -808,180 +812,13 @@ static int __init qpti_map_queues(struct qlogicpti *qpti) return 0; } -/* Detect all PTI Qlogic ISP's in the machine. */ -static int __init qlogicpti_detect(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) { static char buf[80]; struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata; - sprintf(buf, "PTI Qlogic,ISP SBUS SCSI irq %s regs at %lx", - __irq_itoa(qpti->qhost->irq), qpti->qregs); + sprintf(buf, "PTI Qlogic,ISP SBUS SCSI irq %d regs at %p", + qpti->qhost->irq, qpti->qregs); return buf; } @@ -997,7 +834,7 @@ static inline void marker_frob(struct Command_Entry *cmd) marker->rsvd = 0; } -static inline void cmd_frob(struct Command_Entry *cmd, Scsi_Cmnd *Cmnd, +static inline void cmd_frob(struct Command_Entry *cmd, struct scsi_cmnd *Cmnd, struct qlogicpti *qpti) { memset(cmd, 0, sizeof(struct Command_Entry)); @@ -1010,7 +847,7 @@ static inline void cmd_frob(struct Command_Entry *cmd, Scsi_Cmnd *Cmnd, if (Cmnd->device->tagged_supported) { if (qpti->cmd_count[Cmnd->device->id] == 0) qpti->tag_ages[Cmnd->device->id] = jiffies; - if ((jiffies - qpti->tag_ages[Cmnd->device->id]) > (5*HZ)) { + if (time_after(jiffies, qpti->tag_ages[Cmnd->device->id] + (5*HZ))) { cmd->control_flags = CFLAG_ORDERED_TAG; qpti->tag_ages[Cmnd->device->id] = jiffies; } else @@ -1027,7 +864,7 @@ static inline void cmd_frob(struct Command_Entry *cmd, Scsi_Cmnd *Cmnd, } /* Do it to it baby. */ -static inline int load_cmd(Scsi_Cmnd *Cmnd, struct Command_Entry *cmd, +static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd, struct qlogicpti *qpti, u_int in_ptr, u_int out_ptr) { struct dataseg *ds; @@ -1037,8 +874,8 @@ static inline int load_cmd(Scsi_Cmnd *Cmnd, struct Command_Entry *cmd, if (Cmnd->use_sg) { int sg_count; - sg = (struct scatterlist *) Cmnd->buffer; - sg_count = sbus_map_sg(qpti->sdev, sg, Cmnd->use_sg, scsi_to_sbus_dma_dir(Cmnd->sc_data_direction)); + sg = (struct scatterlist *) Cmnd->request_buffer; + sg_count = sbus_map_sg(qpti->sdev, sg, Cmnd->use_sg, Cmnd->sc_data_direction); ds = cmd->dataseg; cmd->segment_cnt = sg_count; @@ -1081,7 +918,7 @@ static inline int load_cmd(Scsi_Cmnd *Cmnd, struct Command_Entry *cmd, sbus_map_single(qpti->sdev, Cmnd->request_buffer, Cmnd->request_bufflen, - scsi_to_sbus_dma_dir(Cmnd->sc_data_direction)); + Cmnd->sc_data_direction); cmd->dataseg[0].d_base = (u32) ((unsigned long)Cmnd->SCp.ptr); cmd->dataseg[0].d_count = Cmnd->request_bufflen; @@ -1112,14 +949,44 @@ static inline void update_can_queue(struct Scsi_Host *host, u_int in_ptr, u_int host->sg_tablesize = QLOGICPTI_MAX_SG(num_free); } +static unsigned int scsi_rbuf_get(struct scsi_cmnd *cmd, unsigned char **buf_out) +{ + unsigned char *buf; + unsigned int buflen; + + if (cmd->use_sg) { + struct scatterlist *sg; + + sg = (struct scatterlist *) cmd->request_buffer; + buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; + buflen = sg->length; + } else { + buf = cmd->request_buffer; + buflen = cmd->request_bufflen; + } + + *buf_out = buf; + return buflen; +} + +static void scsi_rbuf_put(struct scsi_cmnd *cmd, unsigned char *buf) +{ + if (cmd->use_sg) { + struct scatterlist *sg; + + sg = (struct scatterlist *) cmd->request_buffer; + kunmap_atomic(buf - sg->offset, KM_IRQ0); + } +} + /* * Until we scan the entire bus with inquiries, go throught this fella... */ -static void ourdone(Scsi_Cmnd *Cmnd) +static void ourdone(struct scsi_cmnd *Cmnd) { struct qlogicpti *qpti = (struct qlogicpti *) Cmnd->device->host->hostdata; int tgt = Cmnd->device->id; - void (*done) (Scsi_Cmnd *); + void (*done) (struct scsi_cmnd *); /* This grot added by DaveM, blame him for ugliness. * The issue is that in the 2.3.x driver we use the @@ -1127,7 +994,7 @@ static void ourdone(Scsi_Cmnd *Cmnd) * completion linked list at interrupt service time, * so we have to store the done function pointer elsewhere. */ - done = (void (*)(Scsi_Cmnd *)) + done = (void (*)(struct scsi_cmnd *)) (((unsigned long) Cmnd->SCp.Message) #ifdef __sparc_v9__ | ((unsigned long) Cmnd->SCp.Status << 32UL) @@ -1138,11 +1005,9 @@ static void ourdone(Scsi_Cmnd *Cmnd) int ok = host_byte(Cmnd->result) == DID_OK; if (Cmnd->cmnd[0] == 0x12 && ok) { unsigned char *iqd; + unsigned int iqd_len; - if (Cmnd->use_sg != 0) - BUG(); - - iqd = ((unsigned char *)Cmnd->buffer); + iqd_len = scsi_rbuf_get(Cmnd, &iqd); /* tags handled in midlayer */ /* enable sync mode? */ @@ -1156,6 +1021,9 @@ static void ourdone(Scsi_Cmnd *Cmnd) if (iqd[7] & 0x20) { qpti->dev_param[tgt].device_flags |= 0x20; } + + scsi_rbuf_put(Cmnd, iqd); + qpti->sbits |= (1 << tgt); } else if (!ok) { qpti->sbits |= (1 << tgt); @@ -1164,10 +1032,10 @@ static void ourdone(Scsi_Cmnd *Cmnd) done(Cmnd); } -static int qlogicpti_queuecommand(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *)); +static int qlogicpti_queuecommand(struct scsi_cmnd *Cmnd, void (*done)(struct scsi_cmnd *)); -static int qlogicpti_queuecommand_slow(Scsi_Cmnd *Cmnd, - void (*done)(Scsi_Cmnd *)) +static int qlogicpti_queuecommand_slow(struct scsi_cmnd *Cmnd, + void (*done)(struct scsi_cmnd *)) { struct qlogicpti *qpti = (struct qlogicpti *) Cmnd->device->host->hostdata; @@ -1238,7 +1106,7 @@ static int qlogicpti_queuecommand_slow(Scsi_Cmnd *Cmnd, * * "This code must fly." -davem */ -static int qlogicpti_queuecommand(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *)) +static int qlogicpti_queuecommand(struct scsi_cmnd *Cmnd, void (*done)(struct scsi_cmnd *)) { struct Scsi_Host *host = Cmnd->device->host; struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata; @@ -1351,9 +1219,9 @@ static int qlogicpti_return_status(struct Status_Entry *sts, int id) return (sts->scsi_status & STATUS_MASK) | (host_status << 16); } -static Scsi_Cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti) +static struct scsi_cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti) { - Scsi_Cmnd *Cmnd, *done_queue = NULL; + struct scsi_cmnd *Cmnd, *done_queue = NULL; struct Status_Entry *sts; u_int in_ptr, out_ptr; @@ -1410,14 +1278,14 @@ static Scsi_Cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti) if (Cmnd->use_sg) { sbus_unmap_sg(qpti->sdev, - (struct scatterlist *)Cmnd->buffer, + (struct scatterlist *)Cmnd->request_buffer, Cmnd->use_sg, - scsi_to_sbus_dma_dir(Cmnd->sc_data_direction)); - } else { + Cmnd->sc_data_direction); + } else if (Cmnd->request_bufflen) { sbus_unmap_single(qpti->sdev, (__u32)((unsigned long)Cmnd->SCp.ptr), Cmnd->request_bufflen, - scsi_to_sbus_dma_dir(Cmnd->sc_data_direction)); + Cmnd->sc_data_direction); } qpti->cmd_count[Cmnd->device->id]--; sbus_writew(out_ptr, qpti->qregs + MBOX5); @@ -1429,20 +1297,20 @@ static Scsi_Cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti) return done_queue; } -static irqreturn_t qpti_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t qpti_intr(int irq, void *dev_id) { struct qlogicpti *qpti = dev_id; unsigned long flags; - Scsi_Cmnd *dq; + struct scsi_cmnd *dq; spin_lock_irqsave(qpti->qhost->host_lock, flags); dq = qlogicpti_intr_handler(qpti); if (dq != NULL) { do { - Scsi_Cmnd *next; + struct scsi_cmnd *next; - next = (Scsi_Cmnd *) dq->host_scribble; + next = (struct scsi_cmnd *) dq->host_scribble; dq->scsi_done(dq); dq = next; } while (dq != NULL); @@ -1452,7 +1320,7 @@ static irqreturn_t qpti_intr(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -static int qlogicpti_abort(Scsi_Cmnd *Cmnd) +static int qlogicpti_abort(struct scsi_cmnd *Cmnd) { u_short param[6]; struct Scsi_Host *host = Cmnd->device->host; @@ -1489,7 +1357,7 @@ static int qlogicpti_abort(Scsi_Cmnd *Cmnd) return return_status; } -static int qlogicpti_reset(Scsi_Cmnd *Cmnd) +static int qlogicpti_reset(struct scsi_cmnd *Cmnd) { u_short param[6]; struct Scsi_Host *host = Cmnd->device->host; @@ -1513,9 +1381,9 @@ static int qlogicpti_reset(Scsi_Cmnd *Cmnd) return return_status; } -static Scsi_Host_Template driver_template = { - .detect = qlogicpti_detect, - .release = qlogicpti_release, +static struct scsi_host_template qpti_template = { + .module = THIS_MODULE, + .name = "qlogicpti", .info = qlogicpti_info, .queuecommand = qlogicpti_queuecommand_slow, .eh_abort_handler = qlogicpti_abort, @@ -1527,8 +1395,189 @@ static Scsi_Host_Template driver_template = { .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; + + /* 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; -#include "scsi_module.c" + 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_VERSION("2.0"); +module_init(qpti_init); +module_exit(qpti_exit);