Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Release 1.0
[palacios.git] / geekos / src / geekos / blockdev.c
1 /*
2  * Block devices
3  * Copyright (c) 2003 David H. Hovemeyer <daveho@cs.umd.edu>
4  * $Revision: 1.1 $
5  * 
6  * This is free software.  You are permitted to use,
7  * redistribute, and modify it as specified in the file "COPYING".
8  */
9
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>
18
19 /*#define BLOCKDEV_DEBUG */
20 #ifdef BLOCKDEV_DEBUG
21 #  define Debug(args...) Print(args)
22 #else
23 #  define Debug(args...)
24 #endif
25
26 /* ----------------------------------------------------------------------
27  * Private data and functions
28  * ---------------------------------------------------------------------- */
29
30 /*
31  * Lock protecting access/modification of block device list.
32  */
33 static struct Mutex s_blockdevLock;
34
35 /*
36  * List datatype for list of block devices.
37  */
38 DEFINE_LIST(Block_Device_List, Block_Device);
39 IMPLEMENT_LIST(Block_Device_List, Block_Device);
40
41 /*
42  * The list in which all block devices in the system
43  * are registered.
44  */
45 static struct Block_Device_List s_deviceList;
46
47 /*
48  * Perform a block IO request.
49  * Returns 0 if successful, error code on failure.
50  */
51 static int Do_Request(struct Block_Device *dev, enum Request_Type type, int blockNum, void *buf)
52 {
53     struct Block_Request *request;
54     int rc;
55
56     request = Create_Request(dev, type, blockNum, buf);
57     if (request == 0)
58         return ENOMEM;
59     Post_Request_And_Wait(request);
60     rc = request->errorCode;
61     Free(request);
62     return rc;
63 }
64
65 /* ----------------------------------------------------------------------
66  * Public functions
67  * ---------------------------------------------------------------------- */
68
69 /*
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.
74  */
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)
78 {
79     struct Block_Device *dev;
80
81     KASSERT(ops != 0);
82     KASSERT(waitQueue != 0);
83     KASSERT(requestQueue != 0);
84
85     dev = (struct Block_Device*) Malloc(sizeof(*dev));
86     if (dev == 0)
87         return ENOMEM;
88
89     strcpy(dev->name, name);
90     dev->ops = ops;
91     dev->unit = unit;
92     dev->inUse = false;
93     dev->driverData = driverData;
94     dev->waitQueue = waitQueue;
95     dev->requestQueue = requestQueue;
96
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);
102
103     return 0;
104 }
105
106 /*
107  * Open a named block device.
108  * Return 0 if successful, error code on error.
109  */
110 int Open_Block_Device(const char *name, struct Block_Device **pDev)
111 {
112     struct Block_Device *dev;
113     int rc = 0;
114
115     Mutex_Lock(&s_blockdevLock);
116
117     dev = Get_Front_Of_Block_Device_List(&s_deviceList);
118     while (dev != 0) {
119         if (strcmp(dev->name, name) == 0)
120             break;
121         dev = Get_Next_In_Block_Device_List(dev);
122     }
123
124     if (dev == 0)
125         rc = ENODEV;
126     else if (dev->inUse)
127         rc = EBUSY;
128     else {
129         rc = dev->ops->Open(dev);
130         if (rc == 0) {
131             *pDev = dev;
132             dev->inUse = true;
133         }
134     }
135
136     Mutex_Unlock(&s_blockdevLock);
137
138     return rc;
139 }
140
141 /*
142  * Close given block device.
143  * Return 0 if successful, error code on error.
144  */
145 int Close_Block_Device(struct Block_Device *dev)
146 {
147     int rc;
148
149     Mutex_Lock(&s_blockdevLock);
150
151     KASSERT(dev->inUse);
152     rc = dev->ops->Close(dev);
153     if (rc == 0)
154         dev->inUse = false;
155
156     Mutex_Unlock(&s_blockdevLock);
157
158     return rc;
159 }
160
161 /*
162  * Create a block device request to transfer a single block.
163  */
164 struct Block_Request *Create_Request(struct Block_Device *dev, enum Request_Type type,
165     int blockNum, void *buf)
166 {
167     struct Block_Request *request = Malloc(sizeof(*request));
168     if (request != 0) {
169         request->dev = dev;
170         request->type = type;
171         request->blockNum = blockNum;
172         request->buf = buf;
173         request->state = PENDING;
174         Clear_Thread_Queue(&request->waitQueue);
175     }
176     return request;
177 }
178
179 /*
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
182  * an error.
183  */
184 void Post_Request_And_Wait(struct Block_Request *request)
185 {
186     struct Block_Device *dev;
187
188     KASSERT(request != 0);
189
190     dev = request->dev;
191     KASSERT(dev != 0);
192
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);
198     Enable_Interrupts();
199
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);
205     }
206     Debug("Wait completed!\n");
207     Enable_Interrupts();
208 }
209
210 /*
211  * Wait for a block request to arrive.
212  */
213 struct Block_Request *Dequeue_Request(struct Block_Request_List *requestQueue,
214     struct Thread_Queue *waitQueue)
215 {
216     struct Block_Request *request;
217
218     Disable_Interrupts();
219     while (Is_Block_Request_List_Empty(requestQueue))
220         Wait(waitQueue);
221     request = Get_Front_Of_Block_Request_List(requestQueue);
222     Remove_From_Front_Of_Block_Request_List(requestQueue);
223     Enable_Interrupts();
224
225     return request;
226 }
227
228 /*
229  * Signal the completion of a block request.
230  */
231 void Notify_Request_Completion(struct Block_Request *request, enum Request_State state, int errorCode)
232 {
233     Disable_Interrupts();
234     request->state = state;
235     request->errorCode = errorCode;
236     Wake_Up(&request->waitQueue);
237     Enable_Interrupts();
238 }
239
240 /*
241  * Read a block from given device.
242  * Return 0 if successful, error code on error.
243  */
244 int Block_Read(struct Block_Device *dev, int blockNum, void *buf)
245 {
246     return Do_Request(dev, BLOCK_READ, blockNum, buf);
247 }
248
249 /*
250  * Write a block to given device.
251  * Return 0 if successful, error code on error.
252  */
253 int Block_Write(struct Block_Device *dev, int blockNum, void *buf)
254 {
255     return Do_Request(dev, BLOCK_WRITE, blockNum, buf);
256 }
257
258 /*
259  * Get number of blocks in given device.
260  */
261 int Get_Num_Blocks(struct Block_Device *dev)
262 {
263     return dev->ops->Get_Num_Blocks(dev);
264 }
265