dasd.c

来自「linux-2.4.29操作系统的源码」· C语言 代码 · 共 2,133 行 · 第 1/5 页

C
2,133
字号
                cqr = (ccw_req_t *) lowmem;                memset (cqr, 0, PAGE_SIZE);                cqr->flags |= CQR_FLAGS_LM_CQR;                break;        }	if (cqr == NULL)		return NULL;	/* take page from lowmem_pool for the extra data */	if (data_offset == 0) {                list_for_each_entry (lowmem, &device->lowmem_pool, list) {                        list_del (&lowmem->list);                        cqr->data = (void *) lowmem;                        memset (cqr->data, 0, PAGE_SIZE);                        break;                }		if (cqr->data == NULL) {			printk(KERN_DEBUG PRINTK_HEADER 			       "Couldn't allocate data area\n");                                                lowmem = (dasd_lowmem_t *) cqr;                        list_add (&lowmem->list, &device->lowmem_pool);			return NULL;		}	} else {		/* Extra data already allocated with the request */		cqr->data = (void *) ((addr_t) cqr + data_offset);        }	/* take page from lowmem_pool for the channel program */	if (ccw_offset == 0) {                list_for_each_entry (lowmem, &device->lowmem_pool, list) {                        list_del (&lowmem->list);                        cqr->cpaddr = (ccw1_t *) lowmem;                        memset (cqr->cpaddr, 0, PAGE_SIZE);                        break;                }		if (cqr->cpaddr == NULL) {			printk (KERN_DEBUG PRINTK_HEADER				"Couldn't allocate channel program area\n");			if (data_offset == 0) {                                lowmem = (dasd_lowmem_t *) cqr->data;                                list_add (&lowmem->list, &device->lowmem_pool);                        }                        lowmem = (dasd_lowmem_t *) cqr;                        list_add (&lowmem->list, &device->lowmem_pool);			return NULL;		}	} else {		/* Channel program already allocated with the request */		cqr->cpaddr = (ccw1_t *) ((addr_t) cqr + ccw_offset);        }        /* use the remaining memory of the cqr page for IDALs */        cqr->lowmem_idal_ptr = (void *) ((addr_t) cqr + size_needed);	strncpy ((char *)(&cqr->magic), magic, 4);	ASCEBC((char *)(&cqr->magic), 4);	cqr->cplength = cplength;	cqr->datasize = datasize;	return cqr;}/* * function dasd_free_request * returns a ccw_req_t to the appropriate cache or emergeny request line */voiddasd_free_request (ccw_req_t *cqr, dasd_device_t* device){        unsigned long size_needed;        dasd_lowmem_t *lowmem;#ifdef CONFIG_ARCH_S390X        ccw1_t* ccw;        /* clear any idals used for chain (might be in lowmen cqr page, */        /* in seperate lowmen page or kmalloced */        ccw=cqr->cpaddr-1;        do {                ccw++;                if ((cqr->flags & CQR_FLAGS_LM_CQR) &&                    (ccw->cda >= (unsigned long) cqr) &&                    (ccw->cda < (unsigned long) cqr + PAGE_SIZE)) {                    /* IDAL is on the car lowmem page */                        continue;                }                if ((cqr->flags & CQR_FLAGS_LM_IDAL) &&                    (ccw->cda >= (unsigned long) cqr->lowmem_idal) &&                    (ccw->cda < (unsigned long) cqr->lowmem_idal + PAGE_SIZE)) {                        /* IDAL is on seperate lowmem page */                        continue;                }                /* IDAL was build by set_normalized_cda */                clear_normalized_cda (ccw);        } while ((ccw->flags & CCW_FLAG_CC) ||                  (ccw->flags & CCW_FLAG_DC)   );#endif        /* give idal lowmem page back to lowmem_pool */        if (cqr->flags & CQR_FLAGS_LM_IDAL) {                lowmem = (dasd_lowmem_t *) cqr->lowmem_idal;                list_add (&lowmem->list, &device->lowmem_pool);                cqr->flags &= ~CQR_FLAGS_LM_IDAL;        }                        /* give cqr lowmem pages back to lowmem_pool */        if (cqr->flags & CQR_FLAGS_LM_CQR) {                                 /* make the same decisions as in dasd_alloc_request */                size_needed = (sizeof (ccw_req_t) + 7) & (~7L);                if (size_needed + cqr->datasize <= PAGE_SIZE) {                        /* We kept the data with the request */                        size_needed += (cqr->datasize + 7) & (~7L);                } else {                        lowmem = (dasd_lowmem_t *) cqr->data;                        list_add (&lowmem->list, &device->lowmem_pool);                }                                if (size_needed + cqr->cplength * sizeof(ccw1_t) > PAGE_SIZE) {                        /* We didn't keep the CCWs with request */                        lowmem = (dasd_lowmem_t *) cqr->cpaddr;                        list_add (&lowmem->list, &device->lowmem_pool);                }                lowmem = (dasd_lowmem_t *) cqr;                list_add (&lowmem->list, &device->lowmem_pool);	} else {                ccw_free_request (cqr);        }}/* * function dasd_set_normalized_cda * calls set_normalized_cda to build IDALs. * If this did not work because of low memory, we try to use memory from the  * lowmem pool. */intdasd_set_normalized_cda (ccw1_t *cp, unsigned long address,                          ccw_req_t *cqr, dasd_device_t *device){#ifdef CONFIG_ARCH_S390X        int rc;	int nridaws;        dasd_lowmem_t *lowmem;        int count = cp->count;                /* use lowmem idal page if already assinged */        if (!(cqr->flags & CQR_FLAGS_LM_IDAL)) {                rc = set_normalized_cda (cp, (void *)address);                if (rc !=-ENOMEM) {                        return rc;                }        }                /* get number of idal words needed */        nridaws = ((address & (IDA_BLOCK_SIZE-1)) + count + 		   (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG;        /* check if we need an additional IDALs page */	if (!(cqr->flags & CQR_FLAGS_LM_IDAL)) {                /* we got no lowmem cqr page OR */                /* there is no space left for IDALs */                if ((!(cqr->flags & CQR_FLAGS_LM_CQR)) ||                    ((cqr->lowmem_idal_ptr + nridaws * sizeof(unsigned long)) >                      ((void *) cqr + PAGE_SIZE))) {                                                /* use lowmem page only for ERP or */                        /* if there are less than 2 requests on queue */                        if (device->queue.head != NULL &&                            device->queue.head->next != NULL &&                            device->queue.head->status != CQR_STATUS_ERROR) {                                return -ENOMEM;                        }                                               list_for_each_entry (lowmem, &device->lowmem_pool,                                              list) {                                list_del (&lowmem->list);                                cqr->lowmem_idal = (void *)lowmem;                                cqr->lowmem_idal_ptr  = (void *) lowmem;                                memset (cqr->lowmem_idal, 0, PAGE_SIZE);                                cqr->flags |= CQR_FLAGS_LM_IDAL;                                break;                        }                }                        }                /* now we (should) have an valid lowmem_idal_ptr and enough space for */        /* the IDALs - fill the idals table */	cp->flags |= CCW_FLAG_IDA;	cp->cda = (__u32)(unsigned long)cqr->lowmem_idal_ptr;        do {		*((long*)cqr->lowmem_idal_ptr) = address;		address  = (address & -(IDA_BLOCK_SIZE)) + (IDA_BLOCK_SIZE);                cqr->lowmem_idal_ptr += sizeof(unsigned long);		nridaws --;        } while ( nridaws > 0 );#else         cp->cda = address;#endif	return 0;}/******************************************************************************** * SECTION: (de)queueing of requests to channel program queues  ********************************************************************************//* * function dasd_chanq_enq * appends the cqr given as argument to the queue * has to be called with the queue lock (namely the s390_irq_lock) acquired */inline voiddasd_chanq_enq (dasd_chanq_t * q, ccw_req_t * cqr){	if (q->head != NULL) {		q->tail->next = cqr;	} else		q->head = cqr;	cqr->next = NULL;	q->tail = cqr;	check_then_set (&cqr->status,                         CQR_STATUS_FILLED,                         CQR_STATUS_QUEUED);       #ifdef DASD_PROFILE        if (dasd_profile_level == DASD_PROFILE_ON) {                /* save profile information for non erp cqr */                if (cqr->refers == NULL) {                        unsigned int  counter = 0;                        ccw_req_t     *ptr;                        dasd_device_t *device = cqr->device;                                                /* count the length of the chanq for statistics */                        for (ptr = q->head;                              ptr->next != NULL && counter <=31;                              ptr = ptr->next) {                                counter++;                        }                                                                dasd_global_profile.dasd_io_nr_req[counter]++;                        device->profile.dasd_io_nr_req[counter]++;                }        } /* end if DASD_PROFILE_ON */#endif }/* * function dasd_chanq_enq_head * chains the cqr given as argument to the queue head * has to be called with the queue lock (namely the s390_irq_lock) acquired */inline voiddasd_chanq_enq_head (dasd_chanq_t * q, ccw_req_t * cqr){	cqr->next = q->head;	q->head = cqr;	if (q->tail == NULL)		q->tail = cqr;	check_then_set (&cqr->status,                         CQR_STATUS_FILLED,                         CQR_STATUS_QUEUED);}/* * function dasd_chanq_deq * dechains the cqr given as argument from the queue * has to be called with the queue lock (namely the s390_irq_lock) acquired */inline voiddasd_chanq_deq (dasd_chanq_t * q, ccw_req_t * cqr){	ccw_req_t *prev;	if (cqr == NULL)		BUG ();	if (cqr == q->head) {		q->head = cqr->next;		if (q->head == NULL)			q->tail = NULL;	} else {		prev = q->head;		while (prev && prev->next != cqr)			prev = prev->next;		if (prev == NULL)			return; /* request not in chanq */		prev->next = cqr->next;		if (prev->next == NULL)			q->tail = prev;	}	cqr->next = NULL;}/******************************************************************************** * SECTION: Managing the device queues etc.  ********************************************************************************//* * DASD_RESREL_TIMEOUT * * A timer is used to suspend the current reserve/release request  * if it doesn't return within a certain time. */voiddasd_resrel_timeout (unsigned long cqr_ptr){        dasd_device_t *device = ((ccw_req_t *) cqr_ptr)->device;        ccw_req_t     *cqr;	unsigned long flags;	s390irq_spin_lock_irqsave (device->devinfo.irq,                                    flags);        cqr = device->queue.head;        switch (cqr->status) {        case CQR_STATUS_FILLED:        case CQR_STATUS_QUEUED:                /* request was not started - just set to failed */                cqr->status = CQR_STATUS_FAILED;                break;        case CQR_STATUS_IN_IO:        case CQR_STATUS_ERROR:                        if (device->discipline->term_IO (cqr) != 0);                        cqr->status = CQR_STATUS_FAILED;                break;        default:                ; /* DONE and FAILED are ok */        }        dasd_schedule_bh (device);        s390irq_spin_unlock_irqrestore (device->devinfo.irq,                                         flags);} /* end dasd_resrel_timeout *//* * Call unconditional reserve to break the reserve of an other system. * Timeout the request if it doesn't succseed within a certain time. */static int dasd_steal_lock (dasd_device_t *device){        ccw_req_t *cqr;        int rc = 0;        if (!device->discipline->steal_lock)                 rc = -EINVAL;                cqr = device->discipline->steal_lock (device);                if (cqr) {                struct timer_list res_timer;                                init_timer(&res_timer);                res_timer.function = dasd_resrel_timeout;                 res_timer.data     = (unsigned long) cqr;                res_timer.expires  = jiffies + 4 * HZ;                 add_timer(&res_timer);                                rc = dasd_sleep_on_immediate (cqr);                                del_timer_sync(&res_timer);                 dasd_free_request (cqr,                                    device);        } else {                rc = -ENOMEM;        }        return rc;} /* end dasd_steal_lock *//* * DASD_TERM_IO * * Attempts to terminate the current IO and set it to failed if termination * was successful. * Returns an appropriate return code. */intdasd_term_IO (ccw_req_t * cqr){	int rc = 0;	dasd_device_t *device = cqr->device;	int irq;        int retries = 0;	if (!cqr) {		BUG ();	}	irq = device->devinfo.irq;	if (strncmp ((char *) &cqr->magic,                      device->discipline->ebcname, 4)) {		DEV_MESSAGE (KERN_WARNING, device,                             " ccw_req_t 0x%08x magic doesn't match"                             " discipline 0x%08x",                             cqr->magic,                             *(unsigned int *) device->discipline->name);		return -EINVAL;	}                while ((retries < 5                    ) &&               (cqr->status == CQR_STATUS_IN_IO)   ) {                rc = clear_IO (irq,                                (long)cqr,                                cqr->options);                

⌨️ 快捷键说明

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