home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 2 / crawlyvol2.bin / alt_os / mint / mfs6011 / source / minixfs / hdio.c < prev    next >
C/C++ Source or Header  |  1994-05-13  |  12KB  |  579 lines

  1. #include "pun.h"
  2. #include "xhdi.h"
  3.  
  4. #include <string.h>
  5.  
  6. #ifdef MFS_XFS
  7. #include "minixfs.h"
  8. #include "global.h"
  9. #define XRWABS RWABS
  10. #define DWARN(mes,drive) ALERT("Drive %c: " mes,drive)
  11. #else
  12. #define DWARN(mes,drive) fprintf(stderr,"Drive %c: " mes "\n",drive)
  13. #define ALERT(x)     fprintf(stderr,x "\n")
  14. #define NEED_SUPER
  15. #define RWABS Rwabs
  16. #define Kmalloc malloc
  17. #define Kfree free
  18. #define GETBPB Getbpb
  19. #include <osbind.h>
  20. #include <alloc.h>
  21. #include <stdio.h>
  22. #include "hdio.h"
  23.  
  24. #define XRWABS(a,b,c,d,e,f) \
  25. trap_13_wwlwwwl((short)(0x04),(short)(a),(long)(b),(short)(c),(short)(d)\
  26. ,(short)(e),(long)(f) )
  27.  
  28. #define trap_13_wwlwwwl(n, a, b, c, d, e, f)                \
  29. ({                                    \
  30.     register long retvalue __asm__("d0");                \
  31.     volatile short _a = (volatile short)(a);            \
  32.     volatile long  _b = (volatile long) (b);            \
  33.     volatile short _c = (volatile short)(c);            \
  34.     volatile short _d = (volatile short)(d);            \
  35.     volatile short _e = (volatile short)(e);            \
  36.     volatile long  _f = (volatile long) (f);            \
  37.                                         \
  38.     __asm__ volatile                        \
  39.     ("\
  40.         movl    %5,sp@-; \
  41.         movw    %4,sp@-; \
  42.         movw    %3,sp@-; \
  43.         movw    %2,sp@-; \
  44.         movl    %1,sp@-; \
  45.         movw    %0,sp@-    "                    \
  46.     :                          /* outputs */    \
  47.     : "r"(_a), "r"(_b), "r"(_c), "r"(_d), "r"(_e), "r"(_f) /* inputs  */ \
  48.     );                                \
  49.                                     \
  50.     __asm__ volatile                        \
  51.     ("\
  52.         movw    %1,sp@-; \
  53.         trap    #13;    \
  54.         addw    #18,sp "                    \
  55.     : "=r"(retvalue)            /* outputs */        \
  56.     : "g"(n)                /* inputs  */        \
  57.     : "d0", "d1", "d2", "a0", "a1", "a2"    /* clobbered regs */    \
  58.     );                                \
  59.     retvalue;                            \
  60. })
  61.  
  62. #endif
  63.  
  64. /* List of error codes for get_hddinf */
  65.  
  66. char *hdd_err[] = { 
  67. "OK",
  68. "Bad BPB on floppy drive",                /* 1 */
  69. "Need drive A-P for PUN_INFO",                /* 2 */
  70. "Invalid or no PUN_INFO structure",            /* 3 */
  71. "Invalid drive",                    /* 4 */
  72. "Physical mode disabled for ICD software",        /* 5 */
  73. "Physical lrecno error",                /* 6 */
  74. "XHInqDev2 failed (old XHDI version?) and bad BPB",    /* 7 */
  75. "XHInqDev failed",                    /* 8 */
  76. "Unrecognised partition id",                /* 9 */
  77. "XHInqTarget failed",                    /* 10 */
  78. "Unsupported physical sector size",            /* 11 */
  79. "Invalid partition start (zero BPB?)"             /* 12 */
  80. "ICD software too old to fix",                /* 13 */
  81. /* These are from set_lrecno */
  82. "Memory allocation failure",                /* 14 */
  83. "Unable to access last block"                /* 15 */
  84.  
  85. };
  86.  
  87.  
  88. /*
  89.  * Hard disk info. This is a general purpose routine to handle minixfs' needs
  90.  * for hard disks. If this function returns non-zero then the partition 
  91.  * cannot be accessed. XHDI and pun_info are used to get partition info.
  92.  * The structure 'hdinf' is filled in as approproiate.
  93.  *
  94.  * If this looks awful then that's because it *is*.
  95.  */
  96.  
  97. static char rno_xhdi,try_xhdi;
  98. static char try_lrecno,rno_lrecno;
  99. static char try_plrecno,rno_plrecno;
  100.  
  101. char is_icd =-1 ;
  102. unsigned char *cache_icd;
  103.  
  104. int get_hddinf(drive,hdinf,flag)
  105. int drive;
  106. struct hdinfo *hdinf;
  107. char flag;
  108. {
  109.     long ret;
  110. #ifdef NEED_SUPER
  111.     long tstack;
  112.     tstack=Super(0l);
  113.     if(!((*(long *)0x4c2) & (1l<<drive))) return 4;
  114. #endif
  115.     ret = _get_hddinf(drive,hdinf,flag);
  116. #ifdef NEED_SUPER
  117.     Super(tstack);
  118. #endif
  119.     return ret;
  120. }
  121.  
  122. int _get_hddinf(drive,hdinf,flag)
  123. int drive;
  124. struct hdinfo *hdinf; 
  125. char flag;
  126. {
  127.     _BPB *bpb;
  128.  
  129.     hdinf->major=drive;    /* May get overwritten later */
  130.  
  131.     hdinf->drive=drive;
  132.  
  133.     init_icd();
  134.  
  135.     bpb=GETBPB(drive); 
  136.     if( flag ) bpb=0;
  137.  
  138.  
  139.     /* Step 1: if bpb OK and sector size 512 bytes or 1K we may get away
  140.      * with normal Rwabs.
  141.      */
  142.  
  143.     if( !bpb || (bpb->recsiz!=512 && bpb->recsiz!=1024) )
  144.     {
  145.         long tsecsiz;
  146.         char mpid[4];
  147.  
  148.         /* OK can't use normal Rwabs: try XHDI or pun_info */
  149.  
  150.         /* Bypass this rubbish for floppies */
  151.         if(drive < 2 ) return 1;
  152.  
  153.         /* Try and get info from pun_inf structure */
  154.         if( no_xhdi() )
  155.         {
  156.             struct pun_info *pinf;
  157.             if(drive >= MAXUNITS) return 2;
  158.             if(!(*(long *)0x516)) return 3;
  159.             pinf=PUN_PTR;
  160.             if(!pinf || (PUN_VALID & pinf->pun[drive]) ) return 4;
  161.             hdinf->scsiz = 1;
  162.  
  163.             if(is_icd)
  164. #ifdef NO_ICD_PHYS
  165.                 return 5;
  166. #else
  167.             {
  168.                 if(is_icd==2) return 13;
  169.                 hdinf->start = pinf->partition_start[drive+4];
  170.             }
  171. #endif
  172.             else hdinf->start = pinf->partition_start[drive];
  173.  
  174.             if(!hdinf->start) return 12;
  175.  
  176.             hdinf->size = 0;
  177.             hdinf->minor = pinf->pun[drive];
  178.             if(is_icd) hdinf->major=drive;
  179.             else hdinf->major = (hdinf->minor & PUN_DEV) +2;
  180.             hdinf->rwmode = RW_PHYS;
  181.             /* We want to access at least first few sectors */
  182.             if(hdinf->start > 0xfff0)
  183.             {
  184.                 if(no_plrecno(hdinf->major)) return 6;
  185.                 else hdinf->rwmode |= RW_LRECNO;
  186.             }
  187.             return 0;
  188.         }
  189.  
  190.         hdinf->rwmode = RW_XHDI | RW_LRECNO;
  191.  
  192.         /* Hmmmm Getbpb failed or bad secsize: see what XHDI can do */
  193.  
  194.         if( XHInqDev2(drive,&hdinf->major,&hdinf->minor,&hdinf->start,
  195.                               0,&hdinf->size,mpid) )
  196.         {
  197.             if(!bpb && !flag ) return 7;
  198.             if( XHInqDev(drive,&hdinf->major,&hdinf->minor,
  199.                             &hdinf->start,0) ) return 8;
  200.             hdinf->size=0;
  201.         }
  202.         else if(!bpb && strcmp(mpid,"RAW") && strcmp(mpid,"MIX")
  203.                && strcmp(mpid,"BGM") && strcmp(mpid,"GEM") ) return 9;
  204.  
  205.         /* Get physical sector size */
  206.         if( XHInqTarget(hdinf->major,hdinf->minor,&tsecsiz,0,0) )
  207.                                       return 10;
  208.  
  209.         if(tsecsiz==512) hdinf->scsiz=1;
  210.         else 
  211.         {
  212.             if(tsecsiz==1024) hdinf->scsiz=0;
  213.             else return 11;
  214.         }
  215.         return 0;
  216.     }
  217.     if(bpb->recsiz==512) hdinf->scsiz=1;
  218.     else hdinf->scsiz=0;
  219.     hdinf->size=0;
  220.     hdinf->rwmode = RW_NORMAL;
  221.     return 0;
  222. }
  223.  
  224. /* Special kludge for icd software. This software accesses far too many sectors
  225.  * when physical mode I/O is attempted on sectors bigger than 0xffff with the
  226.  * cache on. What we do
  227.  * is to:
  228.  * 1. Test for ICD software.
  229.  * 2. Set a pointer to the 'cache flag'.
  230.  * Return values:
  231.  * 0 Non ICD software or PUN_INFO problem.
  232.  * 1 Probably non ICD host adaptor used with ICD software.
  233.  * 2 ICD software doesn't have a 'cache flag' (probably too old).
  234.  * 3 Probably kludgable (OK).
  235.  * Only '2' is fatal.
  236.  */
  237.  
  238.  
  239. int init_icd()
  240. {
  241.     char *icd_magic;    
  242.     if(is_icd!=-1) return is_icd;
  243.     if(!*((long *)0x516)) return is_icd=0;
  244.     icd_magic=((char *)PUN_PTR)-6;
  245.     if(strncmp(icd_magic,"ICDB",4)) return is_icd=0;
  246.     else
  247.     {
  248.         char *icdh_magic;
  249.         if( icd_magic[5] < 0x50 ) return is_icd=2;
  250.         icdh_magic=*((char ** )(icd_magic-4));
  251.         if(strncmp(icdh_magic,"ICDH",4)) return is_icd=1;
  252.         if( icdh_magic[4] < 0x50 ) return is_icd=2;
  253.         cache_icd = (unsigned char *)(icdh_magic+6);
  254.         return is_icd=3;
  255.     }
  256. }
  257.  
  258. /* This function is called after get_hddinf and is used to finalise the
  259.  * accessibility of a partition. The 'size' parameter is the size of the
  260.  * partition in K; this info will typically come from the super block of
  261.  * a filesystem. 
  262.  * Return values:
  263.  * 0    OK
  264.  * 1    Malloc failure.
  265.  * 2    Can't access last block.
  266.  * 3    Physical lrecno error.
  267.  */
  268.  
  269. int set_lrecno(hdinf,size)
  270. struct hdinfo *hdinf;
  271. long size;
  272. {
  273.     long tsize;
  274.     tsize=size;
  275.     if(hdinf->scsiz) tsize <<=1;
  276.     if( ( (hdinf->rwmode & RW_MODE) == RW_XHDI) && hdinf->size
  277.                               && (hdinf->size < tsize) )
  278.     {
  279.         DWARN("Filesystem size bigger than partition size!",
  280.                                 hdinf->drive);
  281.     }
  282.     else hdinf->size = tsize;
  283.  
  284.     hdinf->rwmode |= RW_CHECK;
  285.  
  286.     if(hdinf->rwmode & RW_LRECNO) return 0;
  287.  
  288.     switch(hdinf->rwmode & RW_MODE)
  289.     {
  290.         case RW_NORMAL:
  291.         if(tsize < 0xffff)
  292.         {
  293.             char *tmp_buf;
  294.             tmp_buf=Kmalloc(1024);
  295.             if(!tmp_buf) return 14;
  296.             /* Try to read last block */
  297.             if(!block_rwabs(2,tmp_buf,1,size-1,hdinf)) 
  298.             {
  299.                 Kfree(tmp_buf);
  300.                 return 0;
  301.             }
  302.             Kfree(tmp_buf);
  303. #ifndef BYPASS_LOGICAL
  304.             return 15;
  305. #endif
  306.         }
  307.  
  308.         if( tsize < 0xffff || no_lrecno(hdinf->major) )
  309.         {
  310.         /* Bad lrecno or access error, try physical mode access */
  311.             int drive,err;
  312.             drive = hdinf->major;
  313.             if( (err=get_hddinf(drive,hdinf,1)) ) return err;
  314.             else return (set_lrecno(hdinf,size));
  315.         }
  316.         else hdinf->rwmode |= RW_LRECNO;
  317.         return 0;
  318.  
  319.         case RW_PHYS:
  320.         if(tsize+hdinf->start >= 0xfffe)
  321.         {
  322.             if(no_plrecno(hdinf->major)) return 1;
  323.             hdinf->size = tsize;
  324.             hdinf->rwmode |= RW_LRECNO;
  325.         }
  326.         return 0;
  327.     }
  328.  
  329.     return 1;    /* This can't happen */
  330. }
  331.  
  332. /* Test for 'lrecno' parameter on drive 'drive': mode' is RWABS mode to use 
  333.  * (2=logical,10=physical).
  334.  * Return values:
  335.  * 0 OK
  336.  * 1 Read error.
  337.  * 2 No lrecno recognised.
  338.  * 3 Error reading large sector number (possibly OK if partition too small).
  339.  * 4 Wraparound bug present.
  340.  * 5 Allocation error.
  341.  */
  342.  
  343. int test_lrecno(drive,mode)
  344. int drive;
  345. int mode;
  346. {
  347.     char *block_buf1,*block_buf2;
  348.     int size;
  349.     _BPB *bpb;
  350.     bpb=Getbpb(drive);
  351.     if( (mode & 8) || !bpb ) size=1024;
  352.     else size=bpb->recsiz;
  353.  
  354.     block_buf1=Kmalloc(size<<1);
  355.     block_buf2=block_buf1+size;
  356.     bzero(block_buf1,size<<1);
  357.  
  358.     if(!block_buf1) return 5;
  359.  
  360.     /* read in boot sector */
  361.     if(RWABS(mode,block_buf1,1,0,drive)) 
  362.     {
  363.         Kfree(block_buf1);
  364.         return 1;
  365.     }
  366.  
  367.     /* read it in with lrecno */    
  368.     if( XRWABS(mode,block_buf2,1,-1,drive,0l) ) 
  369.     {
  370.         Kfree(block_buf1);
  371.         return 2;
  372.     }
  373.  
  374.     /* Compare the two */
  375.     if(bcmp(block_buf1,block_buf2,size))
  376.     {
  377.         Kfree(block_buf1);
  378.         return 2;
  379.     }
  380.  
  381.     /* read in next sector with lrecno */
  382.     if(XRWABS(mode,block_buf2,1,-1,drive,1l))
  383.     {
  384.         Kfree(block_buf1);
  385.         return 1;
  386.     }
  387.  
  388.     /* compare the two */
  389.     if(!bcmp(block_buf1,block_buf2,size))
  390.     {
  391.         Kfree(block_buf1);
  392.         return 2;
  393.     }
  394.  
  395.     /* Check for lrecno bug, this causes the upper word of a long sector
  396.      * number to be ignored. Read in sector 0 and 0x10000, if the bug is
  397.      * present then these will be identical.
  398.      */
  399.     bzero(block_buf2,size);
  400.  
  401.     if(XRWABS(mode,block_buf2,1,-1,drive,0x10000l))
  402.     {
  403.         Kfree(block_buf1);
  404.         return 3;
  405.     }
  406.     else if(!bcmp(block_buf1,block_buf2,size))
  407.     {
  408.         Kfree(block_buf1);
  409.         return 4;
  410.     }
  411.  
  412.     Kfree(block_buf1);
  413.     return 0;
  414.  
  415. }
  416.  
  417. int no_lrecno(drv)
  418. int drv;
  419. {
  420.     if( !try_lrecno )
  421.     {
  422.         rno_lrecno = test_lrecno(drv,2) ;
  423.         try_lrecno = 1;
  424.     }
  425.     return rno_lrecno;
  426. }
  427.  
  428. int no_plrecno(drv)
  429. int drv;
  430. {
  431. #ifdef NO_ICD_PHYS
  432.     if(is_icd) return 1;
  433. #endif
  434.  
  435.     if( !try_plrecno ) 
  436.     {
  437.         unsigned char cache_tmp=0;
  438.         try_plrecno = 1;
  439.         if(cache_icd)
  440.         {
  441.             cache_tmp=*cache_icd;
  442.             *cache_icd=0;
  443.         }
  444.         rno_plrecno = test_lrecno(drv,10) ;
  445.         if(cache_icd) *cache_icd=cache_tmp;
  446.     }
  447.     return rno_plrecno;
  448. }
  449.  
  450. int no_xhdi()
  451. {
  452.     if( !try_xhdi ) 
  453.     {
  454.         if( !XHGetVersion() ) rno_xhdi=1;
  455.         try_xhdi=1;
  456.     }
  457.     return rno_xhdi;
  458. }
  459.  
  460. /* 
  461.  * This is (finally!) the I/O function hdinf uses. It reads/writes in 1K chunks
  462.  * and calls the relevant functions according to the hdinf structure.
  463.  */
  464.  
  465. long block_rwabs(rw,buf,num,recno,hdinf)
  466. int rw;
  467. void *buf;
  468. unsigned num;
  469. long recno;
  470. struct hdinfo *hdinf;
  471. {
  472.     unsigned char cache_tmp=0;
  473.     long ret;
  474.  
  475.     if( hdinf->scsiz )
  476.     {
  477.         recno <<=1;
  478.         num <<=1;
  479.     }
  480.  
  481.     if( (hdinf->rwmode & RW_CHECK) && (recno+num > hdinf->size) )
  482.     {
  483.         DWARN("Attempted access outside partition",hdinf->drive);
  484.         return -1;
  485.     }
  486.  
  487.     switch(hdinf->rwmode & (RW_MODE|RW_LRECNO))
  488.     {
  489.         case RW_NORMAL:
  490.         return RWABS(rw,buf,num,(unsigned)recno,hdinf->major);
  491.  
  492.         case RW_NORMAL | RW_LRECNO:
  493.         return XRWABS(rw,buf,num,-1,hdinf->major,recno);
  494.  
  495.         case RW_PHYS:
  496.         if(cache_icd)
  497.         {
  498.             cache_tmp=*cache_icd;
  499.             *cache_icd=0;
  500.         }
  501.         ret = RWABS(rw | 8,buf,num,(unsigned)(recno+hdinf->start),
  502.                                   hdinf->major);
  503.         if(cache_icd) *cache_icd=cache_tmp;
  504.         return ret;
  505.  
  506.         case RW_PHYS | RW_LRECNO:
  507.         if(cache_icd)
  508.         {
  509.             cache_tmp=*cache_icd;
  510.             *cache_icd=0;
  511.         }
  512.         ret = XRWABS(rw | 8,buf,num,-1,hdinf->major,
  513.                                 recno+hdinf->start);
  514.         if(cache_icd) *cache_icd=cache_tmp;
  515.         return ret;
  516.  
  517.         case RW_XHDI | RW_LRECNO:
  518.         return XHReadWrite(hdinf->major,hdinf->minor,rw,
  519.                             recno+hdinf->start,num,buf);
  520.     }
  521.     return 1;    /* This can't happen ! */
  522. }
  523.  
  524. #ifndef SUPER_CALL
  525.  
  526. /* Determine partition size from drive info. Check Rwabs errors ... it should
  527.  * give an error for an attempt to read past the end of a partition. From then
  528.  * on use a log search to find partition size.
  529.  * If this seems awkward you are right ... certain disk software doesn't enter
  530.  * the correct size in the boot sector (to correct a TOS bug).
  531.  */
  532.  
  533. char *size_err[] = 
  534. {
  535. "OK",
  536. "Getbpb failed",
  537. "Allocation error",
  538. "Driver software incompatible"
  539. };
  540.  
  541. int get_size(drive,size)
  542. int drive;
  543. long *size;
  544. {
  545.     char *buf;
  546.     _BPB *bpb;
  547.     unsigned secnum,bitnum;
  548.     if(! (bpb=GETBPB(drive)) ) return 1; /* Bad bpb */
  549.     if(! (buf=Kmalloc(bpb->recsiz)) ) return 2; /* alloc error */
  550.     
  551.     if(!RWABS(2,buf,1,0xfffe,drive))
  552.     {
  553.         Kfree(buf);
  554.         return 3;    /* Software doesn't return errors */
  555.     }
  556.  
  557.     bitnum=0x8000;
  558.     secnum=0;
  559.  
  560.     do
  561.     {
  562.         secnum |= bitnum;
  563.         if( RWABS(2,buf,1,secnum,drive) ) secnum &=~bitnum;
  564.         bitnum >>=1 ;
  565.     } while(bitnum);
  566.  
  567.     secnum++;
  568.  
  569.     *size=(((long)secnum) * bpb->recsiz)>>10;
  570.     Kfree(buf);
  571.     return 0;
  572.  
  573. }
  574.  
  575. #endif
  576.  
  577.  
  578.  
  579.