home *** CD-ROM | disk | FTP | other *** search
- /*
- * BSL.C
- *
- * Functions to manipulate the Bad Sector List.
- *
- * 25-Nov-87 ml. Started this mess.
- * 04-Dec-87 ml. Hmmm, looks OK.
- * 11-Dec-87 ml. Added bsl2fat().
- * 14-Dec-87 ml. Structure of BSL is changed (_again_!).
- * Now, first entry in BSL contains number VENDOR
- * entries. First byte of 2nd entry is the checksum
- * byte, while 2nd and 3rd bytes are reserved for
- * future use.
- * 14-Sep-89 ml. Uses Rwabs() instead of hread() and hwrite().
- * Will handle SCSI as well as ACSI drives.
- * 21-Sep-89 ml. Modified to work with big sectors for big
- * partitions.
- *
- */
-
- #include <obdefs.h>
- #include <osbind.h>
- #include "fhdx.h"
- #include "define.h"
- #include "part.h"
- #include "bsl.h"
- #include "addr.h"
- #include "lrwabs.h"
-
- /* Globals */
- char *bsl; /* bad sector list */
- long bslsiz; /* num sectors BSL occupies */
-
- extern SECTOR *badbuf;
-
- /*
- * Get size of the Bad Sector List (in sectors)
- * Input:
- * pdev - physical unit BSL belongs to.
- * Return:
- * number of sectors BSL occupies.
- */
- long
- gbslsiz(pdev)
- int pdev; /* physical device number */
- {
- char bs[512]; /* boot sector image */
-
- if (getroot(pdev, bs) == ERROR)
- return ((long)err(rootread));
-
- if (((RSECT *)(bs + 0x200 - sizeof(RSECT)))->bsl_st != STBSL) {
- form_alert(1, "[1][No BSL recorded in root sector!][ OK ]");
- return 0L;
- }
-
- return(((RSECT *)(bs + 0x200 - sizeof(RSECT)))->bsl_cnt);
- }
-
-
- /*
- * Set BSL parameters (starting sector and size of BSL) into
- * root sector image.
- * Input:
- * image - root sector image.
- */
- sbslparm(image)
- char *image;
- {
- ((RSECT *)(image + 0x200 - sizeof(RSECT)))->bsl_st = STBSL;
- ((RSECT *)(image + 0x200 - sizeof(RSECT)))->bsl_cnt = bslsiz;
- }
-
-
- /*
- * Create a BSL in memory.
- * Input:
- * pdev - physical unit BSL will belong to.
- * type - kind of BSL to be created. NEW or EXPAND.
- * nents - number of VENDOR entries BSL should hold.
- * Output:
- * bsl - pointer to the BSL. (in bsl.h)
- * Return:
- * OK - everything is fine.
- * ERROR - anything is wrong.
- * Comment:
- * "NEW" means to create a totally new BSL.
- * "EXPAND" means to expand an existing BSL.
- */
- creabsl(pdev, type, nents)
- int pdev; /* physical unit number */
- int type; /* kind of BSL to be created */
- long nents; /* num VENDOR entries in BSL */
- {
- BYTE *newbsl; /* BSL just created */
- long l, size; /* l - index into BSL; size - size of BSL in bytes */
- long start; /* where to start initializing entries to zeroes */
- long nument();
-
- if (type == NEW) {
- if (form_alert(1, "[1][Create a new BSL?][ Yes | No ]") == 2)
- return ERROR;
- }
-
- if (nents == 0) { /* no VENDOR entries specified */
- size = 512L; /* default size of BSL to 1 sector */
- } else { /* num VENDOR entries is specified */
- /*------------------------------------------------------*/
- /* Calculate length of BSL in bytes. */
- /* Have to add space for reserved entries and USER list */
- /* (note: (+1) to round up) */
- /*------------------------------------------------------*/
- size = ((nents + RENT + WARNBADSECTS)/EPS + 1) * 512L;
- }
-
- /* allocate enough memory for new BSL */
- if ((newbsl = (BYTE *)mymalloc((int)size)) <= 0)
- return err(nomemory);
-
- if (type == NEW) { /* a new BSL */
- start = 0; /* start at 0th entry, i.e. init whole BSL to 0s */
- }
- else { /* expand the BSL */
- /* start init to 0s after VENDOR list */
- start = (nument(VENDOR) + RENT) * BPE;
-
- /* copy original BSL into this expanded memory */
- for (l = 0; l < start; l++)
- newbsl[l] = bsl[l];
- }
-
- /* free up old BSL */
- if (bsl > 0L) free(bsl);
- bsl = newbsl;
-
- /* init BSL to zeroes beginning at 'start'th entry */
- for (l = start; l < size; l++)
- bsl[l] = 0;
-
- /* install BSL info */
- bslsiz = size/512; /* current num sectors BSL occupies */
- put3bytes(bsl, nents); /* num VENDOR entries */
- mkmagic(); /* make the BSL checks sum to BSLMAGIC byte-wise */
-
- return OK;
- }
-
-
- /*
- * Read the BSL into memory.
- * Input:
- * pdev - physical unit that contains the BSL.
- * Output:
- * bsl - pointer to the BSL. (in bsl.h)
- * Return:
- * OK - everything is fine.
- * INVALID - BSL doesn't checksum correctly.
- * ERROR - can't read BSL.
- */
- rdbsl(pdev)
- int pdev; /* physical unit to read from */
- {
- int ret;
- extern HINFO hinfo;
-
- rdagain:
- if ((ret = Lrwabs(PHYSREAD, bsl, (WORD)bslsiz, (SECTOR)STBSL, pdev+2))
- == ERROR) {
- if (form_alert(1, "[1][Read from BSL timed out!][ Retry | Quit ]")
- == 1) {
- goto rdagain;
- }
- return ERROR;
- } else if (ret > 0) {
- ret = err(bslread);
- errcode(pdev);
- return ERROR;
- } else {
- if ((ret = sumbsl()) == INVALID) { /* if BSL is INVALID */
- err(cruptbsl);
- dsplybsl(pdev, (UWORD)hinfo.hi_dhc, (UWORD)hinfo.hi_spt);
- return INVALID;
- }
- return OK;
- }
- }
-
-
- /*
- * Count number of entries in the requested portion of BSL.
- * Input:
- * portion - portion of BSL. MEDIA, VENDOR, USER or UNUSED.
- * Return:
- * Number of entries of the requested portion.
- * Comments:
- * There are 3 bytes per entry (BPE), and the first 2 entries
- * are reserved (RENT) for BSL info.
- */
- long
- nument(portion)
- int portion; /* portion of BSL to be counted */
- {
- long vdr, usr; /* num ent in VENDOR list, num ent in USER list */
- long nbytes, offset; /* BSL's len in bytes, index into BSL */
- long get3bytes();
-
- /* 2nd entry in BSL contains num entries in VENDOR list */
- vdr = get3bytes(bsl);
-
- if (portion == VENDOR) return (vdr);
-
- nbytes = bslsiz*512; /* num bytes in BSL */
-
- /* num bytes available for valid entries */
- /* (need this because nbytes may not be divisible by BPE) */
- nbytes -= (nbytes % BPE);
-
- /* find out num entries in USER list */
- usr = 0;
- for (offset = (RENT+vdr)*BPE; /* index into beginning of USER list */
- (offset < nbytes) /* while not at end of BSL */
- && get3bytes(bsl+offset); /* and it's a used entry */
- offset += BPE) /* increment index */
- usr++; /* increment num entries for USER list */
-
- if (portion == USER)
- return (usr); /* num entries in USER list */
-
- if (portion == MEDIA)
- return (vdr+usr); /* num entries in MEDIA list */
-
- /* portion == UNUSED */
- return ((nbytes/BPE)-RENT-vdr-usr);
- }
-
-
- /*
- * Write the BSL into the disk.
- * Input:
- * pdev - physical unit number BSL belongs to.
- * bsl - pointer to buffer containing the BSL. (in bsl.h)
- * Return:
- * OK - everything is fine.
- * ERROR - can't write BSL.
- */
- wrbsl(pdev)
- int pdev; /* physical unit number */
- {
- extern HINFO hinfo;
- int ret;
-
- wrtagain:
- if ((ret = Lrwabs(PHYSWRT, bsl, (WORD)bslsiz, (SECTOR)STBSL, pdev+2))
- == ERROR) {
- if (form_alert(1, "[1][Write to BSL timed out!][ Retry | Quit ]")
- == 1) {
- goto wrtagain;
- }
- return ERROR;
- } else if (ret > 0) {
- err(bslwrite);
- errcode(pdev);
- dsplybsl(pdev, (UWORD)hinfo.hi_dhc, (UWORD)hinfo.hi_spt);
- return ERROR;
- }
-
- return OK;
- }
-
-
- /*
- * Sort the BSL in memory in ascending order.
- * Input:
- * entries - number of used entries in BSL
- * bsl - pointer to the BSL. (in bsl.h)
- * Output:
- * a sorted bsl.
- * Algorithm:
- * Bubble sort.
- * Comments:
- * The reserved entries won't be sorted.
- */
- sortbsl(entries)
- long entries; /* num entries in BSL */
- {
- long i, e1, e2;
- long start; /* beginning byte of entries in BSL */
- long end; /* tail byte of BSL */
- int change; /* signal if changes have been made in current pass */
- long get3bytes();
-
- if (entries == 0L || entries == 1L) /* BSL doesn't need to be sorted */
- return;
-
- change = 1; /* assume list is not in order */
- start = RENT*BPE; /* beginning of entries in BSL */
- end = entries * BPE;
- while (1) {
- if (change == 0) /* if no changes made, DONE --> HOME */
- return;
-
- change = 0; /* assume list is in order */
- for (i = start; i <= end; i += BPE) {
- e1 = get3bytes(bsl+i);
- e2 = get3bytes(bsl+i+BPE);
- if (e1 > e2) { /* switch if out of order */
- put3bytes(bsl+i, e2);
- put3bytes(bsl+i+BPE, e1);
- change = 1;
- }
- }
- end -= BPE;
- }
- }
-
-
- /*
- * Search through a sorted BSL for a given sector number.
- * Input:
- * sect - sector number searching for.
- * entries - number of used entries in the BSL.
- * Return:
- * YES - if given sector is found.
- * NO - if given sector is not found.
- * Algorithm:
- * Binary Search.
- */
- srchbsl(sect, entries)
- SECTOR sect; /* sector searching for */
- long entries; /* num used entries in BSL */
- {
- long start, mid, end; /* start, middle and end indices into list */
- SECTOR temp; /* sector number in middle of list */
- long get3bytes();
-
- start = RENT; /* start after reserved entries */
- end = entries+RENT-1; /* end of BSL */
-
- while (1) {
- mid = (start + end) / 2; /* middle entry in list */
- temp = get3bytes(bsl+(mid*BPE)); /* sector num at mid entry */
-
- if (sect == temp) /* given sector == sector at mid entry */
- return YES; /* given sector found in list */
- else if (sect < temp) /* given sector < sector at mid entry */
- end = mid - 1; /* limit search to smaller sector num */
- else /* given sector > sector at mid entry */
- start = mid + 1; /* limit search to larger sector num */
-
- if (end < start) /* list is exhausted */
- return NO; /* can't find given sector */
- }
- }
-
-
- /*
- * Checksum (byte-wise) the BSL.
- * Input:
- * bsl - pointer to the BSL. (in bsl.h)
- * Return:
- * OK - BSL checksum to BSLMAGIC (0xa5).
- * INVALID - BSL does not checksum to BSLMAGIC.
- */
- sumbsl()
- {
- register BYTE sum; /* byte-wise sum of BSL */
- long i; /* index into BSL */
- long length; /* length of BSL in bytes */
-
- length = bslsiz*512; /* length of entire BSL */
- sum = 0; /* initialize the sum */
-
- /* Sum up values in the BSL by byte */
- for (i = 0; i < length; i++) {
- sum += bsl[i];
- }
- if (sum != BSLMAGIC) { /* doesn't checksum correctly */
- return INVALID;
- }
- return OK; /* checksum correctly */
- }
-
-
- /*
- * Make the BSL checks sum to BSLMAGIC.
- */
- mkmagic()
- {
- register BYTE diff; /* difference to make BSL checks sum correctly */
- long i; /* index into BSL */
- long len; /* length of BSL in bytes */
-
- len = bslsiz*512; /* length of entire BSl */
- diff = BSLMAGIC; /* initialize the difference */
-
- /* find out what number would make BSL checks sum to BSLMAGIC */
- for (i = 0; i < len; i++) {
- diff -= bsl[i];
- }
-
- /* add that difference to checksum byte (1st byte of 2nd entry of BSL) */
- bsl[BPE] += diff;
- }
-
-
- /*
- * Add bad sectors found to the Bad Sector List.
- * Input:
- * pdev - physical unit BSL belongs to.
- * portion - portion of BSL to add to. VENDOR or USER.
- * nbad - number of bad sectors to be added.
- * Return:
- * nadd - number of new bad sectors added to the BSL.
- * USRFULL - user part of the BSL is filled up.
- * NOMEM - not enough memory for add buffer or BSL.
- * ERROR - something is wrong.
- * Comment:
- * The entry will be added only if it is not already on the
- * bad sector list. Binary search is performed to guarantee this.
- * If the VENDOR list is full, this routine will take care
- * of the expansion of the list also.
- */
- addbsl(pdev, portion, nbad)
- int pdev; /* physical unit number */
- int portion; /* portion of BSL */
- int nbad; /* num of bad sectors to be added */
- {
- long entries; /* num entries to be retained in BSL */
- long empty; /* num empty slots available for adding entries */
- long end; /* address of end of BSL */
- int i, toadd; /* index to badbuf, num of bad sectors to be added */
- int ret; /* return code */
- SECTOR *addbuf; /* bad sectors to be added to BSL */
- long nument();
-
- /* Allocate memory for sector numbers of bad sectors to be added */
- if ((addbuf = (SECTOR *)mymalloc(nbad*4)) <= 0) {
- err(nomemory);
- return NOMEM;
- }
-
- if (portion == VENDOR) { /* adding to VENDOR list */
- entries = nument(VENDOR); /* only keep the VENDOR list */
- empty = 0; /* there's no unused slot for VENDOR ent */
- } else { /* adding to USER list */
- entries = nument(MEDIA); /* keep entire list */
- empty = nument(UNUSED); /* slots left unused */
- }
- sortbsl(entries); /* sort BSL in ascending order */
- toadd = 0; /* none is to be added to BSL yet */
-
- /* For all bad sectors found, search for them in the current BSL.
- Add them to the list only when they are not already recorded. */
- if (entries) { /* only search if BSL is not empty */
- for (i = 0; i < nbad; i++) {
- if (srchbsl(*(badbuf+i), entries) == NO) {
- addbuf[toadd] = *(badbuf+i);
- toadd++;
- }
- }
- } else { /* add in all bad sectors found */
- for (i = 0; i < nbad; i++)
- addbuf[i] = *(badbuf+i);
- toadd = nbad;
- }
-
- /* All bad sectors found have been recorded. Nothing is added to BSL */
- if (toadd == 0) {
- if (portion == USER && (ret = rdbsl(pdev)) != OK) {
- if (ret == INVALID)
- err(cruptbsl);
- goto togo;
- }
- ret = toadd;
- goto togo;
- }
-
- /*------------------------------------------------------------------*/
- /* Check if there are enough empty slots for new entries. If not, */
- /* determine what kind of entries we are adding, VENDOR or USER. */
- /* Expand the BSL if we are adding to VENDOR list. Give warning */
- /* if we are adding to USER list. */
- /*------------------------------------------------------------------*/
- if (toadd > empty) {
- if (portion == VENDOR) { /* this only happens at format time */
- /* expanded BSL should hold (entries + toadd) VENDOR entries */
- if ((ret = creabsl(pdev, EXPAND, entries+toadd)) != OK)
- goto togo;
- } else { /* We are adding to USER list */
- err(manybad);
- toadd = empty; /* num ent to add = empty slots available */
- }
- }
-
- /* Read in orig unsorted list if adding USER entries */
- if (portion == USER) {
- if ((ret = rdbsl(pdev)) != OK) {
- if (ret == INVALID)
- err(cruptbsl);
- goto togo;
- }
- }
-
- /* Append new entries to end of BSL */
- end = bsl + (RENT + entries)*BPE; /* end of BSL */
- for (i = 0; i < toadd; i++) {
- put3bytes((end + i*BPE), addbuf[i]);
- }
-
- /* make BSL checks sum to magic number */
- mkmagic();
-
- if (portion == USER && toadd == empty) {
- ret = USRFULL;
- goto togo;
- }
-
- ret = toadd;
- togo:
- if (addbuf > 0L) free(addbuf);
- return(ret);
- }
-
-
- /*
- * Mark bad sectors from the BSL to FATs of a partition.
- * Input:
- * ldev - logical device the FATs belong to.
- * fat0 - logical sector number of where FAT 0 starts.
- * fatsiz - size of FAT in # log sectors.
- * data - logical sector number of where data clusters start.
- * portion - part of BSL to mark from.
- * sratio -
- */
- bsl2fat(ldev, fat0, fatsiz, data, portion, sratio)
- int ldev; /* logical device number */
- SECTOR fat0; /* starting sector number (logical) of FAT 0 */
- WORD fatsiz; /* FAT size in # log sectors */
- SECTOR data; /* starting sector number (logical) of data clusters */
- int portion; /* part of BSL to mark from, VENDOR or MEDIA */
- WORD sratio; /* log sector size : phys sector size */
- {
- long nument(), entries; /* num entries in the list to be considered */
- long i, end; /* indices to the list to be considered */
- SECTOR badsect; /* a bad sector in the list */
- SECTOR pstart; /* phys sector num where partition starts */
- SECTOR pdata; /* phys sector num where data block starts */
- SECTOR pend; /* phys sector num where data block ends */
- extern SECTOR logstart(), logend();
- int nbad;
-
- pstart = logstart(ldev); /* find partition phys start sector */
- pdata = pstart + (data*sratio); /* find data phys start sector */
- pend = logend(ldev); /* find where data block ends */
- entries = nument(portion); /* find num entries in given portion */
- sortbsl(entries); /* sort given portion of BSL */
-
- end = (RENT + entries) * BPE;
- nbad = 0;
-
- /* Store vendor bad sectors of the logical device in badbuf */
- for (i = BPE*RENT; i < end; i += BPE) {
- if ((badsect = get3bytes(bsl+i)) > pend)
- break;
-
- if (badsect >= pdata) {
- *(badbuf+nbad) = badsect;
- nbad++;
-
- /* if badbuf overflows, mark what we have so far in the FAT */
- if (nbad == WARNBADSECTS) {
- if (fixbadcls(ldev, fat0, fatsiz, data, nbad, sratio) != OK) {
- return ERROR;
- }
- nbad = 0; /* reinit num bad sectors in partition to 0 */
- }
- }
- }
-
- /* Bad sectors in partition not marked in FAT yet */
- if (nbad) {
- if (fixbadcls(ldev, fat0, fatsiz, data, nbad, sratio) != OK) {
- return ERROR;
- }
- }
-
- return OK;
- }
-
-
- /*
- * Count number of bad sectors on a logical drive recorded in BSL.
- * Input:
- * ldev - logical drive to be considered.
- * Return:
- * nbad - number of bad sectors found.
- */
- long
- cntbad(ldev)
- int ldev; /* logical drive number */
- {
- SECTOR pstart, pend; /* phys starting and ending block of ldev */
- extern SECTOR logstart(), logend();
- long nbad=0L; /* num bad sectors on ldev */
- long entries, nument(), bslend;
- long curr, get3bytes();
- int done, i;
-
- pstart = logstart(ldev); /* starting block # of partition */
- pend = logend(ldev); /* ending block # of partition */
- entries = nument(MEDIA); /* num entries in BSL */
- sortbsl(entries); /* sort BSL */
-
- done = 0;
- bslend = (RENT+entries) * BPE;
- for (i = RENT*BPE; (!done) && (i < bslend); i += BPE) {
- curr = get3bytes(bsl+i); /* get next entry in BSL */
- if (curr < pstart) /* not within logical drive's range yet */
- continue;
- if (curr <= pend) /* within logical drive's range */
- nbad++;
- else done = 1; /* pass logical drive's range */
- }
- return (nbad);
- }
-
-
- /*
- * Put a word into memory in 68000 format.
- * Input:
- * p - pointer to memory.
- * i - word to be put.
- */
- putword(p, i)
- BYTE *p;
- unsigned int i;
- {
- *p = i >> 8;
- *(p+1) = i;
- }
-
-
- /*
- * Get a 68000 format word from memory.
- * Input:
- * p - pointer to memory.
- * Return:
- * i - word read from memory.
- */
- getword(p)
- BYTE *p;
- {
- unsigned int i;
-
- i = *p;
- i <<= 8;
- i |= *(p+1);
- return (i);
- }
-
-
- /*
- * Put 3 bytes (68000 format) into memory.
- * Input:
- * p - pointer to memory.
- * l - long which contains the 3 bytes at the low-bit end.
- */
- put3bytes(p, l)
- BYTE *p;
- long l;
- {
- *p = l >> 16;
- *(p+1) = l >> 8;
- *(p+2) = l;
- }
-
-
- /*
- * Get 3 bytes (68000 format) from memory.
- * Input:
- * p - pointer to memory.
- * Return:
- * l - a long which contains the 3 bytes read in last 3 bytes.
- */
- long
- get3bytes(p)
- BYTE *p;
- {
- long k=0x000000ff, l=0x000000ff;
-
- l &= *p; /* first byte */
- l <<= 16;
- k &= *(p+1); /* second byte */
- k <<= 8;
- l |= k;
- k = 0x000000ff;
- k &= *(p+2); /* third byte */
- l |= k;
- return (l);
- }
-