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

📄 dasd_ccwstuff.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
字号:
/*  * File...........: linux/drivers/s390/block/dasd_ccwstuff.c * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 */#include <linux/stddef.h>#include <linux/kernel.h>#include <linux/malloc.h>#include <linux/dasd.h>#include <asm/atomic.h>#include "dasd_types.h"#define PRINTK_HEADER "dasd_ccw:"#define MAX_CP_POWER 9		/* Maximum allowed index */#define CP_PER_PAGE_POWER 9	/* Maximum index, fitting on page */#define get_free_pages __get_free_pages/* Stuff for the handling task_list */dasd_chanq_t *cq_head = NULL;	/* head of task_list */atomic_t chanq_tasks;/* Array of freelists for the channel programs' -space */static ccw1_t *ccwarea[CP_PER_PAGE_POWER + 1] ={NULL,};/* array of pages retrieved for internal use */#define MAX_DASD_PAGES 64static int dasd_page_count = 0;static long dasd_page[MAX_DASD_PAGES];static spinlock_t ccw_lock=SPIN_LOCK_UNLOCKED;	/* spinlock for ccwareas */static spinlock_t cq_lock=SPIN_LOCK_UNLOCKED;	/* spinlock for cq_head */voidccwarea_enq (int index, ccw1_t * area){	FUNCTION_ENTRY ("ccwarea_enq");#if DASD_PARANOIA > 2	if (!area) {		INTERNAL_CHECK ("zero area %s\n", "");	}	if (index > CP_PER_PAGE_POWER) {		INTERNAL_CHECK ("index too large %d\n", index);	}#endif	*(ccw1_t **) area = ccwarea[index];	ccwarea[index] = area;	FUNCTION_EXIT ("ccwarea_enq");	return;}ccw1_t *ccwarea_deq (int index){	ccw1_t *cp;	FUNCTION_ENTRY ("ccwarea_deq");#if DASD_PARANOIA > 2	if (index > CP_PER_PAGE_POWER) {		INTERNAL_CHECK ("index too large %d\n", index);	}#endif	cp = ccwarea[index];	ccwarea[index] = *(ccw1_t **) ccwarea[index];#if DASD_PARANOIA > 2	if (!cp) {		INTERNAL_CHECK ("returning NULL %s\n", "");	}#endif	FUNCTION_EXIT ("ccwarea_deq");	return cp;}ccw1_t *request_cpa (int index){	ccw1_t *freeblk;	FUNCTION_ENTRY ("request_cpa");	if (index > MAX_CP_POWER) {		INTERNAL_ERROR ("index too large %d\n", index);		freeblk = NULL;		goto exit;	}	if (index > CP_PER_PAGE_POWER) {		int pc = 1 << (index - CP_PER_PAGE_POWER);		do {			freeblk = (ccw1_t *) get_free_pages (GFP_ATOMIC, index - CP_PER_PAGE_POWER);			if (dasd_page_count + pc >= MAX_DASD_PAGES) {				PRINT_WARN ("Requesting too many pages...");			} else {				int i;				for (i = 0; i < pc; i++)					dasd_page[dasd_page_count++] =						(long) freeblk + i * PAGE_SIZE;			}			FUNCTION_CONTROL ("requesting index %d", index);			if ( ! freeblk ) {				panic ("No memory received\n");			}		} while (!freeblk);		memset(freeblk,0,PAGE_SIZE<<(index-CP_PER_PAGE_POWER));		goto exit;	}	while (ccwarea[index] == NULL) {		ccw1_t *blk;		if (index == CP_PER_PAGE_POWER) {			do {				blk = (ccw1_t *) get_free_page (GFP_ATOMIC);				if (dasd_page_count + 1 >= MAX_DASD_PAGES) {					PRINT_WARN ("Requesting too many pages...");				} else {					dasd_page[dasd_page_count++] =						(long) blk;				}				if (blk == NULL) {					PRINT_WARN ("Can't allocate page!\n");				}			} while ( ! blk );			memset(blk,0,PAGE_SIZE);			ccwarea_enq (CP_PER_PAGE_POWER, blk);			continue;		}		blk = request_cpa (index + 1);#if DASD_PARANOIA > 1		if (!blk) {			PRINT_WARN ("retrieved NULL");		}#endif				/* DASD_PARANOIA */		ccwarea_enq (index, blk);		ccwarea_enq (index, blk + (1 << index));	}#if DASD_PARANOIA > 2	if (!ccwarea[index]) {		INTERNAL_ERROR ("ccwarea is NULL\n%s", "");	}#endif				/* DASD_PARANOIA */	freeblk = ccwarea_deq (index);#if DASD_PARANOIA > 1	if (!freeblk) {		INTERNAL_ERROR ("freeblk is NULL\n%s", "");	}#endif				/* DASD_PARANOIA */      exit:	FUNCTION_EXIT ("request_cpa");	return freeblk;}ccw1_t *request_cp (int size){	ccw1_t *freeblk;	int index;	int blksize;	/* Determine the index of ccwarea to look at */	for (index = 0, blksize = 1;	     size > blksize;	     index++, blksize = blksize << 1) {	}	if (index > MAX_CP_POWER) {		INTERNAL_ERROR ("index too large %d\n", index);	}	spin_lock (&ccw_lock);	freeblk = request_cpa (index);	spin_unlock (&ccw_lock);	if (freeblk == NULL) {		printk (KERN_WARNING PRINTK_HEADER			"No way to deliver free ccw space\n");	}	return freeblk;}voidrelease_cp (int size, ccw1_t * area){	int index;	int blksize;	/* Determine the index of ccwarea to look at */	for (index = 0, blksize = 1;	     size > blksize;	     index++, blksize = blksize << 1) {	}	if (index > MAX_CP_POWER) {		INTERNAL_ERROR ("index too large %d\n", index);	} else if (index > CP_PER_PAGE_POWER) {		free_pages ((unsigned long) area,			    index - CP_PER_PAGE_POWER);		INTERNAL_CHECK ("large index used: %d\n", index);	} else {		spin_lock (&ccw_lock);		ccwarea_enq (index, area);		spin_unlock (&ccw_lock);	}	return;}/* ---------------------------------------------------------- */static cqr_t *cqrp = NULL;static spinlock_t cqr_lock=SPIN_LOCK_UNLOCKED;voidcqf_enq (cqr_t * cqf){	*(cqr_t **) cqf = cqrp;	cqrp = cqf;}cqr_t *cqf_deq (void){	cqr_t *cqr = cqrp;	cqrp = *(cqr_t **) cqrp;	return cqr;}cqr_t *request_cq (void){	cqr_t *cqr = NULL;	int i;	cqr_t *area;	spin_lock (&cqr_lock);	while (cqrp == NULL) {		do {			area = (cqr_t *) get_free_page (GFP_ATOMIC);			if (area == NULL) {				printk (KERN_WARNING PRINTK_HEADER					"No memory for chanq area\n");			}		} while ( ! area );		memset(area,0,PAGE_SIZE);		if (dasd_page_count + 1 >= MAX_DASD_PAGES) {			PRINT_WARN ("Requesting too many pages...");		} else {			dasd_page[dasd_page_count++] =				(long) area;		}		for (i = 0; i < 4096 / sizeof (cqr_t); i++) {				cqf_enq (area + i);		}	}	cqr = cqf_deq ();	spin_unlock (&cqr_lock);	return cqr;}voidrelease_cq (cqr_t * cqr){	spin_lock (&cqr_lock);	cqf_enq (cqr);	spin_unlock (&cqr_lock);	return;}/* ----------------------------------------------------------- */cqr_t *request_cqr (int cpsize, int datasize){	cqr_t *cqr = NULL;	cqr = request_cq ();	if (cqr == NULL) {		printk (KERN_WARNING PRINTK_HEADER __FILE__			"No memory for chanq request\n");		goto exit;	}	memset (cqr, 0, sizeof (cqr_t));	cqr -> magic = DASD_MAGIC;	if (cpsize) {		cqr->cpaddr = request_cp (cpsize);		if (cqr->cpaddr == NULL) {			printk (KERN_WARNING PRINTK_HEADER __FILE__				"No memory for channel program\n");			goto nocp;		}		cqr->cplength = cpsize;	}	if (datasize) {		do {			cqr->data = (char *) kmalloc (datasize, GFP_ATOMIC);			if (cqr->data == NULL) {				printk (KERN_WARNING PRINTK_HEADER __FILE__					"No memory for cqr data area\n");			}		} while (!cqr->data);		memset (cqr->data,0,datasize);	}	goto exit; nocp:	release_cq (cqr);	cqr = NULL; exit:	return cqr;}intrelease_cqr (cqr_t * cqr){	int rc = 0;	if (cqr == NULL) {		rc = -ENOENT;		return rc;	}	if (cqr->data) {		kfree (cqr->data);	}	if (cqr->dstat) {		kfree (cqr->dstat);	}	if (cqr->cpaddr) {		release_cp (cqr->cplength, cqr->cpaddr);	}	cqr -> magic = dasd_MAGIC;	release_cq (cqr);	return rc;}/* -------------------------------------------------------------- */voiddasd_chanq_enq (dasd_chanq_t * q, cqr_t * cqr){	if (q->head != NULL) {		q->tail->next = cqr;	} else		q->head = cqr;	cqr->next = NULL;	q->tail = cqr;	q->queued_requests ++;	if (atomic_compare_and_swap(CQR_STATUS_FILLED,				    CQR_STATUS_QUEUED,				    &cqr->status)) {		PRINT_WARN ("q_cqr: %p status changed %d\n", 			    cqr,atomic_read(&cqr->status));		atomic_set(&cqr->status,CQR_STATUS_QUEUED);	}}intdasd_chanq_deq (dasd_chanq_t * q, cqr_t * cqr){	cqr_t *prev;	if (cqr == NULL)		return -ENOENT;	if (cqr == (cqr_t *) q->head) {		q->head = cqr->next;		if (q->head == NULL)			q->tail = NULL;	} else {		prev = (cqr_t *) q->head; 		while (prev && prev->next != cqr)			prev = prev->next;		if (prev == NULL)			return -ENOENT;		prev->next = cqr->next;		if (prev->next == NULL)			q->tail = prev;	}	cqr->next = NULL;	q->queued_requests --;	return release_cqr(cqr);}/* -------------------------------------------------------------------------- */voidcql_enq_head (dasd_chanq_t * q){	if (q == NULL) {		INTERNAL_ERROR ("NULL queue passed%s\n", "");		return;	}	if (atomic_read(&q->flags) & DASD_CHANQ_ACTIVE) {		PRINT_WARN("Queue already active");		return;	}	spin_lock(&cq_lock);	atomic_set_mask(DASD_CHANQ_ACTIVE,&q->flags);	q->next_q = cq_head;	cq_head = q;	spin_unlock(&cq_lock);}voidcql_deq (dasd_chanq_t * q){	dasd_chanq_t *c;        if (cq_head == NULL) {                INTERNAL_ERROR ("Channel queue is empty%s\n", "");		return;	}	if (q == NULL) {		INTERNAL_ERROR ("NULL queue passed%s\n", "");		return;	}	spin_lock(&cq_lock);	if (! (atomic_read(&q->flags) & DASD_CHANQ_ACTIVE)) {		PRINT_WARN("Queue not active\n");	}	else if (cq_head == q) {		cq_head = q->next_q;	} else {		c = cq_head;		while (c->next_q && c->next_q != q)			c = c->next_q;		if (c->next_q != q)			INTERNAL_ERROR ("Entry not in queue%s\n", "");		else			c->next_q = q->next_q;	}	q->next_q = NULL;	atomic_clear_mask(DASD_CHANQ_ACTIVE,&q->flags);	spin_unlock(&cq_lock);}

⌨️ 快捷键说明

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