Example #1
0
/**
 * 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);
}
Example #2
0
/**
 * 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;
    }
}