📄 dasd.c
字号:
switch (qp->head->status) { case CQR_STATUS_QUEUED: /* try to start the first I/O that can be started */ if (device->discipline->start_IO == NULL) BUG (); device->discipline->start_IO(qp->head); break; case CQR_STATUS_IN_IO: /* Check, if to invoke the missing interrupt handler */ if (dasd_check_expire_time (qp->head)) { /* to be filled with MIH */ } break; case CQR_STATUS_PENDING: /* just wait */ break; default: BUG (); } } s390irq_spin_unlock_irqrestore (irq, flags);} /* end dasd_process_queues *//* * function dasd_run_bh * acquires the locks needed and then runs the bh */static voiddasd_run_bh (dasd_device_t * device){ long flags; spin_lock_irqsave (&io_request_lock, flags); atomic_set (&device->bh_scheduled, 0); dasd_process_queues (device); spin_unlock_irqrestore (&io_request_lock, flags);}/* * function dasd_schedule_bh * schedules the request_fn to run with next run_bh cycle */voiddasd_schedule_bh (dasd_device_t * device){ /* Protect against rescheduling, when already running */ if (atomic_compare_and_swap (0, 1, &device->bh_scheduled)) { return; } INIT_LIST_HEAD (&device->bh_tq.list); device->bh_tq.sync = 0; device->bh_tq.routine = (void *) (void *) dasd_run_bh; device->bh_tq.data = device; queue_task (&device->bh_tq, &tq_immediate); mark_bh (IMMEDIATE_BH); return;}/* * function do_dasd_request * is called from ll_rw_blk.c and provides the caller of * dasd_process_queues */static voiddo_dasd_request (request_queue_t * queue){ dasd_device_t *device = (dasd_device_t *)queue->queuedata; dasd_process_queues (device);}/* * DASD_HANDLE_STATE_CHANGE_PENDING * * DESCRIPTION * Handles the state change pending interrupt. * Search for the device related request queue and check if the first * cqr in queue in in status 'CQR_STATUE_PENDING'. * If so the status is set to 'CQR_STATUS_QUEUED' to reactivate * the device. * * PARAMETER * stat device status of state change pending interrupt. */voiddasd_handle_state_change_pending (devstat_t * stat){ dasd_device_t **device_addr; ccw_req_t *cqr; device_addr = dasd_device_from_devno (stat->devno); if (device_addr == NULL) { printk (KERN_DEBUG PRINTK_HEADER "unable to find device for state change pending " "interrupt: devno%04x\n", stat->devno); return; } /* re-activate first request in queue */ cqr = (*device_addr)->queue.head; if (cqr->status == CQR_STATUS_PENDING) { DASD_MESSAGE (KERN_DEBUG, (*device_addr), "%s", "device request queue restarted by " "state change pending interrupt\n"); del_timer (&(*device_addr)->timer); check_then_set (&cqr->status, CQR_STATUS_PENDING, CQR_STATUS_QUEUED); dasd_schedule_bh (*device_addr); }} /* end dasd_handle_state_change_pending *//* * function dasd_int_handler * is the DASD driver's default interrupt handler for SSCH-IO */voiddasd_int_handler (int irq, void *ds, struct pt_regs *regs){ int ip; ccw_req_t *cqr; dasd_device_t *device; unsigned long long now; dasd_era_t era = dasd_era_none; /* default is everything is okay */ devstat_t *stat = (devstat_t *)ds; if (stat == NULL) { BUG(); } DASD_DRIVER_DEBUG_EVENT (6, dasd_int_handler, "Interrupt: IRQ %02x, stat %02x, devno %04x", irq, stat->dstat, stat->devno); asm volatile ("STCK %0":"=m" (now)); /* first of all check for state change pending interrupt */ if ((stat->dstat & DEV_STAT_ATTENTION ) && (stat->dstat & DEV_STAT_DEV_END ) && (stat->dstat & DEV_STAT_UNIT_EXCEP) ) { DASD_DRIVER_DEBUG_EVENT (2, dasd_int_handler, "State change Interrupt: %04x", stat->devno); dasd_handle_state_change_pending (stat); return; } ip = stat->intparm; if (!ip) { /* no intparm: unsolicited interrupt */ DASD_DRIVER_DEBUG_EVENT (2, dasd_int_handler, "Unsolicited Interrupt: %04x", stat->devno); printk (KERN_DEBUG PRINTK_HEADER "unsolicited interrupt: irq 0x%x devno %04x\n", irq, stat->devno); return; } if (ip & 0x80000001) { DASD_DRIVER_DEBUG_EVENT (2, dasd_int_handler, "spurious Interrupt: %04x", stat->devno); printk (KERN_DEBUG PRINTK_HEADER "spurious interrupt: irq 0x%x devno %04x, parm %08x\n", irq, stat->devno,ip); return; } cqr = (ccw_req_t *)(long)ip; /* check status - the request might have been killed because of dyn dettach */ if (cqr->status != CQR_STATUS_IN_IO) { DASD_DRIVER_DEBUG_EVENT (2, dasd_int_handler, "invalid status %02x on device %04x", cqr->status, stat->devno); printk (KERN_DEBUG PRINTK_HEADER "invalid status: irq 0x%x devno %04x, status %02x\n", irq, stat->devno, cqr->status); return; } device = (dasd_device_t *) cqr->device; if (device == NULL || device != ds-offsetof(dasd_device_t,dev_status)) { BUG(); } if (device->devinfo.irq != irq) { BUG(); } if (strncmp (device->discipline->ebcname, (char *) &cqr->magic, 4)) { BUG(); } /* first of all lets try to find out the appropriate era_action */ DASD_DEVICE_DEBUG_EVENT (4, device," Int: CS/DS 0x%04x", ((stat->cstat<<8)|stat->dstat)); /* first of all lets try to find out the appropriate era_action */ if (stat->flag & DEVSTAT_FLAG_SENSE_AVAIL || stat->dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) { /* anything abnormal ? */ if (device->discipline->examine_error == NULL || stat->flag & DEVSTAT_HALT_FUNCTION) { era = dasd_era_fatal; } else { era = device->discipline->examine_error (cqr, stat); } DASD_DRIVER_DEBUG_EVENT (1, dasd_int_handler," era_code %d", era); } if ( era == dasd_era_none ) { check_then_set(&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_DONE); cqr->stopclk=now; /* start the next queued request if possible -> fast_io */ if (cqr->next && cqr->next->status == CQR_STATUS_QUEUED) { if (device->discipline->start_IO (cqr->next) != 0) { printk (KERN_WARNING PRINTK_HEADER "Interrupt fastpath failed!\n"); } } } else { /* error */ if (cqr->dstat == NULL) cqr->dstat = kmalloc (sizeof (devstat_t), GFP_ATOMIC); if (cqr->dstat) { memcpy (cqr->dstat, stat, sizeof (devstat_t)); } else { PRINT_ERR ("no memory for dstat...ignoring\n"); }#ifdef ERP_DEBUG /* dump sense data */ if (device->discipline && device->discipline->dump_sense ) { device->discipline->dump_sense (device, cqr); }#endif switch (era) { case dasd_era_fatal: check_then_set (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_FAILED); cqr->stopclk = now; break; case dasd_era_recover: check_then_set (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_ERROR); break; default: BUG (); } } if ( cqr == device->init_cqr && ( cqr->status == CQR_STATUS_DONE || cqr->status == CQR_STATUS_FAILED )){ dasd_state_init_to_ready(device); if ( atomic_read(&dasd_init_pending) == 0) wake_up (&dasd_init_waitq); } dasd_schedule_bh (device);} /* end dasd_int_handler *//* SECTION: Some stuff related to error recovery *//* * DEFAULT_ERP_ACTION * * DESCRIPTION * sets up the default-ERP ccw_req_t, namely one, which performs a TIC * to the original channel program with a retry counter of 16 * * PARAMETER * cqr failed CQR * * RETURN VALUES * erp CQR performing the ERP */ccw_req_t *dasd_default_erp_action (ccw_req_t * cqr){ dasd_device_t *device = cqr->device; ccw_req_t *erp = dasd_alloc_request ((char *) &cqr->magic, 1, 0, cqr->device); printk (KERN_DEBUG PRINTK_HEADER "Default ERP called... \n"); if (!erp) { DASD_MESSAGE (KERN_ERR, device, "%s", "Unable to allocate ERP request"); check_then_set (&cqr->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED); asm volatile ("STCK %0":"=m" (cqr->stopclk)); return cqr; } erp->cpaddr->cmd_code = CCW_CMD_TIC; erp->cpaddr->cda = (__u32) (addr_t) cqr->cpaddr; erp->function = dasd_default_erp_action; erp->refers = cqr; erp->device = cqr->device; erp->magic = cqr->magic; erp->retries = 16; erp->status = CQR_STATUS_FILLED; dasd_chanq_enq_head (&device->queue, erp); return erp;} /* end dasd_default_erp_action *//* * DEFAULT_ERP_POSTACTION * * DESCRIPTION * Frees all ERPs of the current ERP Chain and set the status * of the original CQR either to CQR_STATUS_DONE if ERP was successful * or to CQR_STATUS_FAILED if ERP was NOT successful. * NOTE: This function is only called if no discipline postaction * is available * * PARAMETER * erp current erp_head * * RETURN VALUES * cqr pointer to the original CQR */ccw_req_t *dasd_default_erp_postaction (ccw_req_t *erp){ ccw_req_t *cqr = NULL, *free_erp = NULL; dasd_device_t *device = erp->device; int success; if (erp->refers == NULL || erp->function == NULL ) { BUG (); } if (erp->status == CQR_STATUS_DONE) success = 1; else success = 0; /* free all ERPs - but NOT the original cqr */ while (erp->refers != NULL) { free_erp = erp; erp = erp->refers; /* remove the request from the device queue */ dasd_chanq_deq (&device->queue, free_erp); /* free the finished erp request */ dasd_free_request (free_erp, free_erp->device); } /* save ptr to original cqr */ cqr = erp; /* set corresponding status to original cqr */ if (success) { check_then_set (&cqr->status, CQR_STATUS_ERROR, CQR_STATUS_DONE); } else { check_then_set (&cqr->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED); asm volatile ("STCK %0":"=m" (cqr->stopclk)); } return cqr;} /* end default_erp_postaction *//* SECTION: The helpers of the struct file_operations *//* * function dasd_format * performs formatting of _device_ according to _fdata_ * Note: The discipline's format_function is assumed to deliver formatting * commands to format a single unit of the device. In terms of the ECKD * devices this means CCWs are generated to format a single track. */static intdasd_format (dasd_device_t * device, format_data_t * fdata){ int rc = 0; int openct = atomic_read (&device->open_count); if (openct > 1) { DASD_MESSAGE (KERN_WARNING, device, "%s", "dasd_format: device is open! expect errors."); } DASD_MESSAG
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -