+++ /dev/null
-/*
- * Block devices
- * Copyright (c) 2003 David H. Hovemeyer <daveho@cs.umd.edu>
- * $Revision: 1.1 $
- *
- * This is free software. You are permitted to use,
- * redistribute, and modify it as specified in the file "COPYING".
- */
-
-#include <geekos/errno.h>
-#include <geekos/screen.h>
-#include <geekos/string.h>
-#include <geekos/malloc.h>
-#include <geekos/int.h>
-#include <geekos/kthread.h>
-#include <geekos/synch.h>
-#include <geekos/blockdev.h>
-
-/*#define BLOCKDEV_DEBUG */
-#ifdef BLOCKDEV_DEBUG
-# define Debug(args...) Print(args)
-#else
-# define Debug(args...)
-#endif
-
-/* ----------------------------------------------------------------------
- * Private data and functions
- * ---------------------------------------------------------------------- */
-
-/*
- * Lock protecting access/modification of block device list.
- */
-static struct Mutex s_blockdevLock;
-
-/*
- * List datatype for list of block devices.
- */
-DEFINE_LIST(Block_Device_List, Block_Device);
-IMPLEMENT_LIST(Block_Device_List, Block_Device);
-
-/*
- * The list in which all block devices in the system
- * are registered.
- */
-static struct Block_Device_List s_deviceList;
-
-/*
- * Perform a block IO request.
- * Returns 0 if successful, error code on failure.
- */
-static int Do_Request(struct Block_Device *dev, enum Request_Type type, int blockNum, void *buf)
-{
- struct Block_Request *request;
- int rc;
-
- request = Create_Request(dev, type, blockNum, buf);
- if (request == 0)
- return ENOMEM;
- Post_Request_And_Wait(request);
- rc = request->errorCode;
- Free(request);
- return rc;
-}
-
-/* ----------------------------------------------------------------------
- * Public functions
- * ---------------------------------------------------------------------- */
-
-/*
- * Register a block device.
- * This should be called by device drivers in their Init
- * functions to register all detected devices.
- * Returns 0 if successful, error code otherwise.
- */
-int Register_Block_Device(const char *name, struct Block_Device_Ops *ops,
- int unit, void *driverData, struct Thread_Queue *waitQueue,
- struct Block_Request_List *requestQueue)
-{
- struct Block_Device *dev;
-
- KASSERT(ops != 0);
- KASSERT(waitQueue != 0);
- KASSERT(requestQueue != 0);
-
- dev = (struct Block_Device*) Malloc(sizeof(*dev));
- if (dev == 0)
- return ENOMEM;
-
- strcpy(dev->name, name);
- dev->ops = ops;
- dev->unit = unit;
- dev->inUse = false;
- dev->driverData = driverData;
- dev->waitQueue = waitQueue;
- dev->requestQueue = requestQueue;
-
- Mutex_Lock(&s_blockdevLock);
- /* FIXME: handle name conflict with existing device */
- Debug("Registering block device %s\n", dev->name);
- Add_To_Back_Of_Block_Device_List(&s_deviceList, dev);
- Mutex_Unlock(&s_blockdevLock);
-
- return 0;
-}
-
-/*
- * Open a named block device.
- * Return 0 if successful, error code on error.
- */
-int Open_Block_Device(const char *name, struct Block_Device **pDev)
-{
- struct Block_Device *dev;
- int rc = 0;
-
- Mutex_Lock(&s_blockdevLock);
-
- dev = Get_Front_Of_Block_Device_List(&s_deviceList);
- while (dev != 0) {
- if (strcmp(dev->name, name) == 0)
- break;
- dev = Get_Next_In_Block_Device_List(dev);
- }
-
- if (dev == 0)
- rc = ENODEV;
- else if (dev->inUse)
- rc = EBUSY;
- else {
- rc = dev->ops->Open(dev);
- if (rc == 0) {
- *pDev = dev;
- dev->inUse = true;
- }
- }
-
- Mutex_Unlock(&s_blockdevLock);
-
- return rc;
-}
-
-/*
- * Close given block device.
- * Return 0 if successful, error code on error.
- */
-int Close_Block_Device(struct Block_Device *dev)
-{
- int rc;
-
- Mutex_Lock(&s_blockdevLock);
-
- KASSERT(dev->inUse);
- rc = dev->ops->Close(dev);
- if (rc == 0)
- dev->inUse = false;
-
- Mutex_Unlock(&s_blockdevLock);
-
- return rc;
-}
-
-/*
- * Create a block device request to transfer a single block.
- */
-struct Block_Request *Create_Request(struct Block_Device *dev, enum Request_Type type,
- int blockNum, void *buf)
-{
- struct Block_Request *request = Malloc(sizeof(*request));
- if (request != 0) {
- request->dev = dev;
- request->type = type;
- request->blockNum = blockNum;
- request->buf = buf;
- request->state = PENDING;
- Clear_Thread_Queue(&request->waitQueue);
- }
- return request;
-}
-
-/*
- * Send a block IO request to a device and wait for it to be handled.
- * Returns when the driver completes the requests or signals
- * an error.
- */
-void Post_Request_And_Wait(struct Block_Request *request)
-{
- struct Block_Device *dev;
-
- KASSERT(request != 0);
-
- dev = request->dev;
- KASSERT(dev != 0);
-
- /* Send request to the driver */
- Debug("Posting block device request [@%x]...\n", request);
- Disable_Interrupts();
- Add_To_Back_Of_Block_Request_List(dev->requestQueue, request);
- Wake_Up(dev->waitQueue);
- Enable_Interrupts();
-
- /* Wait for request to be processed */
- Disable_Interrupts();
- while (request->state == PENDING) {
- Debug("Waiting, state=%d\n", request->state);
- Wait(&request->waitQueue);
- }
- Debug("Wait completed!\n");
- Enable_Interrupts();
-}
-
-/*
- * Wait for a block request to arrive.
- */
-struct Block_Request *Dequeue_Request(struct Block_Request_List *requestQueue,
- struct Thread_Queue *waitQueue)
-{
- struct Block_Request *request;
-
- Disable_Interrupts();
- while (Is_Block_Request_List_Empty(requestQueue))
- Wait(waitQueue);
- request = Get_Front_Of_Block_Request_List(requestQueue);
- Remove_From_Front_Of_Block_Request_List(requestQueue);
- Enable_Interrupts();
-
- return request;
-}
-
-/*
- * Signal the completion of a block request.
- */
-void Notify_Request_Completion(struct Block_Request *request, enum Request_State state, int errorCode)
-{
- Disable_Interrupts();
- request->state = state;
- request->errorCode = errorCode;
- Wake_Up(&request->waitQueue);
- Enable_Interrupts();
-}
-
-/*
- * Read a block from given device.
- * Return 0 if successful, error code on error.
- */
-int Block_Read(struct Block_Device *dev, int blockNum, void *buf)
-{
- return Do_Request(dev, BLOCK_READ, blockNum, buf);
-}
-
-/*
- * Write a block to given device.
- * Return 0 if successful, error code on error.
- */
-int Block_Write(struct Block_Device *dev, int blockNum, void *buf)
-{
- return Do_Request(dev, BLOCK_WRITE, blockNum, buf);
-}
-
-/*
- * Get number of blocks in given device.
- */
-int Get_Num_Blocks(struct Block_Device *dev)
-{
- return dev->ops->Get_Num_Blocks(dev);
-}
-