1: /*
   2:  * Copyright (c) 1982, 1986 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  *
   6:  *	@(#)hp.c	7.1 (Berkeley) 6/5/86
   7:  */
   8: 
   9: #ifdef HPDEBUG
  10: int hpdebug;
  11: #endif
  12: #ifdef HPBDEBUG
  13: int hpbdebug;
  14: #endif
  15: 
  16: #include "hp.h"
  17: #if NHP > 0
  18: /*
  19:  * HP disk driver for RP0x+RMxx+ML11
  20:  *
  21:  * TODO:
  22:  *	see if DCLR and/or RELEASE set attention status
  23:  */
  24: #include "../machine/pte.h"
  25: 
  26: #include "param.h"
  27: #include "systm.h"
  28: #include "dk.h"
  29: #include "buf.h"
  30: #include "conf.h"
  31: #include "dir.h"
  32: #include "user.h"
  33: #include "map.h"
  34: #include "../vax/mtpr.h"
  35: #include "vm.h"
  36: #include "cmap.h"
  37: #include "dkbad.h"
  38: #include "ioctl.h"
  39: #include "uio.h"
  40: #include "syslog.h"
  41: 
  42: #include "../vax/dkio.h"
  43: #include "mbareg.h"
  44: #include "mbavar.h"
  45: #include "hpreg.h"
  46: 
  47: /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
  48: struct  size {
  49:     daddr_t nblocks;
  50:     int cyloff;
  51: } rp06_sizes[8] = {
  52:     15884,  0,      /* A=cyl 0 thru 37 */
  53:     33440,  38,     /* B=cyl 38 thru 117 */
  54:     340670, 0,      /* C=cyl 0 thru 814 */
  55:     15884,  118,        /* D=cyl 118 thru 155 */
  56:     55936,  156,        /* E=cyl 156 thru 289 */
  57:     219384, 290,        /* F=cyl 290 thru 814 */
  58:     291280, 118,        /* G=cyl 118 thru 814 */
  59:     0,  0,
  60: }, rp05_sizes[8] = {
  61:     15884,  0,      /* A=cyl 0 thru 37 */
  62:     33440,  38,     /* B=cyl 38 thru 117 */
  63:     171798, 0,      /* C=cyl 0 thru 410 */
  64:     15884,  118,        /* D=cyl 118 thru 155 */
  65:     55936,  156,        /* E=cyl 156 thru 289 */
  66:     50512,  290,        /* F=cyl 290 thru 410 */
  67:     122408, 118,        /* G=cyl 118 thru 410 */
  68:     0,  0,
  69: }, rm03_sizes[8] = {
  70:     15884,  0,      /* A=cyl 0 thru 99 */
  71:     33440,  100,        /* B=cyl 100 thru 308 */
  72:     131680, 0,      /* C=cyl 0 thru 822 */
  73:     15884,  309,        /* D=cyl 309 thru 408 */
  74:     55936,  409,        /* E=cyl 409 thru 758 */
  75:     10144,  759,        /* F=cyl 759 thru 822 */
  76:     82144,  309,        /* G=cyl 309 thru 822 */
  77:     0,  0,
  78: }, rm05_sizes[8] = {
  79:     15884,  0,      /* A=cyl 0 thru 26 */
  80:     33440,  27,     /* B=cyl 27 thru 81 */
  81:     500384, 0,      /* C=cyl 0 thru 822 */
  82:     15884,  562,        /* D=cyl 562 thru 588 */
  83:     55936,  589,        /* E=cyl 589 thru 680 */
  84:     86240,  681,        /* F=cyl 681 thru 822 */
  85:     158592, 562,        /* G=cyl 562 thru 822 */
  86:     291346, 82,     /* H=cyl 82 thru 561 */
  87: }, rm80_sizes[8] = {
  88:     15884,  0,      /* A=cyl 0 thru 36 */
  89:     33440,  37,     /* B=cyl 37 thru 114 */
  90:     242606, 0,      /* C=cyl 0 thru 558 */
  91:     15884,  115,        /* D=cyl 115 thru 151 */
  92:     55936,  152,        /* E=cyl 152 thru 280 */
  93:     120559, 281,        /* F=cyl 281 thru 558 */
  94:     192603, 115,        /* G=cyl 115 thru 558 */
  95:     0,  0,
  96: }, rp07_sizes[8] = {
  97:     15884,  0,      /* A=cyl 0 thru 9 */
  98:     66880,  10,     /* B=cyl 10 thru 51 */
  99:     1008000, 0,     /* C=cyl 0 thru 629 */
 100:     15884,  235,        /* D=cyl 235 thru 244 */
 101:     307200, 245,        /* E=cyl 245 thru 436 */
 102:     308650, 437,        /* F=cyl 437 thru 629 */
 103:     631850, 235,        /* G=cyl 235 thru 629 */
 104:     291346, 52,     /* H=cyl 52 thru 234 */
 105: }, cdc9775_sizes[8] = {
 106:     15884,  0,      /* A=cyl 0 thru 12 */
 107:     66880,  13,     /* B=cyl 13 thru 65 */
 108:     1077760, 0,     /* C=cyl 0 thru 841 */
 109:     15884,  294,        /* D=cyl 294 thru 306 */
 110:     307200, 307,        /* E=cyl 307 thru 546 */
 111:     377440, 547,        /* F=cyl 547 thru 841 */
 112:     701280, 294,        /* G=cyl 294 thru 841 */
 113:     291346, 66,     /* H=cyl 66 thru 293 */
 114: }, cdc9730_sizes[8] = {
 115:     15884,  0,      /* A=cyl 0 thru 49 */
 116:     33440,  50,     /* B=cyl 50 thru 154 */
 117:     263360, 0,      /* C=cyl 0 thru 822 */
 118:     15884,  155,        /* D=cyl 155 thru 204 */
 119:     55936,  205,        /* E=cyl 205 thru 379 */
 120:     141664, 380,        /* F=cyl 380 thru 822 */
 121:     213664, 155,        /* G=cyl 155 thru 822 */
 122:     0,  0,
 123: }, capricorn_sizes[8] = {
 124:     15884,  0,      /* A=cyl 0 thru 31 */
 125:     33440,  32,     /* B=cyl 32 thru 97 */
 126:     524288, 0,      /* C=cyl 0 thru 1023 */
 127:     15884,  668,        /* D=cyl 668 thru 699 */
 128:     55936,  700,        /* E=cyl 700 thru 809 */
 129:     109472, 810,        /* F=cyl 810 thru 1023 */
 130:     182176, 668,        /* G=cyl 668 thru 1023 */
 131:     291346, 98,     /* H=cyl 98 thru 667 */
 132: }, eagle_sizes[8] = {
 133:     15884,  0,      /* A=cyl 0 thru 16 */
 134:     66880,  17,     /* B=cyl 17 thru 86 */
 135:     808320, 0,      /* C=cyl 0 thru 841 */
 136:     15884,  391,        /* D=cyl 391 thru 407 */
 137:     307200, 408,        /* E=cyl 408 thru 727 */
 138:     109296, 728,        /* F=cyl 728 thru 841 */
 139:     432816, 391,        /* G=cyl 391 thru 841 */
 140:     291346, 87,     /* H=cyl 87 thru 390 */
 141: }, ampex_sizes[8] = {
 142:     15884,  0,      /* A=cyl 0 thru 26 */
 143:     33440,  27,     /* B=cyl 27 thru 81 */
 144:     495520, 0,      /* C=cyl 0 thru 814 */
 145:     15884,  562,        /* D=cyl 562 thru 588 */
 146:     55936,  589,        /* E=cyl 589 thru 680 */
 147:     81312,  681,        /* F=cyl 681 thru 814 */
 148:     153664, 562,        /* G=cyl 562 thru 814 */
 149:     291346, 82,     /* H=cyl 82 thru 561 */
 150: }, fj2361_sizes[8] = {
 151:     15884,  0,      /* A=cyl 0 thru 12 */
 152:     66880,  13,     /* B=cyl 13 thru 65 */
 153:     1077760, 0,     /* C=cyl 0 thru 841 */
 154:     15884,  294,        /* D=cyl 294 thru 306 */
 155:     307200, 307,        /* E=cyl 307 thru 546 */
 156:     377408, 547,        /* F=cyl 547 thru 841 */
 157:     701248, 294,        /* G=cyl 294 thru 841 */
 158:     291346, 66,     /* H=cyl 66 thru 293 */
 159: };
 160: /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */
 161: 
 162: /*
 163:  * Table for converting Massbus drive types into
 164:  * indices into the partition tables.  Slots are
 165:  * left for those drives divined from other means
 166:  * (e.g. SI, AMPEX, etc.).
 167:  */
 168: short   hptypes[] = {
 169: #define HPDT_RM03   0
 170:     MBDT_RM03,
 171: #define HPDT_RM05   1
 172:     MBDT_RM05,
 173: #define HPDT_RP06   2
 174:     MBDT_RP06,
 175: #define HPDT_RM80   3
 176:     MBDT_RM80,
 177: #define HPDT_RP04   4
 178:     MBDT_RP04,
 179: #define HPDT_RP05   5
 180:     MBDT_RP05,
 181: #define HPDT_RP07   6
 182:     MBDT_RP07,
 183: #define HPDT_ML11A  7
 184:     MBDT_ML11A,
 185: #define HPDT_ML11B  8
 186:     MBDT_ML11B,
 187: #define HPDT_9775   9
 188:     -1,
 189: #define HPDT_9730   10
 190:     -1,
 191: #define HPDT_CAPRICORN  11
 192:     -1,
 193: #define HPDT_EAGLE  12
 194:     -1,
 195: #define HPDT_9300   13
 196:     -1,
 197: #define HPDT_RM02   14
 198:     MBDT_RM02,      /* beware, actually mapped */
 199: #define HPDT_2361   15
 200:     -1,
 201:     0
 202: };
 203: struct  mba_device *hpinfo[NHP];
 204: int hpattach(),hpustart(),hpstart(),hpdtint();
 205: struct  mba_driver hpdriver =
 206:     { hpattach, 0, hpustart, hpstart, hpdtint, 0,
 207:       hptypes, "hp", 0, hpinfo };
 208: 
 209: /*
 210:  * These variable are all measured in sectors.
 211:  * Sdist is how much to "lead" in the search for a desired sector
 212:  * (i.e. if want N, search for N-sdist.)
 213:  * Maxdist and mindist define the region right before our desired sector within
 214:  * which we don't bother searching.  We don't search when we are already less
 215:  * then maxdist and more than mindist sectors "before" our desired sector.
 216:  * Maxdist should be >= sdist.
 217:  *
 218:  * Beware, sdist, mindist and maxdist are not well tuned
 219:  * for many of the drives listed in this table.
 220:  * Try patching things with something i/o intensive
 221:  * running and watch iostat.
 222:  */
 223: struct hpst {
 224:     short   nsect;      /* # sectors/track */
 225:     short   ntrak;      /* # tracks/cylinder */
 226:     short   nspc;       /* # sector/cylinders */
 227:     short   ncyl;       /* # cylinders */
 228:     struct  size *sizes;    /* partition tables */
 229:     short   sdist;      /* seek distance metric */
 230:     short   maxdist;    /* boundaries of non-searched area */
 231:     short   mindist;    /* preceding the target sector */
 232:     char    *name;      /* name of disk type */
 233: } hpst[] = {
 234:     { 32, 5,    32*5,   823,    rm03_sizes, 7, 4, 1, "RM03" },
 235:     { 32, 19,   32*19,  823,    rm05_sizes, 7, 4, 1, "RM05" },
 236:     { 22,19,    22*19,  815,    rp06_sizes, 7, 4, 1, "RP06"},
 237:     { 31, 14,   31*14,  559,    rm80_sizes, 7, 4, 1, "RM80"},
 238:     { 22, 19,   22*19,  411,    rp05_sizes, 7, 4, 1, "RP04"},
 239:     { 22, 19,   22*19,  411,    rp05_sizes, 7, 4, 1, "RP05"},
 240:     { 50, 32,   50*32,  630,    rp07_sizes,    15, 8, 3, "RP07"},
 241:     { 1, 1, 1,  1,  0,      0, 0, 0, "ML11A"},
 242:     { 1, 1, 1,  1,  0,      0, 0, 0, "ML11B" },
 243:     { 32, 40,   32*40,  843,    cdc9775_sizes,  7, 4, 1, "9775" },
 244:     { 32, 10,   32*10,  823,    cdc9730_sizes,  7, 4, 1, "9730-160" },
 245:     { 32, 16,   32*16,  1024,   capricorn_sizes,10,4, 3, "capricorn" },
 246:     { 48, 20,   48*20,  842,    eagle_sizes,   15, 8, 3, "eagle" },
 247:     { 32, 19,   32*19,  815,    ampex_sizes,    7, 4, 1, "9300" },
 248:     { 64, 20,   64*20,  842,    fj2361_sizes,  15, 8, 3, "2361" },
 249: };
 250: 
 251: u_char  hp_offset[16] = {
 252:     HPOF_P400, HPOF_M400, HPOF_P400, HPOF_M400,
 253:     HPOF_P800, HPOF_M800, HPOF_P800, HPOF_M800,
 254:     HPOF_P1200, HPOF_M1200, HPOF_P1200, HPOF_M1200,
 255:     0, 0, 0, 0,
 256: };
 257: 
 258: struct  buf rhpbuf[NHP];
 259: struct  buf bhpbuf[NHP];
 260: struct  dkbad   hpbad[NHP];
 261: 
 262: struct  hpsoftc {
 263:     u_char  sc_hpinit;  /* drive initialized */
 264:     u_char  sc_recal;   /* recalibrate state */
 265:     u_char  sc_hdr;     /* next i/o includes header */
 266:     u_char  sc_doseeks; /* perform explicit seeks */
 267:     daddr_t sc_mlsize;  /* ML11 size */
 268:     int sc_blkdone; /* amount sucessfully transfered */
 269:     daddr_t sc_badbn;   /* replacement block number */
 270: } hpsoftc[NHP];
 271: 
 272: #define b_cylin b_resid
 273: 
 274: /* #define ML11 0  to remove ML11 support */
 275: #define ML11    (hptypes[mi->mi_type] == MBDT_ML11A)
 276: #define RP06    (hptypes[mi->mi_type] <= MBDT_RP06)
 277: #define RM80    (hptypes[mi->mi_type] == MBDT_RM80)
 278: 
 279: #define hpunit(dev) (minor(dev) >> 3)
 280: #define MASKREG(reg)    ((reg)&0xffff)
 281: #ifdef lint
 282: #define HPWAIT(mi, addr) (hpwait(mi))
 283: #else
 284: #define HPWAIT(mi, addr) (((addr)->hpds & HPDS_DRY) || hpwait(mi))
 285: #endif
 286: 
 287: /*ARGSUSED*/
 288: hpattach(mi, slave)
 289:     register struct mba_device *mi;
 290: {
 291: 
 292:     mi->mi_type = hpmaptype(mi);
 293:     if (!ML11 && mi->mi_dk >= 0) {
 294:         struct hpst *st = &hpst[mi->mi_type];
 295: 
 296:         dk_mspw[mi->mi_dk] = 1.0 / 60 / (st->nsect * 256);
 297:     }
 298: }
 299: 
 300: /*
 301:  * Map apparent MASSBUS drive type into manufacturer
 302:  * specific configuration.  For SI controllers this is done
 303:  * based on codes in the serial number register.  For
 304:  * EMULEX controllers, the track and sector attributes are
 305:  * used when the drive type is an RM02 (not supported by DEC).
 306:  */
 307: hpmaptype(mi)
 308:     register struct mba_device *mi;
 309: {
 310:     register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv;
 311:     register int type = mi->mi_type;
 312: 
 313:     /*
 314: 	 * Model-byte processing for SI controllers.
 315: 	 * NB:  Only deals with RM03 and RM05 emulations.
 316: 	 */
 317:     if (type == HPDT_RM03 || type == HPDT_RM05) {
 318:         int hpsn = hpaddr->hpsn;
 319: 
 320:         if ((hpsn & SIMB_LU) != mi->mi_drive)
 321:             return (type);
 322:         switch ((hpsn & SIMB_MB) & ~(SIMB_S6|SIRM03|SIRM05)) {
 323: 
 324:         case SI9775D:
 325:             printf("hp%d: 9775 (direct)\n", mi->mi_unit);
 326:             type = HPDT_9775;
 327:             break;
 328: 
 329:         case SI9730D:
 330:             printf("hp%d: 9730 (direct)\n", mi->mi_unit);
 331:             type = HPDT_9730;
 332:             break;
 333: 
 334:         case SI9766:
 335:             printf("hp%d: 9766\n", mi->mi_unit);
 336:             type = HPDT_RM05;
 337:             break;
 338: 
 339:         case SI9762:
 340:             printf("hp%d: 9762\n", mi->mi_unit);
 341:             type = HPDT_RM03;
 342:             break;
 343: 
 344:         case SICAPD:
 345:             printf("hp%d: capricorn\n", mi->mi_unit);
 346:             type = HPDT_CAPRICORN;
 347:             break;
 348: 
 349:         case SI9751D:
 350:             printf("hp%d: eagle\n", mi->mi_unit);
 351:             type = HPDT_EAGLE;
 352:             break;
 353:         }
 354:         return (type);
 355:     }
 356: 
 357:     /*
 358: 	 * EMULEX SC750 or SC780.  Poke the holding register.
 359: 	 */
 360:     if (type == HPDT_RM02) {
 361:         int nsectors, ntracks, ncyl;
 362: 
 363:         hpaddr->hpof = HPOF_FMT22;
 364:         mbclrattn(mi);
 365:         hpaddr->hpcs1 = HP_NOP;
 366:         hpaddr->hphr = HPHR_MAXTRAK;
 367:         ntracks = MASKREG(hpaddr->hphr) + 1;
 368:         DELAY(100);
 369:         hpaddr->hpcs1 = HP_NOP;
 370:         hpaddr->hphr = HPHR_MAXSECT;
 371:         nsectors = MASKREG(hpaddr->hphr) + 1;
 372:         DELAY(100);
 373:         hpaddr->hpcs1 = HP_NOP;
 374:         hpaddr->hphr = HPHR_MAXCYL;
 375:         ncyl = MASKREG(hpaddr->hphr) + 1;
 376:         for (type = 0; hptypes[type] != 0; type++)
 377:             if (hpst[type].nsect == nsectors &&
 378:                 hpst[type].ntrak == ntracks &&
 379:                 hpst[type].ncyl == ncyl)
 380:                 break;
 381: 
 382:         if (hptypes[type] == 0) {
 383:     printf("hp%d: %d sectors, %d tracks, %d cylinders: unknown device\n",
 384:                 mi->mi_unit, nsectors, ntracks, ncyl);
 385:             type = HPDT_RM02;
 386:         }
 387:         printf("hp%d: %s\n", mi->mi_unit, hpst[type].name);
 388:         hpaddr->hpcs1 = HP_DCLR|HP_GO;
 389:         mbclrattn(mi);      /* conservative */
 390:         return (type);
 391:     }
 392: 
 393:     /*
 394: 	 * Map all ML11's to the same type.  Also calculate
 395: 	 * transfer rates based on device characteristics.
 396: 	 */
 397:     if (type == HPDT_ML11A || type == HPDT_ML11B) {
 398:         register struct hpsoftc *sc = &hpsoftc[mi->mi_unit];
 399:         register int trt;
 400: 
 401:         sc->sc_mlsize = hpaddr->hpmr & HPMR_SZ;
 402:         if ((hpaddr->hpmr & HPMR_ARRTYP) == 0)
 403:             sc->sc_mlsize >>= 2;
 404:         if (mi->mi_dk >= 0) {
 405:             trt = (hpaddr->hpmr & HPMR_TRT) >> 8;
 406:             dk_mspw[mi->mi_dk] = 1.0 / (1<<(20-trt));
 407:         }
 408:         type = HPDT_ML11A;
 409:     }
 410:     return (type);
 411: }
 412: 
 413: hpopen(dev)
 414:     dev_t dev;
 415: {
 416:     register int unit = hpunit(dev);
 417:     register struct mba_device *mi;
 418: 
 419:     if (unit >= NHP || (mi = hpinfo[unit]) == 0 || mi->mi_alive == 0)
 420:         return (ENXIO);
 421:     return (0);
 422: }
 423: 
 424: hpstrategy(bp)
 425:     register struct buf *bp;
 426: {
 427:     register struct mba_device *mi;
 428:     register struct hpst *st;
 429:     register int unit;
 430:     long sz;
 431:     int xunit = minor(bp->b_dev) & 07;
 432:     int s;
 433: 
 434:     sz = bp->b_bcount;
 435:     sz = (sz+511) >> 9;
 436:     unit = hpunit(bp->b_dev);
 437:     if (unit >= NHP) {
 438:         bp->b_error = ENXIO;
 439:         goto bad;
 440:     }
 441:     mi = hpinfo[unit];
 442:     if (mi == 0 || mi->mi_alive == 0) {
 443:         bp->b_error = ENXIO;
 444:         goto bad;
 445:     }
 446:     st = &hpst[mi->mi_type];
 447:     if (ML11) {
 448:         struct hpsoftc *sc = &hpsoftc[unit];
 449: 
 450:         if (bp->b_blkno < 0 ||
 451:             bp->b_blkno+sz > sc->sc_mlsize) {
 452:             if (bp->b_blkno == sc->sc_mlsize) {
 453:                 bp->b_resid = bp->b_bcount;
 454:                 goto done;
 455:             }
 456:             bp->b_error = EINVAL;
 457:             goto bad;
 458:         }
 459:         bp->b_cylin = 0;
 460:     } else {
 461:         if (bp->b_blkno < 0 ||
 462:             bp->b_blkno+sz > st->sizes[xunit].nblocks) {
 463:             if (bp->b_blkno == st->sizes[xunit].nblocks) {
 464:                 bp->b_resid = bp->b_bcount;
 465:                 goto done;
 466:             }
 467:             bp->b_error = EINVAL;
 468:             goto bad;
 469:         }
 470:         bp->b_cylin = bp->b_blkno/st->nspc + st->sizes[xunit].cyloff;
 471:     }
 472:     s = spl5();
 473:     disksort(&mi->mi_tab, bp);
 474:     if (mi->mi_tab.b_active == 0)
 475:         mbustart(mi);
 476:     splx(s);
 477:     return;
 478: 
 479: bad:
 480:     bp->b_flags |= B_ERROR;
 481: done:
 482:     iodone(bp);
 483:     return;
 484: }
 485: 
 486: hpustart(mi)
 487:     register struct mba_device *mi;
 488: {
 489:     register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv;
 490:     register struct buf *bp = mi->mi_tab.b_actf;
 491:     register struct hpst *st;
 492:     struct hpsoftc *sc = &hpsoftc[mi->mi_unit];
 493:     daddr_t bn;
 494:     int sn, tn, dist;
 495: 
 496:     st = &hpst[mi->mi_type];
 497:     hpaddr->hpcs1 = 0;
 498:     if ((hpaddr->hpcs1&HP_DVA) == 0)
 499:         return (MBU_BUSY);
 500: 
 501:     switch (sc->sc_recal) {
 502: 
 503:     case 1:
 504:         (void)HPWAIT(mi, hpaddr);
 505:         hpaddr->hpdc = bp->b_cylin;
 506:         hpaddr->hpcs1 = HP_SEEK|HP_GO;
 507:         sc->sc_recal++;
 508:         return (MBU_STARTED);
 509:     case 2:
 510:         break;
 511:     }
 512:     sc->sc_recal = 0;
 513:     if ((hpaddr->hpds & HPDS_VV) == 0 || !sc->sc_hpinit) {
 514:         struct buf *bbp = &bhpbuf[mi->mi_unit];
 515: 
 516:         sc->sc_hpinit = 1;
 517:         hpaddr->hpcs1 = HP_DCLR|HP_GO;
 518:         if (mi->mi_mba->mba_drv[0].mbd_as & (1<<mi->mi_drive))
 519:             printf("DCLR attn\n");
 520:         hpaddr->hpcs1 = HP_PRESET|HP_GO;
 521:         if (!ML11)
 522:             hpaddr->hpof = HPOF_FMT22;
 523:         mbclrattn(mi);
 524:         if (!ML11) {
 525:             bbp->b_flags = B_READ|B_BUSY;
 526:             bbp->b_dev = bp->b_dev;
 527:             bbp->b_bcount = 512;
 528:             bbp->b_un.b_addr = (caddr_t)&hpbad[mi->mi_unit];
 529:             bbp->b_blkno = st->ncyl*st->nspc - st->nsect;
 530:             bbp->b_cylin = st->ncyl - 1;
 531:             mi->mi_tab.b_actf = bbp;
 532:             bbp->av_forw = bp;
 533:             bp = bbp;
 534:         }
 535:     }
 536:     if (mi->mi_tab.b_active || mi->mi_hd->mh_ndrive == 1) {
 537:         if (mi->mi_tab.b_errcnt >= 16 && (bp->b_flags & B_READ)) {
 538:             hpaddr->hpof =
 539:                 hp_offset[mi->mi_tab.b_errcnt & 017]|HPOF_FMT22;
 540:             hpaddr->hpcs1 = HP_OFFSET|HP_GO;
 541:             (void)HPWAIT(mi, hpaddr);
 542:             mbclrattn(mi);
 543:         }
 544:         return (MBU_DODATA);
 545:     }
 546:     if (ML11)
 547:         return (MBU_DODATA);
 548:     if ((hpaddr->hpds & HPDS_DREADY) != HPDS_DREADY)
 549:         return (MBU_DODATA);
 550:     bn = bp->b_blkno;
 551:     sn = bn % st->nspc;
 552:     tn = sn / st->nsect;
 553:     sn = sn % st->nsect;
 554:     if (bp->b_cylin == MASKREG(hpaddr->hpdc)) {
 555:         if (sc->sc_doseeks)
 556:             return (MBU_DODATA);
 557:         dist = sn - (MASKREG(hpaddr->hpla) >> 6) - 1;
 558:         if (dist < 0)
 559:             dist += st->nsect;
 560:         if (dist > st->maxdist || dist < st->mindist)
 561:             return (MBU_DODATA);
 562:     } else
 563:         hpaddr->hpdc = bp->b_cylin;
 564:     if (sc->sc_doseeks)
 565:         hpaddr->hpcs1 = HP_SEEK|HP_GO;
 566:     else {
 567:         sn = (sn + st->nsect - st->sdist) % st->nsect;
 568:         hpaddr->hpda = (tn << 8) + sn;
 569:         hpaddr->hpcs1 = HP_SEARCH|HP_GO;
 570:     }
 571:     return (MBU_STARTED);
 572: }
 573: 
 574: hpstart(mi)
 575:     register struct mba_device *mi;
 576: {
 577:     register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv;
 578:     register struct buf *bp = mi->mi_tab.b_actf;
 579:     register struct hpst *st = &hpst[mi->mi_type];
 580:     struct hpsoftc *sc = &hpsoftc[mi->mi_unit];
 581:     daddr_t bn;
 582:     int sn, tn, cn;
 583: 
 584:     if (ML11)
 585:         hpaddr->hpda = bp->b_blkno + sc->sc_blkdone;
 586:     else {
 587:         if (bp->b_flags & B_BAD) {
 588:             bn = sc->sc_badbn;
 589:             cn = bn / st->nspc;
 590:         } else {
 591:             bn = bp->b_blkno;
 592:             cn = bp->b_cylin;
 593:         }
 594:         sn = bn % st->nspc;
 595:         if ((bp->b_flags & B_BAD) == 0)
 596:             sn += sc->sc_blkdone;
 597:         tn = sn / st->nsect;
 598:         sn %= st->nsect;
 599:         cn += tn / st->ntrak;
 600:         tn %= st->ntrak;
 601:         hpaddr->hpda = (tn << 8) + sn;
 602:         hpaddr->hpdc = cn;
 603:     }
 604:     mi->mi_tab.b_bdone = dbtob(sc->sc_blkdone);
 605:     if (sc->sc_hdr) {
 606:         if (bp->b_flags & B_READ)
 607:             return (HP_RHDR|HP_GO);
 608:         else
 609:             return (HP_WHDR|HP_GO);
 610:     }
 611:     return (0);
 612: }
 613: 
 614: hpdtint(mi, mbsr)
 615:     register struct mba_device *mi;
 616:     int mbsr;
 617: {
 618:     register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv;
 619:     register struct buf *bp = mi->mi_tab.b_actf;
 620:     register int er1, er2;
 621:     struct hpsoftc *sc = &hpsoftc[mi->mi_unit];
 622:     int retry = 0;
 623:     int npf;
 624:     daddr_t bn;
 625:     int bcr;
 626: 
 627:     bcr = MASKREG(-mi->mi_mba->mba_bcr);
 628:     if (hpaddr->hpds&HPDS_ERR || mbsr&MBSR_EBITS) {
 629:         er1 = hpaddr->hper1;
 630:         er2 = hpaddr->hper2;
 631:         if (bp->b_flags & B_BAD) {
 632:             npf = bp->b_error;
 633:             bn = sc->sc_badbn;
 634:         } else {
 635:             npf = btop(bp->b_bcount - bcr);
 636:             if (er1 & (HPER1_DCK | HPER1_ECH))
 637:                 npf--;
 638:             bn = bp->b_blkno + npf;
 639:         }
 640:         if (HPWAIT(mi, hpaddr) == 0)
 641:             goto hard;
 642: #ifdef HPDEBUG
 643:         if (hpdebug) {
 644:             int dc = hpaddr->hpdc, da = hpaddr->hpda;
 645: 
 646:             log(LOG_DEBUG,
 647:             "hperr: bp %x cyl %d blk %d blkdone %d as %o dc %x da %x\n",
 648:                 bp, bp->b_cylin, bn, sc->sc_blkdone,
 649:                 hpaddr->hpas&0xff, MASKREG(dc), MASKREG(da));
 650:             log(LOG_DEBUG,
 651:                 "errcnt %d mbsr=%b er1=%b er2=%b bcr -%d\n",
 652:                 mi->mi_tab.b_errcnt, mbsr, mbsr_bits,
 653:                 MASKREG(er1), HPER1_BITS,
 654:                 MASKREG(er2), HPER2_BITS, bcr);
 655:         }
 656: #endif
 657:         if (er1 & HPER1_HCRC) {
 658:             er1 &= ~(HPER1_HCE|HPER1_FER);
 659:             er2 &= ~HPER2_BSE;
 660:         }
 661:         if (er1 & HPER1_WLE) {
 662:             log(LOG_WARNING, "hp%d: write locked\n",
 663:                 hpunit(bp->b_dev));
 664:             bp->b_flags |= B_ERROR;
 665:         } else if (sc->sc_hdr) {
 666:             goto hard;
 667:         } else if (RM80 && er2&HPER2_SSE) {
 668:             (void) hpecc(mi, SSE);
 669:             return (MBD_RESTARTED);
 670:         } else if ((er2 & HPER2_BSE) && !ML11) {
 671:             if (hpecc(mi, BSE))
 672:                 return (MBD_RESTARTED);
 673:             goto hard;
 674:         } else if (MASKREG(er1) == HPER1_FER && RP06) {
 675:             if (hpecc(mi, BSE))
 676:                 return (MBD_RESTARTED);
 677:             goto hard;
 678:         } else if ((er1 & (HPER1_DCK | HPER1_ECH)) == HPER1_DCK &&
 679:             mi->mi_tab.b_errcnt >= 3) {
 680:             if (hpecc(mi, ECC))
 681:                 return (MBD_RESTARTED);
 682:             /*
 683: 			 * ECC corrected.  Only log retries below
 684: 			 * if we got errors other than soft ECC
 685: 			 * (as indicated by additional retries).
 686: 			 */
 687:             if (mi->mi_tab.b_errcnt == 3)
 688:                 mi->mi_tab.b_errcnt = 0;
 689:         } else if ((er1 & HPER1_HCRC) && !ML11 && hpecc(mi, BSE)) {
 690:             /*
 691:  			 * HCRC means the header is screwed up and the sector
 692:  			 * might well exist in the bad sector table,
 693: 			 * better check....
 694:  			 */
 695:             return (MBD_RESTARTED);
 696:         } else if (++mi->mi_tab.b_errcnt > 27 ||
 697:             (ML11 && mi->mi_tab.b_errcnt > 15) ||
 698:             mbsr & MBSR_HARD ||
 699:             er1 & HPER1_HARD ||
 700:             (!ML11 && (er2 & HPER2_HARD))) {
 701: hard:
 702:             bp->b_blkno = bn;       /* XXX */
 703:             harderr(bp, "hp");
 704:             if (mbsr & (MBSR_EBITS &~ (MBSR_DTABT|MBSR_MBEXC)))
 705:                 printf("mbsr=%b ", mbsr, mbsr_bits);
 706:             printf("er1=%b er2=%b",
 707:                 MASKREG(hpaddr->hper1), HPER1_BITS,
 708:                 MASKREG(hpaddr->hper2), HPER2_BITS);
 709:             if (sc->sc_hdr)
 710:                 printf(" (hdr i/o)");
 711:             printf("\n");
 712:             bp->b_flags |= B_ERROR;
 713:             bp->b_flags &= ~B_BAD;
 714:         } else
 715:             retry = 1;
 716:         hpaddr->hpcs1 = HP_DCLR|HP_GO;
 717:         if (retry && (mi->mi_tab.b_errcnt & 07) == 4) {
 718:             hpaddr->hpcs1 = HP_RECAL|HP_GO;
 719:             sc->sc_recal = 1;
 720:             return (MBD_REPOSITION);
 721:         }
 722:     }
 723: #ifdef HPDEBUG
 724:     else
 725:         if (hpdebug && sc->sc_recal) {
 726:             log(LOG_DEBUG,
 727:                 "recal %d errcnt %d mbsr=%b er1=%b er2=%b\n",
 728:                 sc->sc_recal, mi->mi_tab.b_errcnt, mbsr, mbsr_bits,
 729:                 hpaddr->hper1, HPER1_BITS,
 730:                 hpaddr->hper2, HPER2_BITS);
 731:         }
 732: #endif
 733:     (void)HPWAIT(mi, hpaddr);
 734:     if (retry)
 735:         return (MBD_RETRY);
 736:     if (mi->mi_tab.b_errcnt >= 16) {
 737:         /*
 738: 		 * This is fast and occurs rarely; we don't
 739: 		 * bother with interrupts.
 740: 		 */
 741:         hpaddr->hpcs1 = HP_RTC|HP_GO;
 742:         (void)HPWAIT(mi, hpaddr);
 743:         mbclrattn(mi);
 744:     }
 745:     if (mi->mi_tab.b_errcnt && (bp->b_flags & B_ERROR) == 0)
 746:         log(LOG_INFO, "hp%d%c: %d retries %sing sn%d\n",
 747:             hpunit(bp->b_dev), 'a'+(minor(bp->b_dev)&07),
 748:             mi->mi_tab.b_errcnt,
 749:             (bp->b_flags & B_READ) ? "read" : "writ",
 750:             (bp->b_flags & B_BAD) ?
 751:             sc->sc_badbn : bp->b_blkno + sc->sc_blkdone);
 752:     if ((bp->b_flags & B_BAD) && hpecc(mi, CONT))
 753:         return (MBD_RESTARTED);
 754:     sc->sc_hdr = 0;
 755:     sc->sc_blkdone = 0;
 756:     bp->b_resid = bcr;
 757:     if (!ML11) {
 758:         hpaddr->hpof = HPOF_FMT22;
 759:         hpaddr->hpcs1 = HP_RELEASE|HP_GO;
 760:     }
 761:     return (MBD_DONE);
 762: }
 763: 
 764: /*
 765:  * Wait (for a bit) for a drive to come ready;
 766:  * returns nonzero on success.
 767:  */
 768: hpwait(mi)
 769:     register struct mba_device *mi;
 770: {
 771:     register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv;
 772:     register i = 100000;
 773: 
 774:     while ((hpaddr->hpds & HPDS_DRY) == 0 && --i)
 775:         DELAY(10);
 776:     if (i == 0)
 777:         printf("hp%d: intr, not ready\n", mi->mi_unit);
 778:     return (i);
 779: }
 780: 
 781: hpread(dev, uio)
 782:     dev_t dev;
 783:     struct uio *uio;
 784: {
 785:     register int unit = hpunit(dev);
 786: 
 787:     if (unit >= NHP)
 788:         return (ENXIO);
 789:     return (physio(hpstrategy, &rhpbuf[unit], dev, B_READ, minphys, uio));
 790: }
 791: 
 792: hpwrite(dev, uio)
 793:     dev_t dev;
 794:     struct uio *uio;
 795: {
 796:     register int unit = hpunit(dev);
 797: 
 798:     if (unit >= NHP)
 799:         return (ENXIO);
 800:     return (physio(hpstrategy, &rhpbuf[unit], dev, B_WRITE, minphys, uio));
 801: }
 802: 
 803: /*ARGSUSED*/
 804: hpioctl(dev, cmd, data, flag)
 805:     dev_t dev;
 806:     int cmd;
 807:     caddr_t data;
 808:     int flag;
 809: {
 810: 
 811:     switch (cmd) {
 812: 
 813:     case DKIOCHDR:  /* do header read/write */
 814:         hpsoftc[hpunit(dev)].sc_hdr = 1;
 815:         return (0);
 816: 
 817:     default:
 818:         return (ENXIO);
 819:     }
 820: }
 821: 
 822: hpecc(mi, flag)
 823:     register struct mba_device *mi;
 824:     int flag;
 825: {
 826:     register struct mba_regs *mbp = mi->mi_mba;
 827:     register struct hpdevice *rp = (struct hpdevice *)mi->mi_drv;
 828:     register struct buf *bp = mi->mi_tab.b_actf;
 829:     register struct hpst *st = &hpst[mi->mi_type];
 830:     struct hpsoftc *sc = &hpsoftc[mi->mi_unit];
 831:     int npf, o;
 832:     int bn, cn, tn, sn;
 833:     int bcr;
 834: 
 835:     bcr = MASKREG(-mbp->mba_bcr);
 836:     if (bp->b_flags & B_BAD)
 837:         npf = bp->b_error;
 838:     else {
 839:         npf = bp->b_bcount - bcr;
 840:         /*
 841: 		 * Watch out for fractional sector at end of transfer;
 842: 		 * want to round up if finished, otherwise round down.
 843: 		 */
 844:         if (bcr == 0)
 845:             npf += 511;
 846:         npf = btodb(npf);
 847:     }
 848:     o = (int)bp->b_un.b_addr & PGOFSET;
 849:     bn = bp->b_blkno;
 850:     cn = bp->b_cylin;
 851:     sn = bn%(st->nspc) + npf;
 852:     tn = sn/st->nsect;
 853:     sn %= st->nsect;
 854:     cn += tn/st->ntrak;
 855:     tn %= st->ntrak;
 856:     bn += npf;
 857:     switch (flag) {
 858:     case ECC: {
 859:         register int i;
 860:         caddr_t addr;
 861:         struct pte mpte;
 862:         int bit, byte, mask;
 863: 
 864:         npf--;      /* because block in error is previous block */
 865:         bn--;
 866:         if (bp->b_flags & B_BAD)
 867:             bn = sc->sc_badbn;
 868:         log(LOG_WARNING, "hp%d%c: soft ecc sn%d\n", hpunit(bp->b_dev),
 869:             'a'+(minor(bp->b_dev)&07), bn);
 870:         mask = MASKREG(rp->hpec2);
 871:         i = MASKREG(rp->hpec1) - 1;     /* -1 makes 0 origin */
 872:         bit = i&07;
 873:         i = (i&~07)>>3;
 874:         byte = i + o;
 875:         while (i < 512 && (int)dbtob(npf)+i < bp->b_bcount && bit > -11) {
 876:             mpte = mbp->mba_map[npf+btop(byte)];
 877:             addr = ptob(mpte.pg_pfnum) + (byte & PGOFSET);
 878:             putmemc(addr, getmemc(addr)^(mask<<bit));
 879:             byte++;
 880:             i++;
 881:             bit -= 8;
 882:         }
 883:         if (bcr == 0)
 884:             return (0);
 885:         npf++;
 886:         break;
 887:         }
 888: 
 889:     case SSE:
 890:         rp->hpof |= HPOF_SSEI;
 891:         if (bp->b_flags & B_BAD) {
 892:             bn = sc->sc_badbn;
 893:             goto fixregs;
 894:         }
 895:         mbp->mba_bcr = -(bp->b_bcount - (int)ptob(npf));
 896:         break;
 897: 
 898:     case BSE:
 899:         if (rp->hpof & HPOF_SSEI)
 900:             sn++;
 901: #ifdef HPBDEBUG
 902:         if (hpbdebug)
 903:         log(LOG_DEBUG, "hpecc, BSE: bn %d cn %d tn %d sn %d\n", bn, cn, tn, sn);
 904: #endif
 905:         if (bp->b_flags & B_BAD)
 906:             return (0);
 907:         if ((bn = isbad(&hpbad[mi->mi_unit], cn, tn, sn)) < 0)
 908:             return (0);
 909:         bp->b_flags |= B_BAD;
 910:         bp->b_error = npf + 1;
 911:         rp->hpof &= ~HPOF_SSEI;
 912:         bn = st->ncyl*st->nspc - st->nsect - 1 - bn;
 913:         sc->sc_badbn = bn;
 914:     fixregs:
 915:         cn = bn/st->nspc;
 916:         sn = bn%st->nspc;
 917:         tn = sn/st->nsect;
 918:         sn %= st->nsect;
 919:         bcr = bp->b_bcount - (int)ptob(npf);
 920:         bcr = MIN(bcr, 512);
 921:         mbp->mba_bcr = -bcr;
 922: #ifdef HPBDEBUG
 923:         if (hpbdebug)
 924:         log(LOG_DEBUG, "revector to cn %d tn %d sn %d\n", cn, tn, sn);
 925: #endif
 926:         break;
 927: 
 928:     case CONT:
 929: #ifdef HPBDEBUG
 930:         if (hpbdebug)
 931:         log(LOG_DEBUG, "hpecc, CONT: bn %d cn %d tn %d sn %d\n", bn,cn,tn,sn);
 932: #endif
 933:         bp->b_flags &= ~B_BAD;
 934:         if ((int)ptob(npf) >= bp->b_bcount)
 935:             return (0);
 936:         mbp->mba_bcr = -(bp->b_bcount - (int)ptob(npf));
 937:         break;
 938:     }
 939:     rp->hpcs1 = HP_DCLR|HP_GO;
 940:     if (rp->hpof & HPOF_SSEI)
 941:         sn++;
 942:     rp->hpdc = cn;
 943:     rp->hpda = (tn<<8) + sn;
 944:     mbp->mba_sr = -1;
 945:     mbp->mba_var = (int)ptob(npf) + o;
 946:     rp->hpcs1 = bp->b_flags&B_READ ? HP_RCOM|HP_GO : HP_WCOM|HP_GO;
 947:     mi->mi_tab.b_errcnt = 0;    /* error has been corrected */
 948:     sc->sc_blkdone = npf;
 949:     return (1);
 950: }
 951: 
 952: #define DBSIZE  20
 953: 
 954: hpdump(dev)
 955:     dev_t dev;
 956: {
 957:     register struct mba_device *mi;
 958:     register struct mba_regs *mba;
 959:     struct hpdevice *hpaddr;
 960:     char *start;
 961:     int num, unit;
 962:     register struct hpst *st;
 963: 
 964:     num = maxfree;
 965:     start = 0;
 966:     unit = hpunit(dev);
 967:     if (unit >= NHP)
 968:         return (ENXIO);
 969: #define phys(a,b)   ((b)((int)(a)&0x7fffffff))
 970:     mi = phys(hpinfo[unit],struct mba_device *);
 971:     if (mi == 0 || mi->mi_alive == 0)
 972:         return (ENXIO);
 973:     mba = phys(mi->mi_hd, struct mba_hd *)->mh_physmba;
 974:     mba->mba_cr = MBCR_INIT;
 975:     hpaddr = (struct hpdevice *)&mba->mba_drv[mi->mi_drive];
 976:     if ((hpaddr->hpds & HPDS_VV) == 0) {
 977:         hpaddr->hpcs1 = HP_DCLR|HP_GO;
 978:         hpaddr->hpcs1 = HP_PRESET|HP_GO;
 979:         hpaddr->hpof = HPOF_FMT22;
 980:     }
 981:     st = &hpst[mi->mi_type];
 982:     if (dumplo < 0)
 983:         return (EINVAL);
 984:     if (dumplo + num >= st->sizes[minor(dev)&07].nblocks)
 985:         num = st->sizes[minor(dev)&07].nblocks - dumplo;
 986:     while (num > 0) {
 987:         register struct pte *hpte = mba->mba_map;
 988:         register int i;
 989:         int blk, cn, sn, tn;
 990:         daddr_t bn;
 991: 
 992:         blk = num > DBSIZE ? DBSIZE : num;
 993:         bn = dumplo + btop(start);
 994:         cn = bn/st->nspc + st->sizes[minor(dev)&07].cyloff;
 995:         sn = bn%st->nspc;
 996:         tn = sn/st->nsect;
 997:         sn = sn%st->nsect;
 998:         hpaddr->hpdc = cn;
 999:         hpaddr->hpda = (tn << 8) + sn;
1000:         for (i = 0; i < blk; i++)
1001:             *(int *)hpte++ = (btop(start)+i) | PG_V;
1002:         mba->mba_sr = -1;
1003:         mba->mba_bcr = -(blk*NBPG);
1004:         mba->mba_var = 0;
1005:         hpaddr->hpcs1 = HP_WCOM | HP_GO;
1006:         while ((hpaddr->hpds & HPDS_DRY) == 0)
1007:             DELAY(10);
1008:         if (hpaddr->hpds&HPDS_ERR)
1009:             return (EIO);
1010:         start += blk*NBPG;
1011:         num -= blk;
1012:     }
1013:     return (0);
1014: }
1015: 
1016: hpsize(dev)
1017:     dev_t dev;
1018: {
1019:     int unit = hpunit(dev);
1020:     struct mba_device *mi;
1021:     struct hpst *st;
1022: 
1023:     if (unit >= NHP || (mi = hpinfo[unit]) == 0 || mi->mi_alive == 0)
1024:         return (-1);
1025:     st = &hpst[mi->mi_type];
1026:     return ((int)st->sizes[minor(dev) & 07].nblocks);
1027: }
1028: #endif

Defined functions

hpattach defined in line 288; used 2 times
hpdtint defined in line 614; used 2 times
hpdump defined in line 954; never used
hpecc defined in line 822; used 6 times
hpioctl defined in line 804; never used
hpmaptype defined in line 307; used 1 times
hpopen defined in line 413; never used
hpread defined in line 781; never used
hpsize defined in line 1016; never used
hpstart defined in line 574; used 2 times
hpstrategy defined in line 424; used 2 times
hpustart defined in line 486; used 2 times
hpwait defined in line 768; used 2 times
hpwrite defined in line 792; never used

Defined variables

bhpbuf defined in line 259; used 1 times
hp_offset defined in line 251; used 1 times
hpbad defined in line 260; used 2 times
hpbdebug defined in line 13; used 3 times
hpdebug defined in line 10; used 2 times
hpdriver defined in line 205; used 5 times
hpinfo defined in line 203; used 5 times
hpsoftc defined in line 270; used 7 times
hpst defined in line 233; used 11 times
hptypes defined in line 168; used 6 times
rhpbuf defined in line 258; used 2 times
rp06_sizes defined in line 51; used 1 times

Defined struct's

hpsoftc defined in line 262; used 12 times
hpst defined in line 223; used 14 times
size defined in line 48; used 2 times
  • in line 228(2)

