📄 dasd.c
字号:
dasd_device_from_kdev (kdev_t kdev){ major_info_t *major_info = NULL; struct list_head *l; unsigned long flags; spin_lock_irqsave (&dasd_major_lock, flags); list_for_each (l, &dasd_major_info[0].list) { major_info = list_entry (l, major_info_t, list); if (major_info->gendisk.major == MAJOR (kdev)) break; } spin_unlock_irqrestore (&dasd_major_lock, flags); if (major_info != &dasd_major_info[0]) return major_info->dasd_device[MINOR (kdev) >> DASD_PARTN_BITS]; return NULL;}/* * function: dasd_device_from_devno * finds the address of the device structure corresponding to the devno * supplied as argument in the major_info structures and returns * it or NULL when not found */static inline dasd_device_t **dasd_device_from_devno (int devno){ major_info_t *major_info; struct list_head *l; int devindex = dasd_devindex_from_devno (devno); unsigned long flags; spin_lock_irqsave (&dasd_major_lock, flags); list_for_each (l, &dasd_major_info[0].list) { major_info = list_entry (l, major_info_t, list); if (devindex < DASD_PER_MAJOR) { spin_unlock_irqrestore (&dasd_major_lock, flags); return &major_info->dasd_device[devindex]; } devindex -= DASD_PER_MAJOR; } spin_unlock_irqrestore (&dasd_major_lock, flags); return NULL;}/* * function: dasd_features_from_devno * finds the device range corresponding to the devno * supplied as argument in the major_info structures and returns * the features set for it */static intdasd_features_from_devno (int devno){ dasd_range_t *temp; int devindex = 0; unsigned long flags; struct list_head *l; spin_lock_irqsave (&range_lock, flags); list_for_each (l, &dasd_range_head.list) { temp = list_entry (l, dasd_range_t, list); if (devno >= temp->from && devno <= temp->to) { spin_unlock_irqrestore (&range_lock, flags); return temp->features; } devindex += temp->to - temp->from + 1; } spin_unlock_irqrestore (&range_lock, flags); return -ENODEV;}/* SECTION: managing dasd disciplines *//* anchor and spinlock for list of disciplines */static struct list_head dasd_disc_head = LIST_HEAD_INIT(dasd_disc_head);static spinlock_t discipline_lock = SPIN_LOCK_UNLOCKED;/* * function dasd_discipline_enq * chains the discpline given as argument to the head of disiplines * head chaining policy is required to allow module disciplines to * be preferred against those, who are statically linked */static inline voiddasd_discipline_enq (dasd_discipline_t * d){ list_add(&d->list, &dasd_disc_head);}/* * function dasd_discipline_deq * removes the discipline given as argument from the list of disciplines */static inline voiddasd_discipline_deq (dasd_discipline_t * d){ list_del(&d->list);}voiddasd_discipline_add (dasd_discipline_t * d){ unsigned long flags; MOD_INC_USE_COUNT; spin_lock_irqsave (&discipline_lock,flags); dasd_discipline_enq (d); spin_unlock_irqrestore (&discipline_lock,flags); dasd_enable_ranges (&dasd_range_head, d, DASD_STATE_ONLINE);}void dasd_discipline_del (dasd_discipline_t * d){ unsigned long flags; spin_lock_irqsave (&discipline_lock,flags); dasd_disable_ranges(&dasd_range_head, d, DASD_STATE_DEL, 1); dasd_discipline_deq (d); spin_unlock_irqrestore (&discipline_lock,flags); MOD_DEC_USE_COUNT;}static inline dasd_discipline_t *dasd_find_disc (dasd_device_t * device, dasd_discipline_t *d){ dasd_discipline_t *t; struct list_head *l = d ? &d->list : dasd_disc_head.next; do { t = list_entry(l,dasd_discipline_t,list); if ( ( t->id_check == NULL || t->id_check (&device->devinfo) == 0 ) && ( t->check_characteristics == NULL || t->check_characteristics (device) == 0 ) ) break; l = l->next; if ( d || l == &dasd_disc_head ) { t = NULL; break; } } while ( 1 ); return t;}/* SECTION: profiling stuff */static dasd_profile_info_t dasd_global_profile;#ifdef DASD_PROFILE/* * macro: dasd_profile_add_counter * increments counter in global and local profiling structures * according to the value */#define dasd_profile_add_counter( value, counter, device ) \{ \ int ind; \ long help; \ for (ind = 0, help = value >> 3; \ ind < 31 && help; \ help = help >> 1, ind++) {} \ dasd_global_profile.counter[ind]++; \ device->profile.counter[ind]++; \}/* * function dasd_profile_add * adds the profiling information from the cqr given as argument to the * global and device specific profiling information */voiddasd_profile_add (ccw_req_t * cqr){ long strtime, irqtime, endtime, tottime; /* in microsecnds*/ long tottimeps, sectors; dasd_device_t *device = cqr->device; if (!cqr->req) /* safeguard against abnormal cqrs */ return; if ((!cqr->buildclk) || (!cqr->startclk) || (!cqr->stopclk ) || (!cqr->endclk ) || (!(sectors = ((struct request *) (cqr->req))->nr_sectors))) return; strtime = ((cqr->startclk - cqr->buildclk) >> 12); irqtime = ((cqr->stopclk - cqr->startclk) >> 12); endtime = ((cqr->endclk - cqr->stopclk) >> 12); tottime = ((cqr->endclk - cqr->buildclk) >> 12); tottimeps = tottime / sectors; if (!dasd_global_profile.dasd_io_reqs) { memset (&dasd_global_profile, 0, sizeof (dasd_profile_info_t)); }; if (!device->profile.dasd_io_reqs) { memset (&device->profile, 0, sizeof (dasd_profile_info_t)); }; dasd_global_profile.dasd_io_reqs++; device->profile.dasd_io_reqs++; dasd_global_profile.dasd_io_sects+=sectors; device->profile.dasd_io_sects+=sectors; dasd_profile_add_counter (sectors, dasd_io_secs, device); dasd_profile_add_counter (tottime, dasd_io_times, device); dasd_profile_add_counter (tottimeps, dasd_io_timps, device); dasd_profile_add_counter (strtime, dasd_io_time1, device); dasd_profile_add_counter (irqtime, dasd_io_time2, device); dasd_profile_add_counter (irqtime / sectors, dasd_io_time2ps, device); dasd_profile_add_counter (endtime, dasd_io_time3, device);}#endif/* SECTION: All the gendisk stuff *//* SECTION: Managing wrappers for ccwcache *//* * function dasd_alloc_request * tries to return space for a channel program of length cplength with * additional data of size datasize. * If the ccwcache cannot fulfill the request it tries the emergeny requests * before giving up finally * FIXME: initialization of ccw_req_t should be done by function of ccwcache */ccw_req_t *dasd_alloc_request (char *magic, int cplength, int datasize, dasd_device_t* device){ ccw_req_t *rv = NULL; if ((rv = ccw_alloc_request (magic, cplength, datasize)) != NULL) { return rv; } if ((((sizeof (ccw_req_t) + 7) & -8) + cplength * sizeof (ccw1_t) + datasize) > PAGE_SIZE) { BUG (); } if (device->lowmem_cqr==NULL) { DASD_DRIVER_DEBUG_EVENT (2, dasd_alloc_request, "(%04x) Low memory! Using emergency request %p.", device->devinfo.devno, device->lowmem_ccws); device->lowmem_cqr=device->lowmem_ccws; rv = device->lowmem_ccws; memset (rv, 0, PAGE_SIZE); strncpy ((char *) (&rv->magic), magic, 4); ASCEBC ((char *) (&rv->magic), 4); rv->cplength = cplength; rv->datasize = datasize; rv->data = (void *) ((long) rv + PAGE_SIZE - datasize); rv->cpaddr = (ccw1_t *) ((long) rv + sizeof (ccw_req_t)); } else { DASD_DRIVER_DEBUG_EVENT (2, dasd_alloc_request, "(%04x) Refusing emergency mem for request " "NULL, already in use at %p.", device->devinfo.devno, device->lowmem_ccws); } return rv;}/* * function dasd_free_request * returns a ccw_req_t to the appropriate cache or emergeny request line */voiddasd_free_request (ccw_req_t * request, dasd_device_t* device){#ifdef CONFIG_ARCH_S390X ccw1_t* ccw; /* clear any idals used for chain */ ccw=request->cpaddr-1; do { ccw++; if ((ccw->cda < (unsigned long) device->lowmem_idals ) || (ccw->cda >= (unsigned long) device->lowmem_idals+PAGE_SIZE) ) clear_normalized_cda (ccw); else { if (device->lowmem_idal_ptr != device->lowmem_idals) DASD_MESSAGE (KERN_WARNING, device, "Freeing emergency idals from request at %p.", request); device->lowmem_idal_ptr = device->lowmem_idals; device->lowmem_cqr=NULL; } } while ((ccw->flags & CCW_FLAG_CC) || (ccw->flags & CCW_FLAG_DC) );#endif if (request != device->lowmem_ccws) { /* compare to lowmem_ccws to protect usage of lowmem_cqr for IDAL only ! */ ccw_free_request (request); } else { DASD_MESSAGE (KERN_WARNING, device, "Freeing emergency request at %p", request); device->lowmem_cqr=NULL; }}intdasd_set_normalized_cda (ccw1_t * cp, unsigned long address, ccw_req_t* request, dasd_device_t* device ){#ifdef CONFIG_ARCH_S390X int nridaws; int count = cp->count; if (set_normalized_cda (cp, address)!=-ENOMEM) { return 0; } if ((device->lowmem_cqr!=NULL) && (device->lowmem_cqr!=request)) { DASD_MESSAGE (KERN_WARNING, device, "Refusing emergency idals for request %p, memory" " is already in use for request %p", request, device->lowmem_cqr); return -ENOMEM; } device->lowmem_cqr=request; if (device->lowmem_idal_ptr == device->lowmem_idals) { DASD_MESSAGE (KERN_WARNING,device, "Low memory! Using emergency IDALs for request %p.\n", request); } nridaws = ((address & (IDA_BLOCK_SIZE-1)) + count + (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG; if ( device->lowmem_idal_ptr>=device->lowmem_idals + PAGE_SIZE ) { /* Ouch! No Idals left for emergency request */ BUG(); } cp->flags |= CCW_FLAG_IDA; cp->cda = (__u32)(unsigned long)device->lowmem_idal_ptr; do { *((long*)device->lowmem_idal_ptr) = address; address = (address & -(IDA_BLOCK_SIZE)) + (IDA_BLOCK_SIZE); nridaws --; device->lowmem_idal_ptr += sizeof(unsigned long); } 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 /* 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]++; }#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; prev->next = cqr->next; if (prev->next == NULL) q->tail = prev; } cqr->next = NULL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -