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 + -
显示快捷键?