Defined macros

DBSIZE defined in line 952; used 2 times
  • in line 992(2)
HPDT_2361 defined in line 199; never used
HPDT_9300 defined in line 195; never used
HPDT_9730 defined in line 189; used 1 times
HPDT_9775 defined in line 187; used 1 times
HPDT_CAPRICORN defined in line 191; used 1 times
HPDT_EAGLE defined in line 193; used 1 times
HPDT_ML11A defined in line 183; used 2 times
HPDT_ML11B defined in line 185; used 1 times
HPDT_RM02 defined in line 197; used 2 times
HPDT_RM03 defined in line 169; used 2 times
HPDT_RM05 defined in line 171; used 2 times
HPDT_RM80 defined in line 175; never used
HPDT_RP04 defined in line 177; never used
HPDT_RP05 defined in line 179; never used
HPDT_RP06 defined in line 173; never used
HPDT_RP07 defined in line 181; never used
HPWAIT defined in line 284; used 5 times
MASKREG defined in line 280; used 16 times
ML11 defined in line 275; used 11 times
RM80 defined in line 277; used 1 times
RP06 defined in line 276; used 1 times
b_cylin defined in line 272; used 9 times
hpunit defined in line 279; used 10 times
phys defined in line 969; used 2 times
Last modified: 1986-06-05
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2177
Valid CSS Valid XHTML 1.0 Strict