linux-old/drivers/s390/block/xpram.c
<<
>>
Prefs
   1
   2/*
   3 * Xpram.c -- the S/390 expanded memory RAM-disk
   4 *           
   5 * significant parts of this code are based on
   6 * the sbull device driver presented in
   7 * A. Rubini: Linux Device Drivers
   8 *
   9 * Author of XPRAM specific coding: Reinhard Buendgen
  10 *                                  buendgen@de.ibm.com
  11 *
  12 * External interfaces:
  13 *   Interfaces to linux kernel
  14 *        xpram_setup: read kernel parameters   (see init/main.c)
  15 *        xpram_init:  initialize device driver (see drivers/block/ll_rw_blk.c)
  16 *   Module interfaces
  17 *        init_module
  18 *        cleanup_module
  19 *   Device specific file operations
  20 *        xpram_iotcl
  21 *        xpram_open
  22 *        xpram_release
  23 *
  24 * "ad-hoc" partitioning:         
  25 *    the expanded memory can be partitioned among several devices 
  26 *    (with different minors). The partitioning set up can be
  27 *    set by kernel or module parameters (int devs & int sizes[])
  28 *
  29 *    module parameters: devs= and sizes=
  30 *    kernel parameters: xpram_parts=
  31 *      note: I did not succeed in parsing numbers 
  32 *            for module parameters of type string "s" ?!?
  33 *
  34 * Other kenel files/modules affected(gerp for "xpram" or "XPRAM":
  35 *    drivers/s390/Config.in
  36 *    drivers/s390/block/Makefile
  37 *    include/linux/blk.h
  38 *    include/linux/major.h
  39 *    init/main.c
  40 *    drivers/block//ll_rw_blk.c
  41 *
  42 *
  43 * Potential future improvements:
  44 *   request clustering: first coding started not yet tested or integrated
  45 *                       I doubt that it really pays off 
  46 *   generic hard disk support to replace ad-hoc partitioning
  47 *
  48 * Tested with 2.2.14 (under VM)
  49 */
  50
  51#ifdef MODULE
  52#  ifndef __KERNEL__
  53#    define __KERNEL__
  54#  endif
  55#  define __NO_VERSION__ /* don't define kernel_version in module.h */
  56#endif /* MODULE */
  57
  58#include <linux/module.h>
  59#include <linux/version.h>
  60
  61#ifdef MODULE
  62char kernel_version [] = UTS_RELEASE; 
  63#endif
  64
  65#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
  66#  define XPRAM_VERSION 24
  67#else
  68#  define XPRAM_VERSION 22
  69#endif 
  70
  71#if (XPRAM_VERSION == 24)
  72#  include <linux/config.h>
  73#  include <linux/init.h>
  74#endif /* V24 */
  75#include <linux/sched.h>
  76#include <linux/kernel.h> /* printk() */
  77#include <linux/slab.h> /* kmalloc() */
  78#if (XPRAM_VERSION == 24)
  79#  include <linux/devfs_fs_kernel.h>
  80#endif /* V24 */
  81#include <linux/fs.h>     /* everything... */
  82#include <linux/errno.h>  /* error codes */
  83#include <linux/timer.h>
  84#include <linux/types.h>  /* size_t */
  85#include <linux/ctype.h>  /* isdigit, isxdigit */
  86#include <linux/fcntl.h>  /* O_ACCMODE */
  87#include <linux/hdreg.h>  /* HDIO_GETGEO */
  88
  89#include <asm/system.h>   /* cli(), *_flags */
  90#include <asm/uaccess.h>  /* put_user */
  91
  92#if (XPRAM_VERSION == 24)
  93#define MAJOR_NR xpram_major /* force definitions on in blk.h */
  94int xpram_major;   /* must be declared before including blk.h */
  95devfs_handle_t xpram_devfs_handle;
  96
  97#define DEVICE_NR(device) MINOR(device)   /* xpram has no partition bits */
  98#define DEVICE_NAME "xpram"               /* name for messaging */
  99#define DEVICE_INTR xpram_intrptr         /* pointer to the bottom half */
 100#define DEVICE_NO_RANDOM                  /* no entropy to contribute */
 101#define DEVICE_OFF(d)                     /* do-nothing */
 102
 103#include <linux/blk.h>
 104
 105#include "xpram.h"        /* local definitions */
 106
 107__setup("xpram_parts=", xpram_setup);
 108#endif /* V24 */
 109
 110/*
 111   define the debug levels:
 112   - 0 No debugging output to console or syslog
 113   - 1 Log internal errors to syslog, ignore check conditions 
 114   - 2 Log internal errors and check conditions to syslog
 115   - 3 Log internal errors to console, log check conditions to syslog
 116   - 4 Log internal errors and check conditions to console
 117   - 5 panic on internal errors, log check conditions to console
 118   - 6 panic on both, internal errors and check conditions
 119 */
 120#define XPRAM_DEBUG 4
 121
 122#define PRINTK_HEADER XPRAM_NAME
 123
 124#if XPRAM_DEBUG > 0
 125#define PRINT_DEBUG(x...) printk ( KERN_DEBUG PRINTK_HEADER "debug:" x )
 126#define PRINT_INFO(x...) printk ( KERN_INFO PRINTK_HEADER "info:" x )
 127#define PRINT_WARN(x...) printk ( KERN_WARNING PRINTK_HEADER "warning:" x )
 128#define PRINT_ERR(x...) printk ( KERN_ERR PRINTK_HEADER "error:" x )
 129#define PRINT_FATAL(x...) panic ( PRINTK_HEADER "panic:"x )
 130#else
 131#define PRINT_DEBUG(x...) printk ( KERN_DEBUG PRINTK_HEADER "debug:"  x )
 132#define PRINT_INFO(x...) printk ( KERN_DEBUG PRINTK_HEADER "info:" x )
 133#define PRINT_WARN(x...) printk ( KERN_DEBUG PRINTK_HEADER "warning:" x )
 134#define PRINT_ERR(x...) printk ( KERN_DEBUG PRINTK_HEADER "error:" x )
 135#define PRINT_FATAL(x...) printk ( KERN_DEBUG PRINTK_HEADER "panic:" x )
 136#endif  
 137
 138#if (XPRAM_VERSION == 22)
 139#define MAJOR_NR xpram_major /* force definitions on in blk.h */
 140int xpram_major;   /* must be declared before including blk.h */
 141
 142#define DEVICE_NR(device) MINOR(device)   /* xpram has no partition bits */
 143#define DEVICE_NAME "xpram"               /* name for messaging */
 144#define DEVICE_INTR xpram_intrptr         /* pointer to the bottom half */
 145#define DEVICE_NO_RANDOM                  /* no entropy to contribute */
 146
 147
 148#define DEVICE_OFF(d) /* do-nothing */
 149
 150#define DEVICE_REQUEST *xpram_dummy_device_request  /* dummy function variable 
 151                                                     * to prevent warnings 
 152                                                     */#include <linux/blk.h>
 153
 154#include "xpram.h"        /* local definitions */
 155#endif /* V22 */
 156
 157/*
 158 * Non-prefixed symbols are static. They are meant to be assigned at
 159 * load time. Prefixed symbols are not static, so they can be used in
 160 * debugging. They are hidden anyways by register_symtab() unless
 161 * XPRAM_DEBUG is defined.
 162 */
 163
 164static int major    = XPRAM_MAJOR;
 165static int devs     = XPRAM_DEVS;
 166static int rahead   = XPRAM_RAHEAD;
 167static int sizes[XPRAM_MAX_DEVS] = { 0, };
 168static int blksize  = XPRAM_BLKSIZE;
 169static int hardsect = XPRAM_HARDSECT;
 170
 171int xpram_devs, xpram_rahead;
 172int xpram_blksize, xpram_hardsect;
 173int xpram_mem_avail = 0;
 174unsigned int xpram_sizes[XPRAM_MAX_DEVS];
 175
 176
 177MODULE_PARM(devs,"i");
 178MODULE_PARM(sizes,"1-" __MODULE_STRING(XPRAM_MAX_DEVS) "i"); 
 179
 180MODULE_PARM_DESC(devs, "number of devices (\"partitions\"), " \
 181                 "the default is " __MODULE_STRING(XPRAM_DEVS) "\n");
 182MODULE_PARM_DESC(sizes, "list of device (partition) sizes " \
 183                 "the defaults are 0s \n" \
 184                 "All devices with size 0 equally partition the "
 185                 "remaining space on the expanded strorage not "
 186                 "claimed by explicit sizes\n");
 187MODULE_LICENSE("GPL");
 188
 189
 190/* The following items are obtained through kmalloc() in init_module() */
 191
 192Xpram_Dev *xpram_devices = NULL;
 193int *xpram_blksizes = NULL;
 194int *xpram_hardsects = NULL;
 195int *xpram_offsets = NULL;   /* partition offsets */
 196
 197#define MIN(x,y) ((x) < (y) ? (x) : (y))
 198#define MAX(x,y) ((x) > (y) ? (x) : (y))
 199
 200/* 
 201 *              compute nearest multiple of 4 , argument must be non-negative
 202 *              the macros used depends on XPRAM_KB_IN_PG = 4 
 203 */
 204
 205#define NEXT4(x) ((x & 0x3) ? (x+4-(x &0x3)) : (x))   /* increment if needed */
 206#define LAST4(x) ((x & 0x3) ? (x-4+(x & 0x3)) : (x))  /* decrement if needed */
 207
 208#if 0               /* this is probably not faster than the previous code */
 209#define NEXT4(x)   ((((x-1)>>2)>>2)+4)             /* increment if needed */
 210#define LAST4(x)   (((x+3)>>2)<<2)                 /* decrement if needed */
 211#endif
 212
 213/* integer formats */
 214#define XPRAM_INVALF -1    /* invalid     */
 215#define XPRAM_HEXF    0    /* hexadecimal */
 216#define XPRAM_DECF    1    /* decimal     */
 217
 218/* 
 219 *    parsing operations (needed for kernel parameter parsing)
 220 */
 221
 222/* -------------------------------------------------------------------------
 223 * sets the string pointer after the next comma 
 224 *
 225 * argument:    strptr pointer to string
 226 * side effect: strptr points to endof string or to position of the next 
 227 *              comma 
 228 * ------------------------------------------------------------------------*/
 229static void
 230xpram_scan_to_next_comma (char **strptr)
 231{
 232        while ( ((**strptr) != ',') && (**strptr) )
 233                (*strptr)++;
 234}
 235
 236/* -------------------------------------------------------------------------
 237 * interpret character as hex-digit
 238 *
 239 * argument: c charcter
 240 * result: c interpreted as hex-digit
 241 * note: can be used to read digits for any base <= 16
 242 * ------------------------------------------------------------------------*/
 243static int
 244xpram_get_hexdigit (char c)
 245{
 246        if ((c >= '0') && (c <= '9'))
 247                return c - '0';
 248        if ((c >= 'a') && (c <= 'f'))
 249                return c + 10 - 'a';
 250        if ((c >= 'A') && (c <= 'F'))
 251                return c + 10 - 'A';
 252        return -1;
 253}
 254
 255/*--------------------------------------------------------------------------
 256 * Check format of unsigned integer
 257 *
 258 * Argument: strptr pointer to string 
 259 * result:   -1 if strptr does not start with a digit 
 260 *                (does not start an integer)
 261 *           0  if strptr starts a positive hex-integer with "0x" 
 262 *           1  if strptr start a positive decimal integer
 263 *
 264 * side effect: if strptr start a positive hex-integer then strptr is
 265 *              set to the character after the "0x"
 266 *-------------------------------------------------------------------------*/
 267static int
 268xpram_int_format(char **strptr)
 269{
 270        if ( !isdigit(**strptr) )
 271                return XPRAM_INVALF;
 272        if ( (**strptr == '0') 
 273             && ( (*((*strptr)+1) == 'x') || (*((*strptr) +1) == 'X') ) 
 274             && isxdigit(*((*strptr)+2)) ) {
 275                *strptr=(*strptr)+2;
 276                return XPRAM_HEXF;
 277        } else return XPRAM_DECF;
 278}
 279
 280/*--------------------------------------------------------------------------
 281 * Read non-negative decimal integer
 282 *
 283 * Argument: strptr pointer to string starting with a non-negative integer
 284 *           in decimal format
 285 * result:   the value of theinitial integer pointed to by strptr
 286 *
 287 * side effect: strptr is set to the first character following the integer
 288 *-------------------------------------------------------------------------*/
 289
 290static int
 291xpram_read_decint (char ** strptr)
 292{
 293        int res=0;
 294        while ( isdigit(**strptr) ) {
 295                res = (res*10) + xpram_get_hexdigit(**strptr);
 296                (*strptr)++;
 297        }
 298        return res;
 299}
 300
 301/*--------------------------------------------------------------------------
 302 * Read non-negative hex-integer
 303 *
 304 * Argument: strptr pointer to string starting with a non-negative integer
 305 *           in hexformat (without "0x" prefix)
 306 * result:   the value of the initial integer pointed to by strptr
 307 *
 308 * side effect: strptr is set to the first character following the integer
 309 *-------------------------------------------------------------------------*/
 310
 311static int
 312xpram_read_hexint (char ** strptr)
 313{
 314        int res=0;
 315        while ( isxdigit(**strptr) ) {
 316                res = (res<<4) + xpram_get_hexdigit(**strptr);
 317                (*strptr)++;
 318        }
 319        return res;
 320}
 321/*--------------------------------------------------------------------------
 322 * Read non-negative integer
 323 *
 324 * Argument: strptr pointer to string starting with a non-negative integer
 325             (either in decimal- or in hex-format
 326 * result:   the value of the initial integer pointed to by strptr
 327 *           in case of a parsing error the result is -EINVAL
 328 *
 329 * side effect: strptr is set to the first character following the integer
 330 *-------------------------------------------------------------------------*/
 331
 332static int
 333xpram_read_int (char ** strptr)
 334{
 335        switch (  xpram_int_format(strptr) ) {
 336        case XPRAM_INVALF: return -EINVAL;
 337        case XPRAM_HEXF:   return xpram_read_hexint(strptr);
 338        case XPRAM_DECF:   return xpram_read_decint(strptr);
 339        default: return -EINVAL;
 340        }
 341}
 342
 343/*--------------------------------------------------------------------------
 344 * Read size
 345 *
 346 * Argument: strptr pointer to string starting with a non-negative integer
 347 *           followed optionally by a size modifier:
 348 *             k or K for kilo (default),
 349 *             m or M for mega
 350 *             g or G for giga
 351 * result:   the value of the initial integer pointed to by strptr
 352 *           multiplied by the modifier value devided by 1024
 353 *           in case of a parsing error the result is -EINVAL
 354 *
 355 * side effect: strptr is set to the first character following the size
 356 *-------------------------------------------------------------------------*/
 357
 358static int
 359xpram_read_size (char ** strptr)
 360{
 361        int res;
 362  
 363        res=xpram_read_int(strptr);
 364        if ( res < 0 )return res;
 365        switch ( **strptr ) {
 366        case 'g':
 367        case 'G': res=res*1024;
 368        case 'm':
 369        case 'M': res=res*1024;
 370        case 'k' :
 371        case 'K' : (* strptr)++;
 372        }
 373  
 374        return res;
 375}
 376
 377
 378/*--------------------------------------------------------------------------
 379 * Read tail of comma separated size list  ",i1,i2,...,in"
 380 *
 381 * Arguments:strptr pointer to string. It is assumed that the string has
 382 *                  the format (","<size>)*
 383 *           maxl integer describing the maximal number of elements in the
 384                  list pointed to by strptr, max must be > 0.
 385 *           ilist array of dimension >= maxl of integers to be modified
 386 *
 387 * result:   -EINVAL if the list is longer than maxl
 388 *           0 otherwise
 389 *
 390 * side effects: for j=1,...,n ilist[ij] is set to the value of ij if it is
 391 *               a valid non-negative integer and to -EINVAL otherwise
 392 *               if no comma is found where it is expected an entry in
 393 *               ilist is set to -EINVAL
 394 *-------------------------------------------------------------------------*/
 395static int
 396xpram_read_size_list_tail (char ** strptr, int maxl, int * ilist)
 397{ 
 398        int i=0;
 399        char *str = *strptr;
 400        int res=0;
 401
 402        while ( (*str == ',') && (i < maxl) ) {
 403                str++;      
 404                ilist[i] = xpram_read_size(&str);
 405                if ( ilist[i] == -EINVAL ) {
 406                        xpram_scan_to_next_comma(&str);
 407                        res = -EINVAL;
 408                }
 409                i++;
 410        }
 411        return res;
 412#if 0  /* be lenient about trailing stuff */
 413        if ( *str != 0 && *str != ' ' ) {
 414                ilist[MAX(i-1,0)] = -EINVAL;
 415                return -EINVAL;
 416        } else return 0;
 417#endif
 418}
 419
 420
 421/*
 422 *   expanded memory operations
 423 */
 424
 425
 426/*--------------------------------------------------------------------*/
 427/* Copy expanded memory page (4kB) into main memory                   */
 428/* Arguments                                                          */
 429/*           page_addr:    address of target page                     */
 430/*           xpage_index:  index of expandeded memory page            */
 431/* Return value                                                       */
 432/*           0:            if operation succeeds                      */
 433/*           non-0:       otherwise                                   */
 434/*--------------------------------------------------------------------*/
 435long xpram_page_in (unsigned long page_addr, unsigned long xpage_index)
 436{
 437        int cc=0;
 438        unsigned long real_page_addr = __pa(page_addr);
 439#ifndef CONFIG_ARCH_S390X
 440        __asm__ __volatile__ (
 441                "   lr  1,%1         \n"   /* r1 = real_page_addr            */
 442                "   lr  2,%2         \n"   /* r2 = xpage_index               */
 443                "   .long 0xb22e0012 \n"   /* pgin r1,r2                     */
 444                /* copy page from expanded memory */
 445                "0: ipm  %0          \n"   /* save status (cc & program mask */
 446                "   srl  %0,28       \n"   /* cc into least significant bits */
 447                "1:                  \n"   /* we are done                    */
 448                ".section .fixup,\"ax\"\n" /* start of fix up section        */
 449                "2: lhi    %0,2      \n"   /* return unused condition code 2 */
 450                "   bras 1,3f        \n"   /* safe label 1: in r1 and goto 3 */
 451                "   .long 1b         \n"   /* literal containing label 1     */
 452                "3: l    1,0(1)      \n"   /* load label 1 address into r1   */
 453                "   br   1           \n"   /* goto label 1 (across sections) */
 454                ".previous           \n"   /* back in text section           */
 455                ".section __ex_table,\"a\"\n" /* start __extable             */
 456                "   .align 4         \n"
 457                "   .long 0b,2b      \n"   /* failure point 0, fixup code 2  */
 458                ".previous           \n"
 459                : "=d" (cc) : "d" (real_page_addr), "d" (xpage_index) : "cc", "1", "2"
 460                );
 461#else /* CONFIG_ARCH_S390X */
 462        __asm__ __volatile__ (
 463                "   lgr  1,%1        \n"   /* r1 = real_page_addr            */
 464                "   lgr  2,%2        \n"   /* r2 = xpage_index               */
 465                "   .long 0xb22e0012 \n"   /* pgin r1,r2                     */
 466                /* copy page from expanded memory */
 467                "0: ipm  %0          \n"   /* save status (cc & program mask */
 468                "   srl  %0,28       \n"   /* cc into least significant bits */
 469                "1:                  \n"   /* we are done                    */
 470                ".section .fixup,\"ax\"\n" /* start of fix up section        */
 471                "2: lghi %0,2        \n"   /* return unused condition code 2 */
 472                "   jg   1b          \n"   /* goto label 1 above             */
 473                ".previous           \n"   /* back in text section           */
 474                ".section __ex_table,\"a\"\n" /* start __extable             */
 475                "   .align 8         \n"
 476                "   .quad 0b,2b      \n"   /* failure point 0, fixup code 2  */
 477                ".previous           \n"
 478                : "=d" (cc) : "d" (real_page_addr), "d" (xpage_index) : "cc", "1", "2"
 479                );
 480#endif /* CONFIG_ARCH_S390X */
 481        switch (cc) {
 482        case 0: return 0;
 483        case 1: return -EIO;
 484        case 2: return -ENXIO;
 485        case 3: return -ENXIO;
 486        default: return -EIO;  /* should not happen */
 487        };
 488}
 489
 490/*--------------------------------------------------------------------*/
 491/* Copy a 4kB page of main memory to an expanded memory page          */
 492/* Arguments                                                          */
 493/*           page_addr:    address of source page                     */
 494/*           xpage_index:  index of expandeded memory page            */
 495/* Return value                                                       */
 496/*           0:            if operation succeeds                      */
 497/*           non-0:        otherwise                                  */
 498/*--------------------------------------------------------------------*/
 499long xpram_page_out (unsigned long page_addr, unsigned long xpage_index)
 500{
 501        int cc=0;
 502        unsigned long real_page_addr = __pa(page_addr);
 503#ifndef CONFIG_ARCH_S390X
 504        __asm__ __volatile__ (
 505                "  lr  1,%1        \n"   /* r1 = mem_page                  */
 506                "  lr  2,%2        \n"   /* r2 = rpi                       */
 507                " .long 0xb22f0012 \n"   /* pgout r1,r2                    */
 508                                /* copy page from expanded memory */
 509                "0: ipm  %0        \n"   /* save status (cc & program mask */
 510                " srl  %0,28       \n"   /* cc into least significant bits */
 511                "1:                  \n"   /* we are done                    */
 512                ".section .fixup,\"ax\"\n" /* start of fix up section        */
 513                "2: lhi   %0,2       \n"   /* return unused condition code 2 */
 514                "   bras 1,3f        \n"   /* safe label 1: in r1 and goto 3 */
 515                "   .long 1b         \n"   /* literal containing label 1     */
 516                "3: l    1,0(1)      \n"   /* load label 1 address into r1   */
 517                "   br   1           \n"   /* goto label 1 (across sections) */
 518                ".previous           \n"   /* back in text section           */
 519                ".section __ex_table,\"a\"\n" /* start __extable             */
 520                "   .align 4         \n"
 521                "   .long 0b,2b      \n"   /* failure point 0, fixup code 2  */
 522                ".previous           \n"
 523                : "=d" (cc) : "d" (real_page_addr), "d" (xpage_index) : "cc", "1", "2"
 524                );
 525#else /* CONFIG_ARCH_S390X */
 526        __asm__ __volatile__ (
 527                "  lgr  1,%1       \n"   /* r1 = mem_page                  */
 528                "  lgr  2,%2       \n"   /* r2 = rpi                       */
 529                " .long 0xb22f0012 \n"   /* pgout r1,r2                    */
 530                                         /* copy page from expanded memory */
 531                "0: ipm  %0        \n"   /* save status (cc & program mask */
 532                "  srl  %0,28      \n"   /* cc into least significant bits */
 533                "1:                \n"   /* we are done                    */
 534                ".section .fixup,\"ax\"\n" /* start of fix up section      */
 535                "2: lghi %0,2      \n"   /* return unused condition code 2 */
 536                "   jg   1b        \n"   /* goto label 1 above             */
 537                ".previous         \n"   /* back in text section           */
 538                ".section __ex_table,\"a\"\n" /* start __extable           */
 539                "   .align 8       \n"
 540                "   .quad 0b,2b    \n"   /* failure point 0, fixup code 2  */
 541                ".previous         \n"
 542                : "=d" (cc) : "d" (real_page_addr), "d" (xpage_index) : "cc", "1", "2"
 543                );
 544#endif  /* CONFIG_ARCH_S390X */
 545        switch (cc) {
 546        case 0: return 0;
 547        case 1: return -EIO;
 548        case 2: { PRINT_ERR("expanded storage lost!\n"); return -ENXIO; }
 549        case 3: return -ENXIO;
 550        default: return -EIO;  /* should not happen */
 551        }
 552}
 553
 554/*--------------------------------------------------------------------*/
 555/* Measure expanded memory                                            */
 556/* Return value                                                       */
 557/*           size of expanded memory in kB (must be a multipe of 4)   */
 558/*--------------------------------------------------------------------*/
 559int xpram_size(void)
 560{
 561        int cc=0;  
 562        unsigned long base=0;
 563        unsigned long po, pi, rpi;   /* page index order, page index */
 564
 565        unsigned long mem_page = __get_free_page(GFP_KERNEL);
 566
 567        /* for po=0,1,2,... try to move in page number base+(2^po)-1 */
 568        pi=1;   
 569        for (po=0; po <= 32; po++) { /* pi = 2^po */
 570                cc=xpram_page_in(mem_page,base+pi-1);
 571                if ( cc ) break;
 572                pi <<= 1;  
 573        }
 574        if ( cc && (po < 31 ) ) {
 575                pi >>=1;
 576                base += pi;
 577                pi >>=1;
 578                for ( ; pi > 0; pi >>= 1) {
 579                        rpi = pi - 1;
 580                        cc=xpram_page_in(mem_page,base+rpi);
 581                        if ( !cc ) base += pi;
 582                }
 583        }
 584        
 585        free_page (mem_page);
 586
 587        if ( cc && (po < 31) ) 
 588                return (XPRAM_KB_IN_PG * base);
 589        else          /* return maximal value possible */
 590                return INT_MAX;
 591}
 592
 593/*
 594 * Open and close
 595 */
 596
 597int xpram_open (struct inode *inode, struct file *filp)
 598{
 599        Xpram_Dev *dev; /* device information */
 600        int num = MINOR(inode->i_rdev);
 601
 602
 603        if (num >= xpram_devs) return -ENODEV;
 604        dev = xpram_devices + num;
 605
 606        PRINT_DEBUG("calling xpram_open for device %d\n",num);
 607        PRINT_DEBUG("  size %dkB, name %s, usage: %d\n", 
 608                     dev->size,dev->device_name, atomic_read(&(dev->usage)));
 609
 610        atomic_inc(&(dev->usage));
 611        return 0;          /* success */
 612}
 613
 614int xpram_release (struct inode *inode, struct file *filp)
 615{
 616        Xpram_Dev *dev = xpram_devices + MINOR(inode->i_rdev);
 617
 618        PRINT_DEBUG("calling xpram_release for device %d (size %dkB, usage: %d)\n",MINOR(inode->i_rdev) ,dev->size,atomic_read(&(dev->usage)));
 619
 620        /*
 621         * If the device is closed for the last time, start a timer
 622         * to release RAM in half a minute. The function and argument
 623         * for the timer have been setup in init_module()
 624         */
 625        if (!atomic_dec_return(&(dev->usage))) {
 626                /* but flush it right now */
 627                /* Everything is already flushed by caller -- AV */
 628        }
 629        return(0);
 630}
 631
 632
 633/*
 634 * The ioctl() implementation
 635 */
 636
 637int xpram_ioctl (struct inode *inode, struct file *filp,
 638                 unsigned int cmd, unsigned long arg)
 639{
 640        int err, size;
 641        struct hd_geometry *geo = (struct hd_geometry *)arg;
 642
 643        PRINT_DEBUG("ioctl 0x%x 0x%lx\n", cmd, arg);
 644        switch(cmd) {
 645
 646        case BLKGETSIZE:  /* 0x1260 */
 647                /* Return the device size, expressed in sectors */
 648                return put_user( 1024* xpram_sizes[MINOR(inode->i_rdev)]
 649                           / XPRAM_SOFTSECT,
 650                           (unsigned long *) arg);
 651
 652        case BLKGETSIZE64:
 653                return put_user( (u64)(1024* xpram_sizes[MINOR(inode->i_rdev)]
 654                           / XPRAM_SOFTSECT) << 9,
 655                           (u64 *) arg);
 656
 657        case BLKFLSBUF: /* flush, 0x1261 */
 658                fsync_dev(inode->i_rdev);
 659                if ( capable(CAP_SYS_ADMIN) )invalidate_buffers(inode->i_rdev);
 660                return 0;
 661
 662        case BLKRAGET: /* return the readahead value, 0x1263 */
 663                if (!arg)  return -EINVAL;
 664                err = 0; /* verify_area_20(VERIFY_WRITE, (long *) arg, sizeof(long));
 665                          * if (err) return err;
 666                          */
 667                put_user(read_ahead[MAJOR(inode->i_rdev)], (long *)arg);
 668
 669                return 0;
 670
 671        case BLKRASET: /* set the readahead value, 0x1262 */
 672                if (!capable(CAP_SYS_ADMIN)) return -EACCES;
 673                if (arg > 0xff) return -EINVAL; /* limit it */
 674                read_ahead[MAJOR(inode->i_rdev)] = arg;
 675                atomic_eieio();
 676                return 0;
 677
 678        case BLKRRPART: /* re-read partition table: can't do it, 0x1259 */
 679                return -EINVAL;
 680
 681
 682#if (XPRAM_VERSION == 22)
 683                RO_IOCTLS(inode->i_rdev, arg); /* the default RO operations 
 684                                                * BLKROSET
 685                                                * BLKROGET
 686                                                */
 687#endif /* V22 */
 688
 689        case HDIO_GETGEO:
 690                /*
 691                 * get geometry: we have to fake one...  trim the size to a
 692                 * multiple of 64 (32k): tell we have 16 sectors, 4 heads,
 693                 * whatever cylinders. Tell also that data starts at sector. 4.
 694                 */
 695                size = xpram_mem_avail * 1024 / XPRAM_SOFTSECT;
 696                /* size = xpram_mem_avail * 1024 / xpram_hardsect; */
 697                size &= ~0x3f; /* multiple of 64 */
 698                if (geo==NULL) return -EINVAL;
 699                /* 
 700                 * err=verify_area_20(VERIFY_WRITE, geo, sizeof(*geo));
 701                 * if (err) return err;
 702                 */
 703
 704                put_user(size >> 6, &geo->cylinders);
 705                put_user(        4, &geo->heads);
 706                put_user(       16, &geo->sectors);
 707                put_user(        4, &geo->start);
 708
 709                return 0;
 710        }
 711
 712        return -EINVAL; /* unknown command */
 713}
 714
 715/*
 716 * The file operations
 717 */
 718
 719#if (XPRAM_VERSION == 22)
 720struct file_operations xpram_fops = {
 721        NULL,          /* lseek: default */
 722        block_read,
 723        block_write,
 724        NULL,          /* xpram_readdir */
 725        NULL,          /* xpram_select */
 726        xpram_ioctl,
 727        NULL,          /* xpram_mmap */
 728        xpram_open,
 729        NULL,          /* flush */
 730        xpram_release,
 731        block_fsync,
 732        NULL,          /* xpram_fasync */
 733        NULL,
 734        NULL
 735};
 736#endif /* V22 */
 737
 738#if (XPRAM_VERSION == 24)
 739struct block_device_operations xpram_devops =
 740{
 741        owner:   THIS_MODULE,
 742        ioctl:   xpram_ioctl,
 743        open:    xpram_open,
 744        release: xpram_release,
 745};
 746#endif /* V24 */
 747
 748/*
 749 * Block-driver specific functions
 750 */
 751
 752void xpram_request(request_queue_t * queue)
 753{
 754        Xpram_Dev *device;
 755        /*     u8 *ptr;          */
 756        /*    int size;          */
 757
 758        unsigned long page_no;         /* expanded memory page number */
 759        unsigned long sects_to_copy;   /* number of sectors to be copied */
 760        char * buffer;                 /* local pointer into buffer cache */
 761        int dev_no;                    /* device number of request */
 762        int fault;                     /* faulty access to expanded memory */
 763#if ( XPRAM_VERSION == 24 )     
 764        struct request * current_req;      /* working request */
 765#else 
 766#       define current_req CURRENT
 767#endif /* V24 */
 768
 769        while(1) {
 770                INIT_REQUEST;
 771
 772                fault=0;
 773#if ( XPRAM_VERSION == 24 )
 774                current_req = blkdev_entry_next_request (&queue->queue_head);
 775#endif /* V24 */
 776                dev_no = DEVICE_NR(current_req->rq_dev); 
 777                /* Check if the minor number is in range */
 778                if ( dev_no > xpram_devs ) {
 779                        static int count = 0;
 780                        if (count++ < 5) /* print the message at most five times */
 781                                PRINT_WARN(" request for unknown device\n");
 782                        end_request(0);
 783                        continue;
 784                }
 785
 786                /* pointer to device structure, from the global array */
 787                device = xpram_devices + dev_no;   
 788                sects_to_copy = current_req->current_nr_sectors;
 789                /* does request exceed size of device ? */
 790                if ( XPRAM_SEC2KB(sects_to_copy) > xpram_sizes[dev_no] ) {
 791                        PRINT_WARN(" request past end of device\n");
 792                        end_request(0);
 793                        continue;
 794                }
 795
 796                /* Does request start at page boundery? -- paranoia */
 797#if 0
 798                PRINT_DEBUG(" req %lx, sect %lx, to copy %lx, buf addr %lx\n", (unsigned long) current_req, current_req->sector, sects_to_copy, (unsigned long) current_req->buffer);
 799#endif
 800                buffer = current_req->buffer;
 801#if XPRAM_SEC_IN_PG != 1
 802                /* Does request start at an expanded storage page boundery? */
 803                if ( current_req->sector &  (XPRAM_SEC_IN_PG - 1) ) {
 804                        PRINT_WARN(" request does not start at an expanded storage page boundery\n");
 805                        PRINT_WARN(" referenced sector: %ld\n",current_req->sector);
 806                        end_request(0);
 807                        continue;
 808                }
 809                /* Does request refere to partial expanded storage pages? */
 810                if ( sects_to_copy & (XPRAM_SEC_IN_PG - 1) ) {
 811                        PRINT_WARN(" request referes to a partial expanded storage page\n");
 812                        end_request(0);
 813                        continue;
 814                }
 815#endif /*  XPRAM_SEC_IN_PG != 1 */
 816                /* Is request buffer aligned with kernel pages? */
 817                if ( ((unsigned long)buffer) & (XPRAM_PGSIZE-1) ) {
 818                        PRINT_WARN(" request buffer is not aligned with kernel pages\n");
 819                        end_request(0);
 820                        continue;
 821                }
 822
 823                /* which page of expanded storage is affected first? */
 824                page_no = (xpram_offsets[dev_no] >> XPRAM_KB_IN_PG_ORDER)
 825                        + (current_req->sector >> XPRAM_SEC_IN_PG_ORDER); 
 826
 827#if 0 
 828                PRINT_DEBUG("request: %d ( dev %d, copy %d sectors, at page %d ) \n", current_req->cmd,dev_no,sects_to_copy,page_no);
 829#endif
 830
 831                switch(current_req->cmd) {
 832                case READ:
 833                        do {
 834                                if ( (fault=xpram_page_in((unsigned long)buffer,page_no)) ) {
 835                                        PRINT_WARN("xpram(dev %d): page in failed for page %ld.\n",dev_no,page_no);
 836                                        break;
 837                                }
 838                                sects_to_copy -= XPRAM_SEC_IN_PG;
 839                                buffer += XPRAM_PGSIZE;
 840                                page_no++;
 841                        } while ( sects_to_copy > 0 );
 842                        break;
 843                case WRITE:
 844                        do {
 845                                if ( (fault=xpram_page_out((unsigned long)buffer,page_no)) 
 846                                        ) {
 847                                        PRINT_WARN("xpram(dev %d): page out failed for page %ld.\n",dev_no,page_no);
 848                                        break;
 849                                }
 850                                sects_to_copy -= XPRAM_SEC_IN_PG;
 851                                buffer += XPRAM_PGSIZE;
 852                                page_no++;
 853                        } while ( sects_to_copy > 0 );
 854                        break;
 855                default:
 856                        /* can't happen */
 857                        end_request(0);
 858                        continue;
 859                }
 860                if ( fault ) end_request(0);
 861                else end_request(1); /* success */
 862        }
 863}
 864
 865/*
 866 *    Kernel interfaces
 867 */
 868
 869/*
 870 * Parses the kernel parameters given in the kernel parameter line.
 871 * The expected format is 
 872 *           <number_of_partitions>[","<partition_size>]*
 873 * where 
 874 *           devices is a positive integer that initializes xpram_devs
 875 *           each size is a non-negative integer possibly followed by a
 876 *           magnitude (k,K,m,M,g,G), the list of sizes initialises 
 877 *           xpram_sizes
 878 *
 879 * Arguments
 880 *           str: substring of kernel parameter line that contains xprams
 881 *                kernel parameters. 
 882 *           ints: not used -- not in Version > 2.3 any more
 883 *
 884 * Result    0 on success, -EINVAl else -- only for Version > 2.3
 885 *
 886 * Side effects
 887 *           the global variabls devs is set to the value of 
 888 *           <number_of_partitions> and sizes[i] is set to the i-th
 889 *           partition size (if provided). A parsing error of a value
 890 *           results in this value being set to -EINVAL.
 891 */
 892#if (XPRAM_VERSION == 22)
 893void xpram_setup (char *str, int *ints)
 894#else 
 895int xpram_setup (char *str)
 896#endif /* V22 */
 897{
 898        devs = xpram_read_int(&str);
 899        if ( devs != -EINVAL ) 
 900          if ( xpram_read_size_list_tail(&str,devs,sizes) < 0 ) {
 901                        PRINT_ERR("error while reading xpram parameters.\n");
 902#if (XPRAM_VERSION == 24)
 903                        return -EINVAL;
 904#endif /* V24 */
 905                          }
 906#if (XPRAM_VERSION == 24)
 907          else return 0;
 908        else return -EINVAL;
 909#elif (XPRAM_VERSION == 22)
 910        return; 
 911#endif /* V24/V22 */
 912}
 913
 914/*
 915 * initialize xpram device driver
 916 *
 917 * Result: 0 ok
 918 *         negative number: negative error code
 919 */
 920
 921int xpram_init(void)
 922{
 923        int result, i;
 924        int mem_usable;       /* net size of expanded memory */
 925        int mem_needed=0;     /* size of expanded memory needed to fullfill
 926                               * requirements of non-zero parameters in sizes
 927                               */
 928
 929        int mem_auto_no=0;    /* number of (implicit) zero parameters in sizes */
 930        int mem_auto;         /* automatically determined device size          */
 931#if (XPRAM_VERSION == 24)
 932        int minor_length;     /* store the length of a minor (w/o '\0') */
 933        int minor_thresh;     /* threshhold for minor lenght            */
 934
 935        request_queue_t *q;   /* request queue */
 936#endif /* V24 */
 937
 938                                /*
 939                                 * Copy the (static) cfg variables to public prefixed ones to allow
 940                                 * snoozing with a debugger.
 941                                 */
 942
 943        xpram_rahead   = rahead;
 944        xpram_blksize  = blksize;
 945        xpram_hardsect = hardsect;
 946
 947        PRINT_INFO("initializing: %s\n","");
 948                                /* check arguments */
 949        xpram_major    = major;
 950        if ( (devs <= 0) || (devs > XPRAM_MAX_DEVS) ) {
 951                PRINT_ERR("invalid number %d of devices\n",devs);
 952                PRINT_ERR("Giving up xpram\n");
 953                return -EINVAL;
 954        }
 955        xpram_devs     = devs;
 956        for (i=0; i < xpram_devs; i++) {
 957                if ( sizes[i] < 0 ) {
 958                        PRINT_ERR("Invalid partition size %d kB\n",xpram_sizes[i]);
 959                        PRINT_ERR("Giving up xpram\n");
 960                        return -EINVAL;
 961                } else {
 962                  xpram_sizes[i] = NEXT4(sizes[i]);  /* page align */
 963                        if ( sizes[i] ) mem_needed += xpram_sizes[i];
 964                        else mem_auto_no++;
 965                }
 966        }
 967
 968        PRINT_DEBUG("  major %d \n", xpram_major);
 969        PRINT_INFO("  number of devices (partitions): %d \n", xpram_devs);
 970        for (i=0; i < xpram_devs; i++) {
 971                if ( sizes[i] )
 972                        PRINT_INFO("  size of partition %d: %d kB\n", i, xpram_sizes[i]);
 973                else
 974                        PRINT_INFO("  size of partition %d to be set automatically\n",i);
 975        }
 976        PRINT_DEBUG("  memory needed (for sized partitions): %d kB\n", mem_needed);
 977        PRINT_DEBUG("  partitions to be sized automatically: %d\n", mem_auto_no);
 978
 979#if 0
 980                                /* Hardsect can't be changed :( */
 981                                /* I try it any way. Yet I must distinguish
 982                                 * between hardsects (to be changed to 4096)
 983                                 * and soft sectors, hard-coded for buffer 
 984                                 * sizes within the requests
 985                                 */
 986        if (hardsect != 512) {
 987                PRINT_ERR("Can't change hardsect size\n");
 988                hardsect = xpram_hardsect = 512;
 989        }
 990#endif
 991        PRINT_INFO("  hardsector size: %dB \n",xpram_hardsect);
 992
 993        /*
 994         * Register your major, and accept a dynamic number
 995         */
 996#if (XPRAM_VERSION == 22)
 997        result = register_blkdev(xpram_major, "xpram", &xpram_fops);
 998#elif (XPRAM_VERSION == 24)
 999        result = devfs_register_blkdev(xpram_major, "xpram", &xpram_devops);
1000#endif /* V22/V24 */
1001        if (result < 0) {
1002                PRINT_ERR("Can't get major %d\n",xpram_major);
1003                PRINT_ERR("Giving up xpram\n");
1004                return result;
1005        }
1006#if (XPRAM_VERSION == 24)
1007        xpram_devfs_handle = devfs_mk_dir (NULL, "slram", NULL);
1008        devfs_register_series (xpram_devfs_handle, "%u", XPRAM_MAX_DEVS,
1009                               DEVFS_FL_DEFAULT, XPRAM_MAJOR, 0,
1010                               S_IFBLK | S_IRUSR | S_IWUSR,
1011                               &xpram_devops, NULL);
1012#endif /* V22/V24 */
1013        if (xpram_major == 0) xpram_major = result; /* dynamic */
1014        major = xpram_major; /* Use `major' later on to save typing */
1015
1016        result = -ENOMEM; /* for the possible errors */
1017
1018        /* 
1019         * measure expanded memory
1020         */
1021
1022        xpram_mem_avail = xpram_size();
1023        if (!xpram_mem_avail) {
1024                PRINT_ERR("No or not enough expanded memory available\n");
1025                PRINT_ERR("Giving up xpram\n");
1026                result = -ENODEV;
1027                goto fail_malloc;
1028        }
1029        PRINT_INFO("  %d kB expanded memory found.\n",xpram_mem_avail );
1030
1031        /*
1032         * Assign the other needed values: request, rahead, size, blksize,
1033         * hardsect. All the minor devices feature the same value.
1034         * Note that `xpram' defines all of them to allow testing non-default
1035         * values. A real device could well avoid setting values in global
1036         * arrays if it uses the default values.
1037         */
1038
1039#if (XPRAM_VERSION == 22)
1040        blk_dev[major].request_fn = xpram_request;
1041#elif (XPRAM_VERSION == 24)
1042        q = BLK_DEFAULT_QUEUE (major);
1043        blk_init_queue (q, xpram_request);
1044        blk_queue_headactive (BLK_DEFAULT_QUEUE (major), 0);
1045#endif /* V22/V24 */
1046        read_ahead[major] = xpram_rahead;
1047
1048        /* we want to have XPRAM_UNUSED blocks security buffer between devices */
1049        mem_usable=xpram_mem_avail-(XPRAM_UNUSED*(xpram_devs-1));
1050        if ( mem_needed > mem_usable ) {
1051                PRINT_ERR("Not enough expanded memory available\n");
1052                PRINT_ERR("Giving up xpram\n");
1053                goto fail_malloc;
1054        }
1055
1056        /*
1057         * partitioning:
1058         * xpram_sizes[i] != 0; partition i has size xpram_sizes[i] kB
1059         * else:             ; all partitions i with xpram_sizesxpram_size[i] 
1060         *                     partition equally the remaining space
1061         */
1062
1063        if ( mem_auto_no ) {
1064                mem_auto=LAST4((mem_usable-mem_needed)/mem_auto_no);
1065                PRINT_INFO("  automatically determined partition size: %d kB\n", mem_auto);
1066                for (i=0; i < xpram_devs; i++) 
1067                        if (xpram_sizes[i] == 0) xpram_sizes[i] = mem_auto;
1068        }
1069        blk_size[major]=xpram_sizes;
1070
1071        xpram_offsets = kmalloc(xpram_devs * sizeof(int), GFP_KERNEL);
1072        if (!xpram_offsets) {
1073                PRINT_ERR("Not enough memory for xpram_offsets\n");
1074                PRINT_ERR("Giving up xpram\n");
1075                goto fail_malloc;
1076        }
1077        xpram_offsets[0] = 0;
1078        for (i=1; i < xpram_devs; i++) 
1079                xpram_offsets[i] = xpram_offsets[i-1] + xpram_sizes[i-1] + XPRAM_UNUSED;
1080
1081#if 0
1082        for (i=0; i < xpram_devs; i++)
1083                PRINT_DEBUG(" device(%d) offset = %d kB, size = %d kB\n",i, xpram_offsets[i], xpram_sizes[i]);
1084#endif
1085
1086        xpram_blksizes = kmalloc(xpram_devs * sizeof(int), GFP_KERNEL);
1087        if (!xpram_blksizes) {
1088                PRINT_ERR("Not enough memory for xpram_blksizes\n");
1089                PRINT_ERR("Giving up xpram\n");
1090                goto fail_malloc_blksizes;
1091        }
1092        for (i=0; i < xpram_devs; i++) /* all the same blocksize */
1093                xpram_blksizes[i] = xpram_blksize;
1094        blksize_size[major]=xpram_blksizes;
1095
1096        xpram_hardsects = kmalloc(xpram_devs * sizeof(int), GFP_KERNEL);
1097        if (!xpram_hardsects) {
1098                PRINT_ERR("Not enough memory for xpram_hardsects\n");
1099                PRINT_ERR("Giving up xpram\n");
1100                goto fail_malloc_hardsects;
1101        }
1102        for (i=0; i < xpram_devs; i++) /* all the same hardsect */
1103                xpram_hardsects[i] = xpram_hardsect;
1104        hardsect_size[major]=xpram_hardsects;
1105   
1106        /* 
1107         * allocate the devices -- we can't have them static, as the number
1108         * can be specified at load time
1109         */
1110
1111        xpram_devices = kmalloc(xpram_devs * sizeof (Xpram_Dev), GFP_KERNEL);
1112        if (!xpram_devices) {
1113                PRINT_ERR("Not enough memory for xpram_devices\n");
1114                PRINT_ERR("Giving up xpram\n");
1115                goto fail_malloc_devices;
1116        }
1117        memset(xpram_devices, 0, xpram_devs * sizeof (Xpram_Dev));
1118#if (XPRAM_VERSION == 24)
1119        minor_length = 1;
1120        minor_thresh = 10;
1121#endif /* V24 */
1122        for (i=0; i < xpram_devs; i++) {
1123                /* data and usage remain zeroed */
1124                xpram_devices[i].size = xpram_sizes[i];  /* size in kB not in bytes */
1125                atomic_set(&(xpram_devices[i].usage),0);
1126#if (XPRAM_VERSION == 24)
1127                if (i == minor_thresh) {
1128                  minor_length++;
1129                  minor_thresh *= 10;
1130                }
1131                xpram_devices[i].device_name = 
1132                  kmalloc(1 + strlen(XPRAM_DEVICE_NAME_PREFIX) + minor_length,GFP_KERNEL);
1133                if ( xpram_devices[i].device_name == NULL ) {
1134                  PRINT_ERR("Not enough memory for xpram_devices[%d].device_name\n",i);
1135                  PRINT_ERR("Giving up xpram\n");
1136                  goto fail_devfs_register;
1137                }
1138                sprintf(xpram_devices[i].device_name,XPRAM_DEVICE_NAME_PREFIX "%d",i);
1139
1140        PRINT_DEBUG("initializing xpram_open for device %d\n",i);
1141        PRINT_DEBUG("  size %dkB, name %s, usage: %d\n", 
1142                     xpram_devices[i].size,xpram_devices[i].device_name, atomic_read(&(xpram_devices[i].usage)));
1143
1144#if 0  /* WHY? */
1145                xpram_devices[i].devfs_entry =
1146                  devfs_register(NULL /* devfs root dir */,
1147                                 xpram_devices[i].device_name, 0,
1148                                 0 /* flags */,
1149                                 XPRAM_MAJOR,i,
1150                                 0755 /* access mode */,
1151                                 0 /* uid */, 0 /* gid */,
1152                                 &xpram_devops,
1153                                 (void *) &(xpram_devices[i])
1154                                 );
1155                if ( xpram_devices[i].devfs_entry == NULL ) {
1156                  PRINT_ERR("devfs system registry failed\n");
1157                  PRINT_ERR("Giving up xpram\n");
1158                  goto fail_devfs_register;
1159                }
1160#endif  /* WHY? */
1161#endif /* V24 */
1162                                 
1163        }
1164
1165        return 0; /* succeed */
1166
1167        /* clean up memory in case of failures */
1168#if (XPRAM_VERSION == 24)
1169 fail_devfs_register:
1170        for (i=0; i < xpram_devs; i++) {
1171          if ( xpram_devices[i].device_name )
1172            kfree(xpram_devices[i].device_name);
1173        }
1174        kfree(xpram_devices);
1175#endif /* V24 */
1176 fail_malloc_blksizes:
1177        kfree (xpram_offsets);
1178 fail_malloc_hardsects:
1179        kfree (xpram_blksizes);
1180        blksize_size[major] = NULL;
1181 fail_malloc_devices:
1182        kfree(xpram_hardsects);
1183        hardsect_size[major] = NULL;
1184 fail_malloc:
1185        read_ahead[major] = 0;
1186#if (XPRAM_VERSION == 22)
1187        blk_dev[major].request_fn = NULL;
1188#endif /* V22 */
1189        /* ???  unregister_chrdev(major, "xpram"); */
1190        unregister_blkdev(major, "xpram");
1191        return result;
1192}
1193
1194/*
1195 * Finally, the module stuff
1196 */
1197
1198int init_module(void)
1199{
1200        int rc = 0;
1201
1202        PRINT_INFO ("trying to load module\n");
1203        rc = xpram_init ();
1204        if (rc == 0) {
1205                PRINT_INFO ("Module loaded successfully\n");
1206        } else {
1207                PRINT_WARN ("Module load returned rc=%d\n", rc);
1208        }
1209        return rc;
1210}
1211
1212void cleanup_module(void)
1213{
1214        int i;
1215
1216                                /* first of all, flush it all and reset all the data structures */
1217
1218
1219        for (i=0; i<xpram_devs; i++)
1220                fsync_dev(MKDEV(xpram_major, i)); /* flush the devices */
1221
1222#if (XPRAM_VERSION == 22)
1223        blk_dev[major].request_fn = NULL;
1224#endif /* V22 */
1225        read_ahead[major] = 0;
1226        blk_size[major] = NULL;
1227        kfree(blksize_size[major]);
1228        blksize_size[major] = NULL;
1229        kfree(hardsect_size[major]);
1230        hardsect_size[major] = NULL;
1231        kfree(xpram_offsets);
1232
1233                                /* finally, the usual cleanup */
1234#if (XPRAM_VERSION == 22)
1235        unregister_blkdev(major, "xpram");
1236#elif (XPRAM_VERSION == 24)
1237        devfs_unregister(xpram_devfs_handle);
1238        if (devfs_unregister_blkdev(MAJOR_NR, "xpram"))
1239                printk(KERN_WARNING "xpram: cannot unregister blkdev\n");
1240#endif /* V22/V24 */
1241        kfree(xpram_devices);
1242}
1243
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.