⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mesh.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
			}			ms->msgphase = msg_out;			/*			 * We need to wait for REQ before dropping ATN.			 * We wait for at most 30us, then fall back to			 * a scheme where we issue a SEQ_COMMAND with ATN,			 * which will give us a phase mismatch interrupt			 * when REQ does come, and then we send the message.			 */			t = 230;		/* wait up to 230us */			while ((in_8(&mr->bus_status0) & BS0_REQ) == 0) {				if (--t < 0) {					dlog(ms, "impatient for req", ms->n_msgout);					ms->msgphase = msg_none;					break;				}				udelay(1);			}			break;		case dataing:			if (ms->dma_count != 0) {				start_phase(ms);				return;			}			/*			 * We can get a phase mismatch here if the target			 * changes to the status phase, even though we have			 * had a command complete interrupt.  Then, if we			 * issue the SEQ_STATUS command, we'll get a sequence			 * error interrupt.  Which isn't so bad except that			 * occasionally the mesh actually executes the			 * SEQ_STATUS *as well as* giving us the sequence			 * error and phase mismatch exception.			 */			out_8(&mr->sequence, 0);			out_8(&mr->interrupt,			      INT_ERROR | INT_EXCEPTION | INT_CMDDONE);			halt_dma(ms);			break;		case statusing:			if (cmd) {				cmd->SCp.Status = mr->fifo;				if (DEBUG_TARGET(cmd))					printk(KERN_DEBUG "mesh: status is %x\n",					       cmd->SCp.Status);			}			ms->msgphase = msg_in;			break;		case busfreeing:			mesh_done(ms, 1);			return;		case disconnecting:			ms->current_req = NULL;			ms->phase = idle;			mesh_start(ms);			return;		default:			break;		}		++ms->phase;		start_phase(ms);		break;	}}/* * Called by midlayer with host locked to queue a new * request */static int mesh_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)){	struct mesh_state *ms;	cmd->scsi_done = done;	cmd->host_scribble = NULL;	ms = (struct mesh_state *) cmd->device->host->hostdata;	if (ms->request_q == NULL)		ms->request_q = cmd;	else		ms->request_qtail->host_scribble = (void *) cmd;	ms->request_qtail = cmd;	if (ms->phase == idle)		mesh_start(ms);	return 0;}/* * Called to handle interrupts, either call by the interrupt * handler (do_mesh_interrupt) or by other functions in * exceptional circumstances */static void mesh_interrupt(struct mesh_state *ms){	volatile struct mesh_regs __iomem *mr = ms->mesh;	int intr;#if 0	if (ALLOW_DEBUG(ms->conn_tgt))		printk(KERN_DEBUG "mesh_intr, bs0=%x int=%x exc=%x err=%x "		       "phase=%d msgphase=%d\n", mr->bus_status0,		       mr->interrupt, mr->exception, mr->error,		       ms->phase, ms->msgphase);#endif	while ((intr = in_8(&mr->interrupt)) != 0) {		dlog(ms, "interrupt intr/err/exc/seq=%.8x", 		     MKWORD(intr, mr->error, mr->exception, mr->sequence));		if (intr & INT_ERROR) {			handle_error(ms);		} else if (intr & INT_EXCEPTION) {			handle_exception(ms);		} else if (intr & INT_CMDDONE) {			out_8(&mr->interrupt, INT_CMDDONE);			cmd_complete(ms);		}	}}/* Todo: here we can at least try to remove the command from the * queue if it isn't connected yet, and for pending command, assert * ATN until the bus gets freed. */static int mesh_abort(struct scsi_cmnd *cmd){	struct mesh_state *ms = (struct mesh_state *) cmd->device->host->hostdata;	printk(KERN_DEBUG "mesh_abort(%p)\n", cmd);	mesh_dump_regs(ms);	dumplog(ms, cmd->device->id);	dumpslog(ms);	return FAILED;}/* * Called by the midlayer with the lock held to reset the * SCSI host and bus. * The midlayer will wait for devices to come back, we don't need * to do that ourselves */static int mesh_host_reset(struct scsi_cmnd *cmd){	struct mesh_state *ms = (struct mesh_state *) cmd->device->host->hostdata;	volatile struct mesh_regs __iomem *mr = ms->mesh;	volatile struct dbdma_regs __iomem *md = ms->dma;	unsigned long flags;	printk(KERN_DEBUG "mesh_host_reset\n");	spin_lock_irqsave(ms->host->host_lock, flags);	/* Reset the controller & dbdma channel */	out_le32(&md->control, (RUN|PAUSE|FLUSH|WAKE) << 16);	/* stop dma */	out_8(&mr->exception, 0xff);	/* clear all exception bits */	out_8(&mr->error, 0xff);	/* clear all error bits */	out_8(&mr->sequence, SEQ_RESETMESH);       	mesh_flush_io(mr);	udelay(1);	out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);	out_8(&mr->source_id, ms->host->this_id);	out_8(&mr->sel_timeout, 25);	/* 250ms */	out_8(&mr->sync_params, ASYNC_PARAMS);	/* Reset the bus */	out_8(&mr->bus_status1, BS1_RST);	/* assert RST */       	mesh_flush_io(mr);	udelay(30);			/* leave it on for >= 25us */	out_8(&mr->bus_status1, 0);	/* negate RST */	/* Complete pending commands */	handle_reset(ms);		spin_unlock_irqrestore(ms->host->host_lock, flags);	return SUCCESS;}static void set_mesh_power(struct mesh_state *ms, int state){	if (!machine_is(powermac))		return;	if (state) {		pmac_call_feature(PMAC_FTR_MESH_ENABLE, macio_get_of_node(ms->mdev), 0, 1);		msleep(200);	} else {		pmac_call_feature(PMAC_FTR_MESH_ENABLE, macio_get_of_node(ms->mdev), 0, 0);		msleep(10);	}}#ifdef CONFIG_PMstatic int mesh_suspend(struct macio_dev *mdev, pm_message_t mesg){	struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);	unsigned long flags;	switch (mesg.event) {	case PM_EVENT_SUSPEND:	case PM_EVENT_FREEZE:		break;	default:		return 0;	}	if (mesg.event == mdev->ofdev.dev.power.power_state.event)		return 0;	scsi_block_requests(ms->host);	spin_lock_irqsave(ms->host->host_lock, flags);	while(ms->phase != idle) {		spin_unlock_irqrestore(ms->host->host_lock, flags);		msleep(10);		spin_lock_irqsave(ms->host->host_lock, flags);	}	ms->phase = sleeping;	spin_unlock_irqrestore(ms->host->host_lock, flags);	disable_irq(ms->meshintr);	set_mesh_power(ms, 0);	mdev->ofdev.dev.power.power_state = mesg;	return 0;}static int mesh_resume(struct macio_dev *mdev){	struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);	unsigned long flags;	if (mdev->ofdev.dev.power.power_state.event == PM_EVENT_ON)		return 0;	set_mesh_power(ms, 1);	mesh_init(ms);	spin_lock_irqsave(ms->host->host_lock, flags);	mesh_start(ms);	spin_unlock_irqrestore(ms->host->host_lock, flags);	enable_irq(ms->meshintr);	scsi_unblock_requests(ms->host);	mdev->ofdev.dev.power.power_state.event = PM_EVENT_ON;	return 0;}#endif /* CONFIG_PM *//* * If we leave drives set for synchronous transfers (especially * CDROMs), and reboot to MacOS, it gets confused, poor thing. * So, on reboot we reset the SCSI bus. */static int mesh_shutdown(struct macio_dev *mdev){	struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);	volatile struct mesh_regs __iomem *mr;	unsigned long flags;       	printk(KERN_INFO "resetting MESH scsi bus(es)\n");	spin_lock_irqsave(ms->host->host_lock, flags);       	mr = ms->mesh;	out_8(&mr->intr_mask, 0);	out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);	out_8(&mr->bus_status1, BS1_RST);	mesh_flush_io(mr);	udelay(30);	out_8(&mr->bus_status1, 0);	spin_unlock_irqrestore(ms->host->host_lock, flags);	return 0;}static struct scsi_host_template mesh_template = {	.proc_name			= "mesh",	.name				= "MESH",	.queuecommand			= mesh_queue,	.eh_abort_handler		= mesh_abort,	.eh_host_reset_handler		= mesh_host_reset,	.can_queue			= 20,	.this_id			= 7,	.sg_tablesize			= SG_ALL,	.cmd_per_lun			= 2,	.use_clustering			= DISABLE_CLUSTERING,	.use_sg_chaining		= ENABLE_SG_CHAINING,};static int mesh_probe(struct macio_dev *mdev, const struct of_device_id *match){	struct device_node *mesh = macio_get_of_node(mdev);	struct pci_dev* pdev = macio_get_pci_dev(mdev);	int tgt, minper;	const int *cfp;	struct mesh_state *ms;	struct Scsi_Host *mesh_host;	void *dma_cmd_space;	dma_addr_t dma_cmd_bus;	switch (mdev->bus->chip->type) {	case macio_heathrow:	case macio_gatwick:	case macio_paddington:		use_active_neg = 0;		break;	default:		use_active_neg = SEQ_ACTIVE_NEG;	}	if (macio_resource_count(mdev) != 2 || macio_irq_count(mdev) != 2) {       		printk(KERN_ERR "mesh: expected 2 addrs and 2 intrs"	       	       " (got %d,%d)\n", macio_resource_count(mdev),		       macio_irq_count(mdev));		return -ENODEV;	}	if (macio_request_resources(mdev, "mesh") != 0) {       		printk(KERN_ERR "mesh: unable to request memory resources");		return -EBUSY;	}       	mesh_host = scsi_host_alloc(&mesh_template, sizeof(struct mesh_state));	if (mesh_host == NULL) {		printk(KERN_ERR "mesh: couldn't register host");		goto out_release;	}		/* Old junk for root discovery, that will die ultimately */#if !defined(MODULE)       	note_scsi_host(mesh, mesh_host);#endif	mesh_host->base = macio_resource_start(mdev, 0);	mesh_host->irq = macio_irq(mdev, 0);       	ms = (struct mesh_state *) mesh_host->hostdata;	macio_set_drvdata(mdev, ms);	ms->host = mesh_host;	ms->mdev = mdev;	ms->pdev = pdev;		ms->mesh = ioremap(macio_resource_start(mdev, 0), 0x1000);	if (ms->mesh == NULL) {		printk(KERN_ERR "mesh: can't map registers\n");		goto out_free;	}			ms->dma = ioremap(macio_resource_start(mdev, 1), 0x1000);	if (ms->dma == NULL) {		printk(KERN_ERR "mesh: can't map registers\n");		iounmap(ms->mesh);		goto out_free;	}       	ms->meshintr = macio_irq(mdev, 0);       	ms->dmaintr = macio_irq(mdev, 1);       	/* Space for dma command list: +1 for stop command,       	 * +1 to allow for aligning.	 */	ms->dma_cmd_size = (mesh_host->sg_tablesize + 2) * sizeof(struct dbdma_cmd);	/* We use the PCI APIs for now until the generic one gets fixed	 * enough or until we get some macio-specific versions	 */	dma_cmd_space = pci_alloc_consistent(macio_get_pci_dev(mdev),					     ms->dma_cmd_size,					     &dma_cmd_bus);	if (dma_cmd_space == NULL) {		printk(KERN_ERR "mesh: can't allocate DMA table\n");		goto out_unmap;	}	memset(dma_cmd_space, 0, ms->dma_cmd_size);	ms->dma_cmds = (struct dbdma_cmd *) DBDMA_ALIGN(dma_cmd_space);       	ms->dma_cmd_space = dma_cmd_space;	ms->dma_cmd_bus = dma_cmd_bus + ((unsigned long)ms->dma_cmds)		- (unsigned long)dma_cmd_space;	ms->current_req = NULL;       	for (tgt = 0; tgt < 8; ++tgt) {	       	ms->tgts[tgt].sdtr_state = do_sdtr;	       	ms->tgts[tgt].sync_params = ASYNC_PARAMS;	       	ms->tgts[tgt].current_req = NULL;       	}	if ((cfp = of_get_property(mesh, "clock-frequency", NULL)))       		ms->clk_freq = *cfp;	else {       		printk(KERN_INFO "mesh: assuming 50MHz clock frequency\n");	       	ms->clk_freq = 50000000;       	}       	/* The maximum sync rate is clock / 5; increase       	 * mesh_sync_period if necessary.	 */	minper = 1000000000 / (ms->clk_freq / 5); /* ns */	if (mesh_sync_period < minper)		mesh_sync_period = minper;	/* Power up the chip */	set_mesh_power(ms, 1);	/* Set it up */       	mesh_init(ms);	/* Request interrupt */       	if (request_irq(ms->meshintr, do_mesh_interrupt, 0, "MESH", ms)) {	       	printk(KERN_ERR "MESH: can't get irq %d\n", ms->meshintr);		goto out_shutdown;	}	/* Add scsi host & scan */	if (scsi_add_host(mesh_host, &mdev->ofdev.dev))		goto out_release_irq;	scsi_scan_host(mesh_host);	return 0; out_release_irq:	free_irq(ms->meshintr, ms); out_shutdown:	/* shutdown & reset bus in case of error or macos can be confused	 * at reboot if the bus was set to synchronous mode already	 */	mesh_shutdown(mdev);	set_mesh_power(ms, 0);	pci_free_consistent(macio_get_pci_dev(mdev), ms->dma_cmd_size,			    ms->dma_cmd_space, ms->dma_cmd_bus); out_unmap:	iounmap(ms->dma);	iounmap(ms->mesh); out_free:	scsi_host_put(mesh_host); out_release:	macio_release_resources(mdev);	return -ENODEV;}static int mesh_remove(struct macio_dev *mdev){	struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);	struct Scsi_Host *mesh_host = ms->host;	scsi_remove_host(mesh_host);	free_irq(ms->meshintr, ms);	/* Reset scsi bus */	mesh_shutdown(mdev);	/* Shut down chip & termination */	set_mesh_power(ms, 0);	/* Unmap registers & dma controller */	iounmap(ms->mesh);       	iounmap(ms->dma);	/* Free DMA commands memory */	pci_free_consistent(macio_get_pci_dev(mdev), ms->dma_cmd_size,			    ms->dma_cmd_space, ms->dma_cmd_bus);	/* Release memory resources */	macio_release_resources(mdev);	scsi_host_put(mesh_host);	return 0;}static struct of_device_id mesh_match[] = {	{	.name 		= "mesh",	},	{	.type		= "scsi",	.compatible	= "chrp,mesh0"	},	{},};MODULE_DEVICE_TABLE (of, mesh_match);static struct macio_driver mesh_driver = {	.name 		= "mesh",	.match_table	= mesh_match,	.probe		= mesh_probe,	.remove		= mesh_remove,	.shutdown	= mesh_shutdown,#ifdef CONFIG_PM	.suspend	= mesh_suspend,	.resume		= mesh_resume,#endif};static int __init init_mesh(void){	/* Calculate sync rate from module parameters */	if (sync_rate > 10)		sync_rate = 10;	if (sync_rate > 0) {		printk(KERN_INFO "mesh: configured for synchronous %d MB/s\n", sync_rate);		mesh_sync_period = 1000 / sync_rate;	/* ns */		mesh_sync_offset = 15;	} else		printk(KERN_INFO "mesh: configured for asynchronous\n");	return macio_register_driver(&mesh_driver);}static void __exit exit_mesh(void){	return macio_unregister_driver(&mesh_driver);}module_init(init_mesh);module_exit(exit_mesh);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -