📄 dasd.c
字号:
/* SECTION: Managing the device queues etc. *//* * DASD_TERM_IO * * attempts to terminate the 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)) { DASD_MESSAGE (KERN_WARNING, device, " ccw_req_t 0x%08x magic doesn't match" " discipline 0x%08x\n", cqr->magic, *(unsigned int *) device->discipline->name); return -EINVAL; } while ((retries < 5 ) && (cqr->status == CQR_STATUS_IN_IO) ) { if ( retries < 2 ) rc = halt_IO(irq, (long)cqr, cqr->options | DOIO_WAIT_FOR_INTERRUPT); else rc = clear_IO(irq, (long)cqr, cqr->options | DOIO_WAIT_FOR_INTERRUPT); switch (rc) { case 0: /* termination successful */ check_then_set (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_FAILED); asm volatile ("STCK %0":"=m" (cqr->stopclk)); break; case -ENODEV: DASD_MESSAGE (KERN_WARNING, device, "%s", "device gone, retry\n"); break; case -EIO: DASD_MESSAGE (KERN_WARNING, device, "%s", "I/O error, retry\n"); break; case -EBUSY: DASD_MESSAGE (KERN_WARNING, device, "%s", "device busy, retry later\n"); break; default: DASD_MESSAGE (KERN_ERR, device, "line %d unknown RC=%d, please report" " to linux390@de.ibm.com\n", __LINE__, rc); BUG (); break; } retries ++; } return rc;}/* * function dasd_start_IO * attempts to start the IO and returns an appropriate return code */intdasd_start_IO (ccw_req_t * cqr){ int rc = 0; dasd_device_t *device = cqr->device; int irq; unsigned long long now; if (!cqr) { BUG (); } irq = device->devinfo.irq; if (strncmp ((char *) &cqr->magic, device->discipline->ebcname, 4)) { DASD_MESSAGE (KERN_WARNING, device, " ccw_req_t 0x%08x magic doesn't match" " discipline 0x%08x\n", cqr->magic, *(unsigned int *) device->discipline->name); return -EINVAL; } asm volatile ("STCK %0":"=m" (now)); cqr->startclk = now; rc = do_IO (irq, cqr->cpaddr, (long) cqr, cqr->lpm, cqr->options); switch (rc) { case 0: if (cqr->options & DOIO_WAIT_FOR_INTERRUPT) { /* request already finished (synchronous IO) */ DASD_MESSAGE (KERN_ERR, device, "%s", " do_IO finished request... " "DOIO_WAIT_FOR_INTERRUPT was set"); check_then_set (&cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_DONE); cqr->stopclk = now; dasd_schedule_bh (device); } else { check_then_set (&cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_IN_IO); } break; case -EBUSY: DASD_MESSAGE (KERN_WARNING, device, "%s", "device busy, retry later\n"); break; case -ETIMEDOUT: DASD_MESSAGE (KERN_WARNING, device, "%s", "request timeout - terminated\n"); case -ENODEV: case -EIO: check_then_set (&cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_FAILED); cqr->stopclk = now; dasd_schedule_bh (device); break; default: DASD_MESSAGE (KERN_ERR, device, "line %d unknown RC=%d, please report" " to linux390@de.ibm.com\n", __LINE__, rc); BUG (); break; } return rc;}/* * function dasd_sleep_on_req * attempts to start the IO and waits for completion * FIXME: replace handmade sleeping by wait_event */intdasd_sleep_on_req (ccw_req_t * req){ unsigned long flags; int cs; int rc = 0; dasd_device_t *device = (dasd_device_t *) req->device; if ( signal_pending(current) ) { return -ERESTARTSYS; } s390irq_spin_lock_irqsave (device->devinfo.irq, flags); dasd_chanq_enq (&device->queue, req); /* let the bh start the request to keep them in order */ dasd_schedule_bh (device); do { s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags); wait_event ( device->wait_q, (((cs = req->status) == CQR_STATUS_DONE) || (cs == CQR_STATUS_FAILED) || signal_pending(current))); s390irq_spin_lock_irqsave (device->devinfo.irq, flags); if ( signal_pending(current) ) { rc = -ERESTARTSYS; if (req->status == CQR_STATUS_IN_IO ) device->discipline->term_IO(req); break; } else if ( req->status == CQR_STATUS_FAILED) { rc = -EIO; break; } } while (cs != CQR_STATUS_DONE && cs != CQR_STATUS_FAILED); s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags); return rc;} /* end dasd_sleep_on_req *//* * function dasd_end_request * posts the buffer_cache about a finalized request * FIXME: for requests splitted to serveral cqrs */static inline voiddasd_end_request (struct request *req, int uptodate){ while (end_that_request_first (req, uptodate, DASD_NAME)) { }#ifndef DEVICE_NO_RANDOM add_blkdev_randomness (MAJOR (req->rq_dev));#endif end_that_request_last (req); return;}/* * function dasd_get_queue * returns the queue corresponding to a device behind a kdev */static request_queue_t *dasd_get_queue (kdev_t kdev){ dasd_device_t *device = dasd_device_from_kdev (kdev); if (!device) { return NULL; } return device->request_queue;}/* * function dasd_check_expire_time * check the request given as argument for expiration * and returns 0 if not yet expired, EIO else */static inline intdasd_check_expire_time (ccw_req_t * cqr){ unsigned long long now; int rc = 0; asm volatile ("STCK %0":"=m" (now)); if (cqr->expires && cqr->expires + cqr->startclk < now) { DASD_MESSAGE (KERN_ERR, ((dasd_device_t *) cqr->device), "IO timeout 0x%08lx%08lx usecs in req %p\n", (long) (cqr->expires >> 44), (long) (cqr->expires >> 12), cqr); cqr->expires <<= 1; rc = -EIO; } return rc;}/* * function dasd_finalize_request * implemets the actions to perform, when a request is finally finished * namely in status CQR_STATUS_DONE || CQR_STATUS_FAILED */static inline voiddasd_finalize_request (ccw_req_t * cqr){ dasd_device_t *device = cqr->device; asm volatile ("STCK %0":"=m" (cqr->endclk)); if (cqr->req) {#ifdef DASD_PROFILE dasd_profile_add (cqr);#endif dasd_end_request (cqr->req, (cqr->status == CQR_STATUS_DONE)); /* free request if nobody is waiting on it */ dasd_free_request (cqr, cqr->device); } else { if ( cqr == device->init_cqr && /* bring late devices online */ device->level <= DASD_STATE_ONLINE ) { device->timer.function = dasd_enable_single_device; device->timer.data = (unsigned long) device; device->timer.expires = jiffies; add_timer(&device->timer); } /* notify sleeping task about finished postprocessing */ wake_up (&device->wait_q); } return;}/* * function dasd_process_queues * transfers the requests on the queue given as argument to the chanq * if possible, the request ist started on a fastpath */static voiddasd_process_queues (dasd_device_t * device){ unsigned long flags; struct request *req; request_queue_t *queue = device->request_queue; dasd_chanq_t *qp = &device->queue; int irq = device->devinfo.irq; ccw_req_t *final_requests = NULL; static int chanq_min_size = DASD_MIN_SIZE_FOR_QUEUE; int chanq_max_size = DASD_CHANQ_MAX_SIZE; ccw_req_t *cqr = NULL, *temp; dasd_erp_postaction_fn_t erp_postaction; s390irq_spin_lock_irqsave (irq, flags); /* First we dechain the requests, processed with completed status */ while (qp->head && ((qp->head->status == CQR_STATUS_DONE ) || (qp->head->status == CQR_STATUS_FAILED) || (qp->head->status == CQR_STATUS_ERROR ) )) { dasd_erp_action_fn_t erp_action; ccw_req_t *erp_cqr = NULL; /* preprocess requests with CQR_STATUS_ERROR */ if (qp->head->status == CQR_STATUS_ERROR) { qp->head->retries--; if (qp->head->dstat->flag & DEVSTAT_HALT_FUNCTION) { check_then_set (&qp->head->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED); asm volatile ("STCK %0":"=m" (qp->head->stopclk)); } else if ((device->discipline->erp_action == NULL ) || ((erp_action = device->discipline->erp_action (qp->head)) == NULL) ) { erp_cqr = dasd_default_erp_action (qp->head); } else { /* call discipline ERP action */ erp_cqr = erp_action (qp->head); } continue; } else if (qp->head->refers) { /* we deal with a finished ERP */ if (qp->head->status == CQR_STATUS_DONE) { DASD_MESSAGE (KERN_DEBUG, device, "%s", "ERP successful"); } else { DASD_MESSAGE (KERN_ERR, device, "%s", "ERP unsuccessful"); } if ((device->discipline->erp_postaction == NULL )|| ((erp_postaction = device->discipline->erp_postaction (qp->head)) == NULL) ) { dasd_default_erp_postaction (qp->head); } else { /* call ERP postaction of discipline */ erp_postaction (qp->head); } continue; } /* dechain request now */ if (final_requests == NULL) final_requests = qp->head; cqr = qp->head; qp->head = qp->head->next; if (qp->head == NULL) qp->tail = NULL; } /* end while over completed requests */ if (cqr) cqr->next = NULL; /* Now clean the requests with final status */ while (final_requests) { temp = final_requests; final_requests = temp->next; dasd_finalize_request (temp); } /* Now we try to fetch requests from the request queue */ for (temp = cqr; temp != NULL; temp = temp->next) if (temp->status == CQR_STATUS_QUEUED) chanq_max_size--; while ((atomic_read(&device->plugged) == 0) && (!queue->plugged) && (!list_empty (&queue->queue_head)) && (req = dasd_next_request (queue)) != NULL) { /* queue empty or certain critera fulfilled -> transfer */ if (qp->head == NULL || chanq_max_size > 0 || (req->nr_sectors >= chanq_min_size)) { ccw_req_t *cqr = NULL; if (is_read_only(device->kdev) && req->cmd == WRITE) { DASD_DRIVER_DEBUG_EVENT (3, dasd_int_handler, "(%04x) Rejecting write request %p\n", device->devinfo.devno, req); dasd_end_request (req, 0); dasd_dequeue_request (queue,req); } else { /* relocate request according to partition table */ req->sector += device->major_info->gendisk. part[MINOR (req->rq_dev)].start_sect; cqr = device->discipline->build_cp_from_req (device, req); if (cqr == NULL) { DASD_DRIVER_DEBUG_EVENT (3, dasd_int_handler, "(%04x) CCW creation failed " "on request %p\n", device->devinfo.devno, req); /* revert relocation of request */ req->sector -= device->major_info->gendisk. part[MINOR (req->rq_dev)].start_sect; break; /* terminate request queue loop */ }#ifdef CONFIG_DYNAMIC_QUEUE_MIN_SIZE chanq_min_size = (chanq_min_size + req->nr_sectors) >> 1;#endif /* CONFIG_DYNAMIC_QUEUE_MIN_SIZE */ dasd_dequeue_request (queue, req); dasd_chanq_enq (qp, cqr); } } else { /* queue not empty OR criteria not met */ break; /* terminate request queue loop */ } } /* we process the requests with non-final status */ if (qp->head) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -