1: /*
   2:  * Copyright (c) 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:  *	@(#)si.c	1.5 (2.11BSD GTE) 1995/04/13
   7:  */
   8: 
   9: /*
  10:  *	SI 9500 driver for CDC 9766 disks
  11:  */
  12: 
  13: #include "si.h"
  14: #if NSI > 0
  15: #include "param.h"
  16: #include "../machine/seg.h"
  17: 
  18: #include "systm.h"
  19: #include "buf.h"
  20: #include "conf.h"
  21: #include "sireg.h"
  22: #include "map.h"
  23: #include "uba.h"
  24: #include "dk.h"
  25: #include "disklabel.h"
  26: #include "disk.h"
  27: #include "xp.h"
  28: #include "errno.h"
  29: 
  30: #define SI_NSECT    32
  31: #define SI_NTRAC    19
  32: 
  33: #if NXPD > 0
  34: extern struct size {
  35:     daddr_t nblocks;
  36:     int cyloff;
  37: } rm5_sizes[8];
  38: #else !NXPD
  39: /*
  40:  * We reserve room for bad block forwarding information even though this
  41:  * driver doesn't support bad block forwarding.  This allows us to simply
  42:  * copy the table from xp.c.
  43:  */
  44: struct size {
  45:     daddr_t nblocks;
  46:     int cyloff;
  47: } rm5_sizes[8] = {  /* RM05, CDC 9766 */
  48:     9120,     0,    /* a: cyl   0 -  14 */
  49:     9120,    15,    /* b: cyl  15 -  29 */
  50:     234080,  30,    /* c: cyl  30 - 414 */
  51:     247906, 415,    /* d: cyl 415 - 822, reserve 1 track + 126 */
  52:     164160,  30,    /* e: cyl  30 - 299 */
  53:     152000, 300,    /* f: cyl 300 - 549 */
  54:     165826, 550,    /* g: cyl 550 - 822, reserve 1 track + 126 */
  55:     500384,   0,    /* h: cyl   0 - 822 */
  56: };
  57: #endif NXPD
  58: 
  59: struct  sidevice *SIADDR;
  60: 
  61: int si_offset[] = { SI_OFP, SI_OFM };
  62: 
  63: struct  buf sitab;
  64: struct  buf siutab[NSI];
  65: 
  66: int sicc[NSI];  /* Current cylinder */
  67: int dualsi = 0; /* dual port flag */
  68: 
  69: #ifdef UCB_METER
  70: static  int     si_dkn = -1;    /* number for iostat */
  71: #endif
  72: 
  73: void
  74: siroot()
  75: {
  76:     siattach((struct sidevice *)0176700, 0);
  77: }
  78: 
  79: siattach(addr, unit)
  80: register struct sidevice *addr;
  81: {
  82: #ifdef UCB_METER
  83:     if (si_dkn < 0) {
  84:         dk_alloc(&si_dkn, NSI+1, "si", 60L * 32L * 256L);
  85:         if (si_dkn >= 0)
  86:             dk_wps[si_dkn+NSI] = 0L;
  87:     }
  88: #endif
  89: 
  90:     if (unit != 0)
  91:         return(0);
  92:     if ((addr != (struct sidevice *) NULL) && (fioword(addr) != -1))
  93:     {
  94:         SIADDR = addr;
  95:         if(addr ->siscr != 0)
  96:             dualsi++;   /* dual port controller */
  97:         if((addr->sierr & (SIERR_ERR | SIERR_CNT)) == (SIERR_ERR | SIERR_CNT))
  98:             dualsi++;
  99:         return(1);
 100:     }
 101:     SIADDR = (struct sidevice *) NULL;
 102:     return(0);
 103: }
 104: 
 105: siopen(dev, flag)
 106:     dev_t dev;
 107:     int flag;
 108: {
 109:     register int unit;
 110: 
 111:     unit = minor(dev) & 077;
 112:     if (unit >= (NSI << 3) || !SIADDR)
 113:         return (ENXIO);
 114:     return (0);
 115: }
 116: 
 117: sistrategy(bp)
 118: register struct buf *bp;
 119: {
 120:     register struct buf *dp;
 121:     register int unit;
 122:     long bn;
 123:     int s;
 124: 
 125:     unit = minor(bp->b_dev) & 077;
 126:     if (unit >= (NSI << 3) || (SIADDR == (struct sidevice *) NULL)) {
 127:         bp->b_error = ENXIO;
 128:         goto errexit;
 129:     }
 130:     if (bp->b_blkno < 0 ||
 131:         (bn = bp->b_blkno) + (long) ((bp->b_bcount + 511) >> 9)
 132:         > rm5_sizes[unit & 07].nblocks) {
 133:         bp->b_error = EINVAL;
 134: errexit:
 135:         bp->b_flags |= B_ERROR;
 136:         iodone(bp);
 137:         return;
 138:     }
 139:     mapalloc(bp);
 140:     bp->b_cylin = bn / (SI_NSECT * SI_NTRAC) + rm5_sizes[unit & 07].cyloff;
 141:     unit = dkunit(bp->b_dev);
 142:     dp = &siutab[unit];
 143:     s = splbio();
 144:     disksort(dp, bp);
 145:     if (dp->b_active == 0) {
 146:         siustart(unit);
 147:         if (sitab.b_active == 0)
 148:             sistart();
 149:     }
 150:     splx(s);
 151: }
 152: 
 153: /*
 154:  * Unit start routine.
 155:  * Seek the drive to where the data is
 156:  * and then generate another interrupt
 157:  * to actually start the transfer.
 158:  * If there is only one drive on the controller
 159:  * or we are very close to the data, don't
 160:  * bother with the search.  If called after
 161:  * searching once, don't bother to look
 162:  * where we are, just queue for transfer (to avoid
 163:  * positioning forever without transferring).
 164:  */
 165: siustart(unit)
 166: register unit;
 167: {
 168:     register struct sidevice *siaddr = SIADDR;
 169:     register struct buf *dp;
 170:     struct  buf *bp;
 171:     daddr_t bn;
 172:     int sn, cn, csn;
 173: 
 174:     if (unit >= NSI)
 175:         return;
 176: #ifdef UCB_METER
 177:     if (si_dkn >= 0)
 178:         dk_busy &= ~(1 << (si_dkn + unit));
 179: #endif
 180:     dp = &siutab[unit];
 181:     if ((bp = dp->b_actf) == NULL)
 182:         return;
 183:     /*
 184: 	 * If we have already positioned this drive,
 185: 	 * then just put it on the ready queue.
 186: 	 */
 187:     if (dp->b_active)
 188:         goto done;
 189:     dp->b_active++;
 190: 
 191: #if NSI >   1
 192:     /*
 193: 	 * If drive is not ready, forget about positioning.
 194: 	 */
 195:     if(dualsi)
 196:         getsi();
 197:     if ((siaddr->sissr >> (unit*4)) & SISSR_NRDY)
 198:         goto done;
 199: 
 200:     /*
 201: 	 * Figure out where this transfer is going to
 202: 	 * and see if we are close enough to justify not searching.
 203: 	 */
 204:     bn = bp->b_blkno;
 205:     cn = bp->b_cylin;
 206:     sn = bn % (SI_NSECT * SI_NTRAC);
 207:     sn = (sn + SI_NSECT) % SI_NSECT;
 208: 
 209:     if (sicc[unit] == cn)
 210:         goto done;
 211: 
 212: search:
 213:     siaddr->sisar = (unit << 10) | cn;
 214:     if(dualsi)
 215:         SIADDR->siscr = 0;
 216:     sicc[unit] = cn;
 217: #ifdef UCB_METER
 218:     /*
 219: 	 * Mark unit busy for iostat.
 220: 	 */
 221:     if (si_dkn >= 0) {
 222:         int dkn = si_dkn + unit;
 223: 
 224:         dk_busy |= 1<<dkn;
 225:         dk_seek[dkn]++;
 226:     }
 227: #endif
 228:     return;
 229: #endif	NSI > 1
 230: 
 231: done:
 232:     /*
 233: 	 * Device is ready to go.
 234: 	 * Put it on the ready queue for the controller.
 235: 	 */
 236:     dp->b_forw = NULL;
 237:     if (sitab.b_actf == NULL)
 238:         sitab.b_actf = dp;
 239:     else
 240:         sitab.b_actl->b_forw = dp;
 241:     sitab.b_actl = dp;
 242: }
 243: 
 244: /*
 245:  * Start up a transfer on a drive.
 246:  */
 247: sistart()
 248: {
 249:     register struct sidevice *siaddr = SIADDR;
 250:     register struct buf *bp;
 251:     register unit;
 252:     struct  buf *dp;
 253:     daddr_t bn;
 254:     int dn, sn, tn, cn;
 255:     int offset;
 256: 
 257: loop:
 258:     /*
 259: 	 * Pull a request off the controller queue.
 260: 	 */
 261:     if ((dp = sitab.b_actf) == NULL)
 262:         return;
 263:     if ((bp = dp->b_actf) == NULL) {
 264:         sitab.b_actf = dp->b_forw;
 265:         goto loop;
 266:     }
 267:     /*
 268: 	 * Mark controller busy and
 269: 	 * determine destination of this request.
 270: 	 */
 271:     sitab.b_active++;
 272:     unit = minor(bp->b_dev) & 077;
 273:     dn = dkunit(bp->b_dev);
 274:     bn = bp->b_blkno;
 275:     cn = bn / (SI_NSECT * SI_NTRAC) + rm5_sizes[unit & 07].cyloff;
 276:     sn = bn % (SI_NSECT * SI_NTRAC);
 277:     tn = sn / SI_NSECT;
 278:     sn = sn % SI_NSECT;
 279: 
 280:     /*
 281: 	 * Check that drive is ready.
 282: 	 */
 283:     if(dualsi)
 284:         getsi();
 285:     if ((siaddr->sissr >> (dn*4)) & SISSR_NRDY) {
 286:         sitab.b_active = 0;
 287:         sitab.b_errcnt = 0;
 288:         dp->b_actf = bp->av_forw;
 289:         bp->b_flags |= B_ERROR;
 290:         iodone(bp);
 291:         goto loop;
 292:     }
 293: 
 294:     offset = 0;
 295:     if (sitab.b_errcnt >= 16 && (bp->b_flags & B_READ))
 296:         offset = si_offset[sitab.b_errcnt & 1];
 297: 
 298:     siaddr->sipcr = (dn << 10) | cn;
 299:     siaddr->sihsr = (tn << 5) + sn;
 300:     siaddr->simar = bp->b_un.b_addr;
 301:     siaddr->siwcr = bp->b_bcount >> 1;
 302:     /*
 303: 	 * Warning:  unit is being used as a temporary.
 304: 	 */
 305:     unit = offset | ((bp->b_xmem & 3) << 4) | SI_IE | SI_GO;
 306:     if (bp->b_flags & B_READ)
 307:         unit |= SI_READ;
 308:     else
 309:         unit |= SI_WRITE;
 310:     siaddr->sicnr = unit;
 311: 
 312: #ifdef UCB_METER
 313:     if (si_dkn >= 0) {
 314:         int dkn = si_dkn + NSI;
 315: 
 316:         dk_busy |= 1<<dkn;
 317:         dk_seek[dkn]++;
 318:         dk_wds[dkn] += bp->b_bcount >> 6;
 319:     }
 320: #endif
 321: }
 322: 
 323: /*
 324:  * Handle a disk interrupt.
 325:  */
 326: siintr()
 327: {
 328:     register struct sidevice *siaddr = SIADDR;
 329:     register struct buf *dp;
 330:     register unit;
 331:     struct  buf *bp;
 332:     int ss, ssr;
 333: 
 334:     ssr = siaddr->sissr;
 335:     if (sitab.b_active) {
 336: #ifdef UCB_METER
 337:         if (si_dkn >= 0)
 338:             dk_busy &= ~(1 << (si_dkn + NSI));
 339: #endif
 340:         /*
 341: 		 * Get device and block structures.
 342: 		 */
 343:         dp = sitab.b_actf;
 344:         bp = dp->b_actf;
 345:         unit = dkunit(bp->b_dev);
 346:         /*
 347: 		 * Check for and process errors.
 348: 		 */
 349:         if (siaddr->sierr & SIERR_ERR) {
 350:             /*
 351: 			 * After 18 retries (16 without offset and
 352: 			 * 2 with offset positioning), give up.
 353: 			 */
 354:             if (++sitab.b_errcnt > 18) {
 355:                 bp->b_flags |= B_ERROR;
 356:                 harderr(bp, "si");
 357:                 printf("cnr=%b err=%b\n", siaddr->sicnr,
 358:                 SI_BITS, siaddr->sierr, SIERR_BITS);
 359:             } else
 360:                 sitab.b_active = 0;
 361: 
 362:             siaddr->sicnr = SI_RESET;
 363:             if(dualsi)
 364:                 getsi();
 365:             siaddr->sicnr = SI_IE;
 366: 
 367:             sicc[unit] = -1;
 368:         }
 369: 
 370:         if(dualsi)
 371:             SIADDR->siscr = 0;
 372:         if (sitab.b_active) {
 373:             sitab.b_active = 0;
 374:             sitab.b_errcnt = 0;
 375:             sitab.b_actf = dp->b_forw;
 376:             dp->b_active = 0;
 377:             dp->b_actf = bp->av_forw;
 378:             bp->b_resid = ~siaddr->siwcr;
 379:             if (bp->b_resid == 0xffff) bp->b_resid = 0;
 380:             bp->b_resid <<= 1;
 381:             iodone(bp);
 382:             if (dp->b_actf)
 383:                 siustart(unit);
 384:         }
 385:     }
 386: 
 387:     for (unit = 0; unit < NSI; unit++) {
 388:         ss = (ssr >> unit*4) & 017;
 389:         if (ss & (SISSR_BUSY|SISSR_ERR)) {
 390:             harderr(bp, "si");
 391:             printf("ssr=%b err=%b\n", ssr,
 392:                 SISSR_BITS, siaddr->sierr, SIERR_BITS);
 393:             sicc[unit] = -1;
 394:             siustart(unit);
 395:         }
 396:         else if (ss & SISSR_DONE)
 397:             siustart(unit);
 398:     }
 399: 
 400:     sistart();
 401: }
 402: 
 403: #ifdef SI_DUMP
 404: /*
 405:  *  Dump routine for SI 9500
 406:  *  Dumps from dumplo to end of memory/end of disk section for minor(dev).
 407:  */
 408: 
 409: #define DBSIZE  16          /* number of blocks to write */
 410: 
 411: sidump(dev)
 412: dev_t   dev;
 413: {
 414:     register struct sidevice *siaddr = SIADDR;
 415:     daddr_t bn, dumpsize;
 416:     long    paddr;
 417:     register count;
 418:     register struct ubmap *ubp;
 419:     int cn, tn, sn, unit;
 420: 
 421:     unit = minor(dev) >> 3;
 422:     if ((bdevsw[major(dev)].d_strategy != sistrategy)   /* paranoia */
 423:         || unit > NSI)
 424:         return(EINVAL);
 425:     dumpsize = rm5_sizes[dev & 07].nblocks;
 426:     if ((dumplo < 0) || (dumplo >= dumpsize))
 427:         return(EINVAL);
 428:     dumpsize -= dumplo;
 429: 
 430:     /*
 431: 	 * reset the 9500
 432: 	 */
 433:     siaddr->sicnr = SI_RESET;
 434:     ubp = &UBMAP[0];
 435:     for (paddr = 0L; dumpsize > 0; dumpsize -= count) {
 436:         count = dumpsize>DBSIZE? DBSIZE: dumpsize;
 437:         bn = dumplo + (paddr >> PGSHIFT);
 438:         cn = (bn/(SI_NSECT*SI_NTRAC)) + rm5_sizes[minor(dev)&07].cyloff;
 439:         sn = bn % (SI_NSECT * SI_NTRAC);
 440:         tn = sn / SI_NSECT;
 441:         sn = sn % SI_NSECT;
 442:         if(dualsi)
 443:             getsi();
 444:         siaddr->sipcr = (unit << 10) | cn;
 445:         siaddr->sihsr = (tn << 5) + sn;
 446:         siaddr->siwcr = count << (PGSHIFT-1);
 447: 
 448:         if (ubmap) {
 449:             ubp->ub_lo = loint(paddr);
 450:             ubp->ub_hi = hiint(paddr);
 451:             siaddr->simar = 0;
 452:             siaddr->sicnr = SI_WRITE | SI_GO;
 453:         }
 454:         else
 455:             {
 456:             siaddr->simar = loint(paddr);
 457:             siaddr->sicnr = SI_WRITE|SI_GO|((paddr >> 8)&(03 << 4));
 458:         }
 459:         while (!(siaddr->sicnr & SI_DONE))
 460:             ;
 461:         if (siaddr->sierr & SIERR_ERR) {
 462:             if (siaddr->sierr & SIERR_TIMO)
 463:                 return(0);  /* made it to end of memory */
 464:             return(EIO);
 465:         }
 466:         paddr += (DBSIZE << PGSHIFT);
 467:     }
 468:     return(0);      /* filled disk minor dev */
 469: }
 470: #endif SI_DUMP
 471: 
 472: getsi()
 473: {
 474:     register struct sidevice *siaddr = SIADDR;
 475: 
 476:     while(!(siaddr->siscr & 0200))
 477:     {
 478:         siaddr->sicnr = SI_RESET;
 479:         siaddr->siscr = 1;
 480:     }
 481: }
 482: 
 483: /*
 484:  * Simple minded but effective. Likely none of these are still around or in use.
 485: */
 486: daddr_t
 487: sisize(dev)
 488:     dev_t   dev;
 489:     {
 490: 
 491:     return(rm5_sizes[dev & 07].nblocks);
 492:     }
 493: #endif NSI

Defined functions

getsi defined in line 472; used 4 times
siattach defined in line 79; used 1 times
  • in line 76
sidump defined in line 411; never used
siintr defined in line 326; used 1 times
siopen defined in line 105; never used
siroot defined in line 73; never used
sisize defined in line 486; never used
sistart defined in line 247; used 2 times
sistrategy defined in line 117; used 1 times
siustart defined in line 165; used 4 times

Defined variables

SIADDR defined in line 59; used 11 times
dualsi defined in line 67; used 8 times
rm5_sizes declared in line 37; defined in line 47; used 12 times
si_dkn defined in line 70; used 12 times
si_offset defined in line 61; used 1 times
sicc defined in line 66; used 4 times
sitab defined in line 63; used 20 times
siutab defined in line 64; used 2 times

Defined struct's

size defined in line 44; never used

Defined macros

DBSIZE defined in line 409; used 3 times
SI_NSECT defined in line 30; used 12 times
SI_NTRAC defined in line 31; used 6 times
Last modified: 1995-04-14
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4332
Valid CSS Valid XHTML 1.0 Strict