Whamcloud - gitweb
Land b_smallfix onto HEAD (20040416_1638) (more 2.6 build fixes)
[fs/lustre-release.git] / lustre / ptlbd / blk.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (c) 2002, 2003 Cluster File Systems, Inc.
5  *   Author: Zach Brown <zab@clusterfs.com>
6  *
7  *   This file is part of Lustre, http://www.lustre.org.
8  *
9  *   Lustre is free software; you can redistribute it and/or
10  *   modify it under the terms of version 2 of the GNU General Public
11  *   License as published by the Free Software Foundation.
12  *
13  *   Lustre is distributed in the hope that it will be useful,
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *   GNU General Public License for more details.
17  *
18  *   You should have received a copy of the GNU General Public License
19  *   along with Lustre; if not, write to the Free Software
20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */
22 #include <linux/module.h>
23 #include <linux/major.h>
24 #include <linux/smp.h>
25 #include <linux/hdreg.h>
26
27 #define DEBUG_SUBSYSTEM S_PTLBD
28
29 #include <linux/lustre_ha.h>
30 #include <linux/obd_support.h>
31 #include <linux/lustre_idl.h>
32 #include <linux/obd_ptlbd.h>
33
34 /*
35  * todo:
36  *   assign proper major number
37  *   allow more minors
38  *   discover actual block sizes?
39  *   allow more than one sector per io
40  *   think about vary-io
41  *   restrict single ops to sequential block io
42  *   ddn target addresses need to be 32 bit
43  *   cant get to addresses after 0xFFFF0000
44  */
45
46 #define PTLBD_MAJOR 253
47 #define PTLBD_MAX_MINOR 1
48
49 #define MAJOR_NR PTLBD_MAJOR
50 #define LOCAL_END_REQUEST
51 #include <linux/blk.h>
52 #include <linux/blkdev.h>
53 #include <linux/blkpg.h>
54 #include <linux/devfs_fs_kernel.h>
55
56 static int ptlbd_size_size[PTLBD_MAX_MINOR];
57 static int ptlbd_size[PTLBD_MAX_MINOR];
58 static int ptlbd_hardsect_size[PTLBD_MAX_MINOR];
59 static int ptlbd_max_sectors[PTLBD_MAX_MINOR];
60 //RHism static char ptlbd_dev_varyio[PTLBD_MAX_MINOR];
61
62 /*
63  * per minor state, indexed by minor.
64  */
65
66 static struct ptlbd_obd *one_for_now;
67
68 void ptlbd_blk_register(struct ptlbd_obd *ptlbd)
69 {
70         ENTRY;
71         one_for_now = ptlbd;
72         EXIT;
73 }
74
75 static struct ptlbd_obd * ptlbd_get_minor(int minor)
76 {
77         ENTRY;
78         if ( minor >= PTLBD_MAX_MINOR ) 
79                 RETURN( ERR_PTR(-ENODEV) );
80         RETURN(one_for_now);
81 }
82
83 static struct ptlbd_obd * ptlbd_get_inode(struct inode  *inode)
84 {
85         ENTRY;
86
87         if ( inode == NULL ) /* can this really happen? */
88                 RETURN( ERR_PTR(-EINVAL) );
89
90         return ptlbd_get_minor(MINOR(inode->i_rdev));
91 }
92
93 static int ptlbd_open(struct inode *inode, struct file  *file)
94 {
95         struct ptlbd_obd *ptlbd = ptlbd_get_inode(inode);
96         ENTRY;
97
98
99         if ( IS_ERR(ptlbd) )
100                 RETURN(PTR_ERR(ptlbd));
101
102         if (! ptlbd->bd_import->imp_remote_handle.cookie)
103                if (ptlbd_do_connect(ptlbd))
104                        RETURN(-ENOTCONN);
105
106         ptlbd->refcount++;
107         RETURN(0);
108 }
109
110
111 static int ptlbd_ioctl(struct inode *inode, struct file *file,
112                 unsigned int cmd, unsigned long arg)
113 {
114         struct ptlbd_obd *ptlbd;
115         int ret;
116         __u16   major, minor, dev;
117         struct hd_geometry geo;
118
119         if ( ! capable(CAP_SYS_ADMIN) )
120                 RETURN(-EPERM);
121
122         ptlbd = ptlbd_get_inode(inode);
123         if ( IS_ERR(ptlbd) )
124                 RETURN( PTR_ERR(ptlbd) );
125
126         major = MAJOR(inode->i_rdev);
127         minor = MINOR(inode->i_rdev);
128         dev = inode->i_rdev;
129
130         switch(cmd) {
131                 case HDIO_GETGEO:
132                         geo.heads = 64;
133                         geo.sectors = 32;
134                         geo.start = 4;
135                         geo.cylinders = blk_size[major][minor]/
136                                         (geo.heads * geo.sectors);
137                         if (copy_to_user((void *) arg, &geo, sizeof(geo)))
138                                 ret = -EFAULT;
139                         else  
140                                 ret = 0;
141                         break;
142
143                 case BLKSECTGET:
144                         ret = copy_to_user((void *) arg, 
145                                 & max_sectors[major][minor], sizeof(arg));
146                         break;
147
148                 case BLKFLSBUF:
149                         ret = blk_ioctl(dev, cmd, arg);
150                         ptlbd_send_flush_req(ptlbd, PTLBD_FLUSH);
151                         break;
152
153                 case BLKGETSIZE:
154                 case BLKGETSIZE64:
155                 case BLKROSET:
156                 case BLKROGET:
157                 case BLKRASET:
158                 case BLKRAGET:
159                 case BLKSSZGET:
160                 case BLKELVGET:
161                 case BLKELVSET:
162                 default:
163                         ret = blk_ioctl(dev, cmd, arg);
164                         break;
165
166                 case BLKSECTSET:       /* don't allow setting of max_sectors */
167
168                 case BLKRRPART:        /* not a partitionable device */
169                 case BLKPG:            /* "" */
170                         ret = -EINVAL;
171                         break;
172         }
173
174         RETURN(ret);
175 }
176
177 static int ptlbd_release(struct inode *inode, struct file *file)
178 {
179         struct ptlbd_obd *ptlbd = ptlbd_get_inode(inode);
180         ENTRY;
181
182         if ( IS_ERR(ptlbd) ) 
183                 RETURN( PTR_ERR(ptlbd) );
184
185         if (--ptlbd->refcount == 0)
186                 ptlbd_do_disconnect(ptlbd);
187
188         RETURN(0);
189 }
190
191 static void ptlbd_end_request_havelock(struct request *req)
192 {
193         struct buffer_head *bh;
194         int uptodate = 1;
195
196         if ( req->errors )
197                 uptodate = 0;
198
199         while( (bh = req->bh) != NULL ) {
200                 blk_finished_io(bh->b_size >> 9);
201                 req->bh = bh->b_reqnext;
202                 bh->b_reqnext = NULL;
203                 bh->b_end_io(bh, uptodate);
204         }
205         blkdev_release_request(req);
206 }
207
208 #if 0
209 static void ptlbd_end_request_getlock(struct request *req)
210 {
211         unsigned long flags;
212
213         spin_lock_irqsave(&io_request_lock, flags);
214         ptlbd_end_request_havelock(req);
215         spin_unlock_irqrestore(&io_request_lock, flags);
216 }
217 #endif
218
219 static void ptlbd_request(request_queue_t *q)
220 {
221         struct ptlbd_obd *ptlbd;
222         struct request *req;
223         ptlbd_cmd_t cmd;
224         int     errors = 0;
225         ENTRY;
226
227         while ( !QUEUE_EMPTY ) {
228                 req = CURRENT;
229                 ptlbd = ptlbd_get_minor(MINOR(req->rq_dev));
230
231                 blkdev_dequeue_request(req);
232
233                 if ( ptlbd->refcount <= 0 ) {
234                         req->errors++;
235                         ptlbd_end_request_havelock(req);
236                         return;
237                 }
238
239                 spin_unlock_irq(&io_request_lock);
240
241                 if ( req->cmd == READ )
242                         cmd = PTLBD_READ;
243                 else 
244                         cmd = PTLBD_WRITE;
245
246                 errors = ptlbd_send_rw_req(ptlbd, cmd, req->bh);
247
248                 spin_lock_irq(&io_request_lock);
249
250                 if (errors)
251                         req->errors += errors;
252
253                 ptlbd_end_request_havelock(req);
254         }
255 }
256
257 static struct block_device_operations ptlbd_ops = {
258         .owner   = THIS_MODULE,
259         .open    = ptlbd_open,
260         .ioctl   = ptlbd_ioctl,
261         .release = ptlbd_release,
262 };
263
264 int ptlbd_blk_init(void)
265 {
266         int ret;
267         int i;
268         ENTRY;
269
270         ret = register_blkdev(PTLBD_MAJOR, "ptlbd", &ptlbd_ops);
271         if ( ret < 0 ) 
272                 RETURN(ret);
273
274         blk_size[PTLBD_MAJOR] = ptlbd_size;
275         blksize_size[PTLBD_MAJOR] = ptlbd_size_size;
276         hardsect_size[PTLBD_MAJOR] = ptlbd_hardsect_size;
277         max_sectors[PTLBD_MAJOR] = ptlbd_max_sectors;
278
279         blk_init_queue(BLK_DEFAULT_QUEUE(PTLBD_MAJOR), ptlbd_request);
280         blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR), 0);
281
282         for ( i = 0 ; i < PTLBD_MAX_MINOR ; i++) {
283                 ptlbd_size_size[i] = 4096;
284                 /* avoid integer overflow */
285                 ptlbd_size[i] = (16*1024*((1024*1024) >> BLOCK_SIZE_BITS));
286                 ptlbd_hardsect_size[i] = 4096;
287                 ptlbd_max_sectors[i] = PTLRPC_MAX_BRW_PAGES * (4096/512);
288         }
289
290         return 0;
291 }
292
293 void ptlbd_blk_exit(void)
294 {
295         ENTRY;
296         blk_cleanup_queue(BLK_DEFAULT_QUEUE(PTLBD_MAJOR));
297         unregister_blkdev(PTLBD_MAJOR, "ptlbd");
298 }
299
300 #undef MAJOR_NR