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

📄 cpqarray.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 4 页
字号:
	c->hdr.size = sizeof(rblk_t) >> 2;	c->size += sizeof(rblk_t);	c->req.hdr.blk = ida[(ctlr<<CTLR_SHIFT) + MINOR(creq->rq_dev)].start_sect + creq->sector;	c->bh = bh;DBGPX(	if (bh == NULL)		panic("bh == NULL?");		printk("sector=%d, nr_sectors=%d\n", creq->sector, creq->nr_sectors););	seg = 0; lastdataend = NULL;	sect = 0;	while(bh) {		sect += bh->b_size/512;DBGPX(		if (bh->b_size % 512) {			printk("Oh damn.  %d+%d, size = %d\n", creq->sector, sect, bh->b_size);			panic("b_size %% 512 != 0");		});		if (bh->b_data == lastdataend) {			c->req.sg[seg-1].size += bh->b_size;			lastdataend += bh->b_size;		} else {			c->req.sg[seg].size = bh->b_size;			c->req.sg[seg].addr = (__u32)virt_to_bus(bh->b_data);			lastdataend = bh->b_data + bh->b_size;			if (++seg == SG_MAX)				break;		}		bh = bh->b_reqnext;	}DBGPX(	printk("Submitting %d sectors in %d segments\n", sect, seg); );	c->req.hdr.sg_cnt = seg;	c->req.hdr.blk_cnt = sect;	creq->sector += sect;	creq->nr_sectors -= sect;	/* Ready the next request:	 * Fix up creq if we still have more buffers in the buffer chain, or	 * mark this request as done and ready the next one.         */	if (creq->nr_sectors) {DBGPX(		if (bh==NULL) {			printk("sector=%d, nr_sectors=%d, sect=%d, seg=%d\n",				creq->sector, creq->nr_sectors, sect, seg);			panic("mother...");		});		creq->bh = bh->b_reqnext;		bh->b_reqnext = NULL;DBGPX(		printk("More to do on same request %p\n", creq); );	} else {DBGPX(		printk("Done with %p\n", creq); );		blkdev_dequeue_request(creq);		end_that_request_last(creq);	}	c->req.hdr.cmd = (creq->cmd == READ) ? IDA_READ : IDA_WRITE;	c->type = CMD_RWREQ;	/* Put the request on the tail of the request queue */	addQ(&h->reqQ, c);	h->Qdepth++;	if (h->Qdepth > h->maxQsinceinit) 		h->maxQsinceinit = h->Qdepth;	start_io(h);}/*  * start_io submits everything on a controller's request queue * and moves it to the completion queue. * * Interrupts had better be off if you're in here */static void start_io(ctlr_info_t *h){	cmdlist_t *c;	while((c = h->reqQ) != NULL) {		/* Can't do anything if we're busy */		if (h->access.fifo_full(h) == 0)			return;		/* Get the first entry from the request Q */		removeQ(&h->reqQ, c);		h->Qdepth--;			/* Tell the controller to do our bidding */		h->access.submit_command(h, c);		/* Get onto the completion Q */		addQ(&h->cmpQ, c);	}}static inline void complete_buffers(struct buffer_head *bh, int ok){	struct buffer_head *xbh;	while(bh) {		xbh = bh->b_reqnext;		bh->b_reqnext = NULL;				bh->b_end_io(bh, ok);		bh = xbh;	}}/* * Mark all buffers that cmd was responsible for */static inline void complete_command(cmdlist_t *cmd, int timeout){	int ok=1;	if (cmd->req.hdr.rcode & RCODE_NONFATAL &&	   (hba[cmd->ctlr]->misc_tflags & MISC_NONFATAL_WARN) == 0) {		printk(KERN_WARNING "Non Fatal error on ida/c%dd%d\n",				cmd->ctlr, cmd->hdr.unit);		hba[cmd->ctlr]->misc_tflags |= MISC_NONFATAL_WARN;	}	if (cmd->req.hdr.rcode & RCODE_FATAL) {		printk(KERN_WARNING "Fatal error on ida/c%dd%d\n",				cmd->ctlr, cmd->hdr.unit);		ok = 0;	}	if (cmd->req.hdr.rcode & RCODE_INVREQ) {				printk(KERN_WARNING "Invalid request on ida/c%dd%d = (cmd=%x sect=%d cnt=%d sg=%d ret=%x)\n",				cmd->ctlr, cmd->hdr.unit, cmd->req.hdr.cmd,				cmd->req.hdr.blk, cmd->req.hdr.blk_cnt,				cmd->req.hdr.sg_cnt, cmd->req.hdr.rcode);		ok = 0;		}	if (timeout) ok = 0;	complete_buffers(cmd->bh, ok);}/* *  The controller will interrupt us upon completion of commands. *  Find the command on the completion queue, remove it, tell the OS and *  try to queue up more IO */static void do_ida_intr(int irq, void *dev_id, struct pt_regs *regs){	ctlr_info_t *h = dev_id;	cmdlist_t *c;	unsigned long istat;	unsigned long flags;	__u32 a,a1;	istat = h->access.intr_pending(h);	/* Is this interrupt for us? */	if (istat == 0)		return;	/*	 * If there are completed commands in the completion queue,	 * we had better do something about it.	 */	spin_lock_irqsave(&io_request_lock, flags);	if (istat & FIFO_NOT_EMPTY) {		while((a = h->access.command_completed(h))) {			a1 = a; a &= ~3;			if ((c = h->cmpQ) == NULL)			{  				printk(KERN_WARNING "cpqarray: Completion of %08lx ignored\n", (unsigned long)a1);				continue;				} 			while(c->busaddr != a) {				c = c->next;				if (c == h->cmpQ) 					break;			}			/*			 * If we've found the command, take it off the			 * completion Q and free it			 */			if (c->busaddr == a) {				removeQ(&h->cmpQ, c);				if (c->type == CMD_RWREQ) {					complete_command(c, 0);					cmd_free(h, c);				} else if (c->type == CMD_IOCTL_PEND) {					c->type = CMD_IOCTL_DONE;				}				continue;			}		}	}	/*	 * See if we can queue up some more IO	 */	do_ida_request(h->ctlr);	spin_unlock_irqrestore(&io_request_lock, flags);}/* * This timer was for timing out requests that haven't happened after * IDA_TIMEOUT.  That wasn't such a good idea.  This timer is used to * reset a flags structure so we don't flood the user with * "Non-Fatal error" messages. */static void ida_timer(unsigned long tdata){	ctlr_info_t *h = (ctlr_info_t*)tdata;	h->timer.expires = jiffies + IDA_TIMER;	add_timer(&h->timer);	h->misc_tflags = 0;}/* *  ida_ioctl does some miscellaneous stuff like reporting drive geometry, *  setting readahead and submitting commands from userspace to the controller. */static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg){	int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;	int dsk  = MINOR(inode->i_rdev) >> NWD_SHIFT;	int error;	int diskinfo[4];	struct hd_geometry *geo = (struct hd_geometry *)arg;	ida_ioctl_t *io = (ida_ioctl_t*)arg;	ida_ioctl_t my_io;	switch(cmd) {	case HDIO_GETGEO:		if (hba[ctlr]->drv[dsk].cylinders) {			diskinfo[0] = hba[ctlr]->drv[dsk].heads;			diskinfo[1] = hba[ctlr]->drv[dsk].sectors;			diskinfo[2] = hba[ctlr]->drv[dsk].cylinders;		} else {			diskinfo[0] = 0xff;			diskinfo[1] = 0x3f;			diskinfo[2] = hba[ctlr]->drv[dsk].nr_blks / (0xff*0x3f);		}		put_user(diskinfo[0], &geo->heads);		put_user(diskinfo[1], &geo->sectors);		put_user(diskinfo[2], &geo->cylinders);		put_user(ida[(ctlr<<CTLR_SHIFT)+MINOR(inode->i_rdev)].start_sect, &geo->start);		return 0;	case IDAGETDRVINFO:		return copy_to_user(&io->c.drv,&hba[ctlr]->drv[dsk],sizeof(drv_info_t));	case BLKGETSIZE:		if (!arg) return -EINVAL;		put_user(ida[(ctlr<<CTLR_SHIFT)+MINOR(inode->i_rdev)].nr_sects, (long*)arg);		return 0;	case BLKRRPART:		return revalidate_logvol(inode->i_rdev, 1);	case IDAPASSTHRU:		if (!suser()) return -EPERM;		error = copy_from_user(&my_io, io, sizeof(my_io));		if (error) return error;		error = ida_ctlr_ioctl(ctlr, dsk, &my_io);		if (error) return error;		error = copy_to_user(io, &my_io, sizeof(my_io));		return error;	case IDAGETCTLRSIG:		if (!arg) return -EINVAL;		put_user(hba[ctlr]->ctlr_sig, (int*)arg);		return 0;	case IDAREVALIDATEVOLS:		return revalidate_allvol(inode->i_rdev);	case IDADRIVERVERSION:		if (!arg) return -EINVAL;		put_user(DRIVER_VERSION, (unsigned long*)arg);		return 0;	case IDAGETPCIINFO:	{				ida_pci_info_struct pciinfo;		if (!arg) return -EINVAL;		pciinfo.bus = hba[ctlr]->pci_dev->bus->number;		pciinfo.dev_fn = hba[ctlr]->pci_dev->devfn;		pciinfo.board_id = hba[ctlr]->board_id;		if(copy_to_user((void *) arg, &pciinfo,  			sizeof( ida_pci_info_struct)))				return -EFAULT;		return(0);	}		case BLKFLSBUF:	case BLKROSET:	case BLKROGET:	case BLKRASET:	case BLKRAGET:	case BLKPG:		return blk_ioctl(inode->i_rdev, cmd, arg);	default:		return -EINVAL;	}		}/* * ida_ctlr_ioctl is for passing commands to the controller from userspace. * The command block (io) has already been copied to kernel space for us, * however, any elements in the sglist need to be copied to kernel space * or copied back to userspace. * * Only root may perform a controller passthru command, however I'm not doing * any serious sanity checking on the arguments.  Doing an IDA_WRITE_MEDIA and * putting a 64M buffer in the sglist is probably a *bad* idea. */static int ida_ctlr_ioctl(int ctlr, int dsk, ida_ioctl_t *io){	ctlr_info_t *h = hba[ctlr];	cmdlist_t *c;	void *p = NULL;	unsigned long flags;	int error;	if ((c = cmd_alloc(NULL)) == NULL)		return -ENOMEM;	c->ctlr = ctlr;	c->hdr.unit = (io->unit & UNITVALID) ? (io->unit & ~UNITVALID) : dsk;	c->hdr.size = sizeof(rblk_t) >> 2;	c->size += sizeof(rblk_t);	c->req.hdr.cmd = io->cmd;	c->req.hdr.blk = io->blk;	c->req.hdr.blk_cnt = io->blk_cnt;	c->type = CMD_IOCTL_PEND;	/* Pre submit processing */	switch(io->cmd) {	case PASSTHRU_A:		p = kmalloc(io->sg[0].size, GFP_KERNEL);		if (!p) 		{ 			error = -ENOMEM; 			cmd_free(NULL, c); 			return(error);		}		copy_from_user(p, (void*)io->sg[0].addr, io->sg[0].size);		c->req.hdr.blk = virt_to_bus(&(io->c));		c->req.sg[0].size = io->sg[0].size;		c->req.sg[0].addr = virt_to_bus(p);		c->req.hdr.sg_cnt = 1;		break;	case IDA_READ:		p = kmalloc(io->sg[0].size, GFP_KERNEL);		if (!p) 		{                         error = -ENOMEM;                         cmd_free(NULL, c);                        return(error);                }		c->req.sg[0].size = io->sg[0].size;		c->req.sg[0].addr = virt_to_bus(p);		c->req.hdr.sg_cnt = 1;		break;	case IDA_WRITE:	case IDA_WRITE_MEDIA:	case DIAG_PASS_THRU:		p = kmalloc(io->sg[0].size, GFP_KERNEL);		if (!p)  		{                         error = -ENOMEM;                         cmd_free(NULL, c);                        return(error);                }		copy_from_user(p, (void*)io->sg[0].addr, io->sg[0].size);		c->req.sg[0].size = io->sg[0].size;		c->req.sg[0].addr = virt_to_bus(p);		c->req.hdr.sg_cnt = 1;		break;	default:		c->req.sg[0].size = sizeof(io->c);		c->req.sg[0].addr = virt_to_bus(&io->c);		c->req.hdr.sg_cnt = 1;	}	/* Put the request on the tail of the request queue */	spin_lock_irqsave(&io_request_lock, flags);	addQ(&h->reqQ, c);	h->Qdepth++;	start_io(h);	spin_unlock_irqrestore(&io_request_lock, flags);	/* Wait for completion */	while(c->type != CMD_IOCTL_DONE)		schedule();	/* Post submit processing */	switch(io->cmd) {	case PASSTHRU_A:	case IDA_READ:	case DIAG_PASS_THRU:		copy_to_user((void*)io->sg[0].addr, p, io->sg[0].size);		/* fall through and free p */	case IDA_WRITE:	case IDA_WRITE_MEDIA:		kfree(p);		break;	default:		/* Nothing to do */	}	io->rcode = c->req.hdr.rcode;	cmd_free(NULL, c);	return(0);}/* * Commands are pre-allocated in a large block.  Here we use a simple bitmap * scheme to suballocte them to the driver.  Operations that are not time * critical (and can wait for kmalloc and possibly sleep) can pass in NULL * as the first argument to get a new command. */static cmdlist_t * cmd_alloc(ctlr_info_t *h){	cmdlist_t * c;	int i;	if (h == NULL) {		c = (cmdlist_t*)kmalloc(sizeof(cmdlist_t), GFP_KERNEL);		if(c==NULL)			return NULL;	} else {		do {			i = find_first_zero_bit(h->cmd_pool_bits, NR_CMDS);			if (i == NR_CMDS)				return NULL;		} while(test_and_set_bit(i%32, h->cmd_pool_bits+(i/32)) != 0);		c = h->cmd_pool + i;		h->nr_allocs++;	}	memset(c, 0, sizeof(cmdlist_t));	c->busaddr = virt_to_bus(c);	return c;}static void cmd_free(ctlr_info_t *h, cmdlist_t *c){	int i;	if (h == NULL) {		kfree(c);	} else {		i = c - h->cmd_pool;		clear_bit(i%32, h->cmd_pool_bits+(i/32));		h->nr_frees++;	}}/***********************************************************************    name:        sendcmd    Send a command to an IDA using the memory mapped FIFO interface    and wait for it to complete.      This routine should only be called at init time.

⌨️ 快捷键说明

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