3 * Copyright (c) 2003 David H. Hovemeyer <daveho@cs.umd.edu>
6 * This is free software. You are permitted to use,
7 * redistribute, and modify it as specified in the file "COPYING".
10 #include <geekos/errno.h>
11 #include <geekos/screen.h>
12 #include <geekos/string.h>
13 #include <geekos/malloc.h>
14 #include <geekos/int.h>
15 #include <geekos/kthread.h>
16 #include <geekos/synch.h>
17 #include <geekos/blockdev.h>
19 /*#define BLOCKDEV_DEBUG */
21 # define Debug(args...) Print(args)
23 # define Debug(args...)
26 /* ----------------------------------------------------------------------
27 * Private data and functions
28 * ---------------------------------------------------------------------- */
31 * Lock protecting access/modification of block device list.
33 static struct Mutex s_blockdevLock;
36 * List datatype for list of block devices.
38 DEFINE_LIST(Block_Device_List, Block_Device);
39 IMPLEMENT_LIST(Block_Device_List, Block_Device);
42 * The list in which all block devices in the system
45 static struct Block_Device_List s_deviceList;
48 * Perform a block IO request.
49 * Returns 0 if successful, error code on failure.
51 static int Do_Request(struct Block_Device *dev, enum Request_Type type, int blockNum, void *buf)
53 struct Block_Request *request;
56 request = Create_Request(dev, type, blockNum, buf);
59 Post_Request_And_Wait(request);
60 rc = request->errorCode;
65 /* ----------------------------------------------------------------------
67 * ---------------------------------------------------------------------- */
70 * Register a block device.
71 * This should be called by device drivers in their Init
72 * functions to register all detected devices.
73 * Returns 0 if successful, error code otherwise.
75 int Register_Block_Device(const char *name, struct Block_Device_Ops *ops,
76 int unit, void *driverData, struct Thread_Queue *waitQueue,
77 struct Block_Request_List *requestQueue)
79 struct Block_Device *dev;
82 KASSERT(waitQueue != 0);
83 KASSERT(requestQueue != 0);
85 dev = (struct Block_Device*) Malloc(sizeof(*dev));
89 strcpy(dev->name, name);
93 dev->driverData = driverData;
94 dev->waitQueue = waitQueue;
95 dev->requestQueue = requestQueue;
97 Mutex_Lock(&s_blockdevLock);
98 /* FIXME: handle name conflict with existing device */
99 Debug("Registering block device %s\n", dev->name);
100 Add_To_Back_Of_Block_Device_List(&s_deviceList, dev);
101 Mutex_Unlock(&s_blockdevLock);
107 * Open a named block device.
108 * Return 0 if successful, error code on error.
110 int Open_Block_Device(const char *name, struct Block_Device **pDev)
112 struct Block_Device *dev;
115 Mutex_Lock(&s_blockdevLock);
117 dev = Get_Front_Of_Block_Device_List(&s_deviceList);
119 if (strcmp(dev->name, name) == 0)
121 dev = Get_Next_In_Block_Device_List(dev);
129 rc = dev->ops->Open(dev);
136 Mutex_Unlock(&s_blockdevLock);
142 * Close given block device.
143 * Return 0 if successful, error code on error.
145 int Close_Block_Device(struct Block_Device *dev)
149 Mutex_Lock(&s_blockdevLock);
152 rc = dev->ops->Close(dev);
156 Mutex_Unlock(&s_blockdevLock);
162 * Create a block device request to transfer a single block.
164 struct Block_Request *Create_Request(struct Block_Device *dev, enum Request_Type type,
165 int blockNum, void *buf)
167 struct Block_Request *request = Malloc(sizeof(*request));
170 request->type = type;
171 request->blockNum = blockNum;
173 request->state = PENDING;
174 Clear_Thread_Queue(&request->waitQueue);
180 * Send a block IO request to a device and wait for it to be handled.
181 * Returns when the driver completes the requests or signals
184 void Post_Request_And_Wait(struct Block_Request *request)
186 struct Block_Device *dev;
188 KASSERT(request != 0);
193 /* Send request to the driver */
194 Debug("Posting block device request [@%x]...\n", request);
195 Disable_Interrupts();
196 Add_To_Back_Of_Block_Request_List(dev->requestQueue, request);
197 Wake_Up(dev->waitQueue);
200 /* Wait for request to be processed */
201 Disable_Interrupts();
202 while (request->state == PENDING) {
203 Debug("Waiting, state=%d\n", request->state);
204 Wait(&request->waitQueue);
206 Debug("Wait completed!\n");
211 * Wait for a block request to arrive.
213 struct Block_Request *Dequeue_Request(struct Block_Request_List *requestQueue,
214 struct Thread_Queue *waitQueue)
216 struct Block_Request *request;
218 Disable_Interrupts();
219 while (Is_Block_Request_List_Empty(requestQueue))
221 request = Get_Front_Of_Block_Request_List(requestQueue);
222 Remove_From_Front_Of_Block_Request_List(requestQueue);
229 * Signal the completion of a block request.
231 void Notify_Request_Completion(struct Block_Request *request, enum Request_State state, int errorCode)
233 Disable_Interrupts();
234 request->state = state;
235 request->errorCode = errorCode;
236 Wake_Up(&request->waitQueue);
241 * Read a block from given device.
242 * Return 0 if successful, error code on error.
244 int Block_Read(struct Block_Device *dev, int blockNum, void *buf)
246 return Do_Request(dev, BLOCK_READ, blockNum, buf);
250 * Write a block to given device.
251 * Return 0 if successful, error code on error.
253 int Block_Write(struct Block_Device *dev, int blockNum, void *buf)
255 return Do_Request(dev, BLOCK_WRITE, blockNum, buf);
259 * Get number of blocks in given device.
261 int Get_Num_Blocks(struct Block_Device *dev)
263 return dev->ops->Get_Num_Blocks(dev);