forked from mirrors/linux
		
	[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 changed files with 186 additions and 175 deletions
				
			
		|  | @ -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. | ||||
|  | @ -46,8 +46,6 @@ | |||
| #include <scsi/scsi_tcq.h> | ||||
| #include <scsi/scsi_host.h> | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| #define MAX_TARGETS	16 | ||||
| #define MAX_LUNS	8	/* 32 for 1.31 F/W */ | ||||
| 
 | ||||
|  | @ -57,7 +55,6 @@ | |||
| 
 | ||||
| static struct qlogicpti *qptichain = NULL; | ||||
| static DEFINE_SPINLOCK(qptichain_lock); | ||||
| static int qptis_running = 0; | ||||
| 
 | ||||
| #define PACKB(a, b)			(((a)<<4)|(b)) | ||||
| 
 | ||||
|  | @ -815,173 +812,6 @@ 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(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) | ||||
| { | ||||
| 	static char buf[80]; | ||||
|  | @ -1551,9 +1381,9 @@ static int qlogicpti_reset(struct scsi_cmnd *Cmnd) | |||
| 	return return_status; | ||||
| } | ||||
| 
 | ||||
| static struct 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, | ||||
|  | @ -1565,8 +1395,189 @@ static struct 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; | ||||
| 
 | ||||
| #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_VERSION("2.0"); | ||||
| 
 | ||||
| module_init(qpti_init); | ||||
| module_exit(qpti_exit); | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 David S. Miller
						David S. Miller