/** * Disk interrupt handler. Interrupt is raised so request is handled * by the disk. Sets return value of current request to zero, wakes up * function that is waiting this request and puts next request in work * by calling disk_next_request(). * * @param device Pointer to the device data structure */ static void disk_interrupt_handle(device_t *device) { disk_real_device_t *real_dev = device->real_device; disk_io_area_t *io = (disk_io_area_t *)device->io_address; spinlock_acquire(&real_dev->slock); /* Check if this interrupt was for us */ if (!(DISK_STATUS_RIRQ(io->status) || DISK_STATUS_WIRQ(io->status))) { spinlock_release(&real_dev->slock); return; } /* Just reset both flags, since the handling is identical */ io->command = DISK_COMMAND_WIRQ; io->command = DISK_COMMAND_RIRQ; /* If this assert fails, disk has caused an interrupt without any service request. */ KERNEL_ASSERT(real_dev->request_served != NULL); real_dev->request_served->return_value = 0; /* Wake up the function that is waiting this request to be handled. In case of synchronous request that is disk_submit_request. In case of asynchronous call it is some other function.*/ semaphore_V(real_dev->request_served->sem); real_dev->request_served = NULL; disk_next_request(device->generic_device); spinlock_release(&real_dev->slock); }
/** * Submits a request to the request queue. Request is inserted in the * queue by disk scheduler. * * If request is synchronous (request->sem == NULL) call will block * and wait until the request is handled. Appropriate return value is * returned. * * If request is asynchronous (request->sem != NULL) call will return * immediately. 1 will be returned as retrun value. * * @param gbd Pointer to the gbd-device that will hadle request * * @param request Pointer to the request to be handled. * * @return 1 if success, 0 otherwise. */ static int disk_submit_request(gbd_t *gbd, gbd_request_t *request) { int sem_null; interrupt_status_t intr_status; disk_real_device_t *real_dev = gbd->device->real_device; request->internal = NULL; request->next = NULL; request->return_value = -1; sem_null = (request->sem == NULL); if(sem_null) { /* Semaphore is null so this is synchronous request. Create a new semaphore with value 0. This will cause this function to block until the interrupt handler has handled the request. */ request->sem = semaphore_create(0); if(request->sem == NULL) return 0; /* failure */ } intr_status = _interrupt_disable(); spinlock_acquire(&real_dev->slock); disksched_schedule(&real_dev->request_queue, request); if(real_dev->request_served == NULL) { /* Driver is idle so new request under work */ disk_next_request(gbd); } spinlock_release(&real_dev->slock); _interrupt_set_state(intr_status); if(sem_null) { /* Synchronous call. Wait here until the interrupt handler has handled the request. After this semaphore created earlier in this function is no longer needed. */ semaphore_P(request->sem); semaphore_destroy(request->sem); request->sem = NULL; /* Request is handled. Check the retrun value. */ if(request->return_value == 0) return 1; else return 0; } else { /* Asynchronous call. Assume success, because request is not yet handled. */ return 1; } }