|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1991,1990 Carnegie Mellon University ! 4: * All Rights Reserved. ! 5: * ! 6: * Permission to use, copy, modify and distribute this software and its ! 7: * documentation is hereby granted, provided that both the copyright ! 8: * notice and this permission notice appear in all copies of the ! 9: * software, derivative works or modified versions, and any portions ! 10: * thereof, and that both notices appear in supporting documentation. ! 11: * ! 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 15: * ! 16: * Carnegie Mellon requests users of this software to return to ! 17: * ! 18: * Software Distribution Coordinator or [email protected] ! 19: * School of Computer Science ! 20: * Carnegie Mellon University ! 21: * Pittsburgh PA 15213-3890 ! 22: * ! 23: * any improvements or extensions that they make and grant Carnegie Mellon ! 24: * the rights to redistribute these changes. ! 25: */ ! 26: /* ! 27: * File: rz_cpu.c ! 28: * Author: Alessandro Forin, Carnegie Mellon University ! 29: * Date: 7/91 ! 30: * ! 31: * Top layer of the SCSI driver: interface with the MI. ! 32: * This file contains operations specific to CPU-like devices. ! 33: * ! 34: * We handle here the case of simple devices which do not use any ! 35: * sophisticated host-to-host communication protocol, they look ! 36: * very much like degenerative cases of TAPE devices. ! 37: * ! 38: * For documentation and debugging, we also provide code to act like one. ! 39: */ ! 40: ! 41: #include <mach/std_types.h> ! 42: #include <scsi/compat_30.h> ! 43: ! 44: #include <scsi/scsi.h> ! 45: #include <scsi/scsi_defs.h> ! 46: #include <scsi/rz.h> ! 47: ! 48: #if (NSCSI > 0) ! 49: ! 50: void sccpu_act_as_target(); /* forwards */ ! 51: void sccpu_start(); ! 52: ! 53: /* ! 54: * This function decides which 'protocol' we well speak ! 55: * to a cpu target. For now the decision is left to a ! 56: * global var. XXXXXXX ! 57: */ ! 58: extern scsi_devsw_t scsi_host; ! 59: scsi_devsw_t *scsi_cpu_protocol = /* later &scsi_host*/ ! 60: &scsi_devsw[SCSI_CPU]; ! 61: ! 62: void sccpu_new_initiator(self, initiator) ! 63: target_info_t *self, *initiator; ! 64: { ! 65: initiator->dev_ops = scsi_cpu_protocol; ! 66: if (initiator == self) { ! 67: self->flags = TGT_DID_SYNCH|TGT_FULLY_PROBED|TGT_ONLINE| ! 68: TGT_ALIVE|TGT_US; ! 69: self->dev_info.cpu.req_pending = FALSE; ! 70: } else { ! 71: initiator->flags = TGT_ONLINE|TGT_ALIVE; ! 72: initiator->dev_info.cpu.req_pending = TRUE; ! 73: } ! 74: } ! 75: ! 76: void sccpu_strategy(ior) ! 77: register io_req_t ior; ! 78: { ! 79: void sccpu_start(); ! 80: ! 81: rz_simpleq_strategy(ior, sccpu_start); ! 82: } ! 83: ! 84: void sccpu_start(tgt, done) ! 85: target_info_t *tgt; ! 86: boolean_t done; ! 87: { ! 88: io_req_t head, ior; ! 89: scsi_ret_t ret; ! 90: ! 91: /* this is to the doc & debug code mentioned in the beginning */ ! 92: if (!done && tgt->dev_info.cpu.req_pending) { ! 93: panic("sccpu_act_as_target called"); ! 94: #if 0 ! 95: sccpu_act_as_target( tgt); ! 96: #endif ! 97: return; ! 98: } ! 99: ! 100: ior = tgt->ior; ! 101: if (ior == 0) ! 102: return; ! 103: ! 104: if (done) { ! 105: ! 106: /* see if we must retry */ ! 107: if ((tgt->done == SCSI_RET_RETRY) && ! 108: ((ior->io_op & IO_INTERNAL) == 0)) { ! 109: delay(1000000);/*XXX*/ ! 110: goto start; ! 111: } else ! 112: /* got a bus reset ? shouldn't matter */ ! 113: if ((tgt->done == (SCSI_RET_ABORTED|SCSI_RET_RETRY)) && ! 114: ((ior->io_op & IO_INTERNAL) == 0)) { ! 115: goto start; ! 116: } else ! 117: ! 118: /* check completion status */ ! 119: ! 120: if (tgt->cur_cmd == SCSI_CMD_REQUEST_SENSE) { ! 121: scsi_sense_data_t *sns; ! 122: ! 123: ior->io_op = ior->io_temporary; ! 124: ior->io_error = D_IO_ERROR; ! 125: ior->io_op |= IO_ERROR; ! 126: ! 127: sns = (scsi_sense_data_t *)tgt->cmd_ptr; ! 128: if (scsi_debug) ! 129: scsi_print_sense_data(sns); ! 130: ! 131: if (scsi_check_sense_data(tgt, sns)) { ! 132: if (sns->u.xtended.ili) { ! 133: if (ior->io_op & IO_READ) { ! 134: int residue; ! 135: ! 136: residue = sns->u.xtended.info0 << 24 | ! 137: sns->u.xtended.info1 << 16 | ! 138: sns->u.xtended.info2 << 8 | ! 139: sns->u.xtended.info3; ! 140: if (scsi_debug) ! 141: printf("Cpu Short Read (%d)\n", residue); ! 142: /* ! 143: * NOTE: residue == requested - actual ! 144: * We only care if > 0 ! 145: */ ! 146: if (residue < 0) residue = 0;/* sanity */ ! 147: ior->io_residual += residue; ! 148: ior->io_error = 0; ! 149: ior->io_op &= ~IO_ERROR; ! 150: /* goto ok */ ! 151: } ! 152: } ! 153: } ! 154: } ! 155: ! 156: else if (tgt->done != SCSI_RET_SUCCESS) { ! 157: ! 158: if (tgt->done == SCSI_RET_NEED_SENSE) { ! 159: ! 160: ior->io_temporary = ior->io_op; ! 161: ior->io_op = IO_INTERNAL; ! 162: if (scsi_debug) ! 163: printf("[NeedSns x%x x%x]", ior->io_residual, ior->io_count); ! 164: scsi_request_sense(tgt, ior, 0); ! 165: return; ! 166: ! 167: } else if (tgt->done == SCSI_RET_RETRY) { ! 168: /* only retry here READs and WRITEs */ ! 169: if ((ior->io_op & IO_INTERNAL) == 0) { ! 170: ior->io_residual = 0; ! 171: goto start; ! 172: } else{ ! 173: ior->io_error = D_WOULD_BLOCK; ! 174: ior->io_op |= IO_ERROR; ! 175: } ! 176: } else { ! 177: ior->io_error = D_IO_ERROR; ! 178: ior->io_op |= IO_ERROR; ! 179: } ! 180: } ! 181: ! 182: if (scsi_debug) ! 183: printf("[Resid x%x]", ior->io_residual); ! 184: ! 185: /* dequeue next one */ ! 186: head = ior; ! 187: ! 188: simple_lock(&tgt->target_lock); ! 189: ior = head->io_next; ! 190: tgt->ior = ior; ! 191: if (ior) ! 192: ior->io_prev = head->io_prev; ! 193: simple_unlock(&tgt->target_lock); ! 194: ! 195: iodone(head); ! 196: ! 197: if (ior == 0) ! 198: return; ! 199: } ! 200: ior->io_residual = 0; ! 201: start: ! 202: if (ior->io_op & IO_READ) { ! 203: ret = scsi_receive( tgt, ior ); ! 204: } else if ((ior->io_op & IO_INTERNAL) == 0) { ! 205: ret = scsi_send( tgt, ior ); ! 206: } ! 207: } ! 208: ! 209: ! 210: #if 0 ! 211: /* XX turned off this code because it's impossible ! 212: to reference 'end' and other such magic symbols ! 213: from boot modules. */ ! 214: /* ! 215: * This is a simple code to make us act as a dumb ! 216: * processor type. Use for debugging only. ! 217: */ ! 218: static struct io_req sccpu_ior; ! 219: vm_offset_t sccpu_buffer; /* set this with debugger */ ! 220: ! 221: void sccpu_act_as_target(self) ! 222: target_info_t *self; ! 223: { ! 224: static char inq_data[] = "\3\0\1\0\040\0\0\0Mach3.0 Processor Link v0.1"; ! 225: static char sns_data[] = "\160\0\0\0\0\0\0\0\0"; ! 226: ! 227: self->dev_info.cpu.req_pending = FALSE; ! 228: sccpu_ior.io_next = 0; ! 229: #define MAXSIZE 1024*64 ! 230: sccpu_ior.io_count = (MAXSIZE < self->dev_info.cpu.req_len) ? ! 231: MAXSIZE : self->dev_info.cpu.req_len; ! 232: ! 233: switch (self->dev_info.cpu.req_cmd) { ! 234: case SCSI_CMD_INQUIRY: ! 235: sccpu_ior.io_data = inq_data; break; ! 236: case SCSI_CMD_REQUEST_SENSE: ! 237: sccpu_ior.io_data = sns_data; break; ! 238: default: ! 239: if (sccpu_buffer == 0) { ! 240: /* ( read my lips :-) */ ! 241: /* extern char end[]; */ ! 242: sccpu_buffer = trunc_page(kalloc(MAXSIZE)); ! 243: } ! 244: sccpu_ior.io_data = (char*)sccpu_buffer; break; ! 245: } ! 246: ! 247: if (self->dev_info.cpu.req_cmd == SCSI_CMD_SEND) { ! 248: self->cur_cmd = SCSI_CMD_READ; ! 249: sccpu_ior.io_op = IO_READ; ! 250: } else { ! 251: self->cur_cmd = SCSI_CMD_WRITE; ! 252: sccpu_ior.io_op = IO_WRITE; ! 253: } ! 254: self->ior = &sccpu_ior; ! 255: } ! 256: #endif ! 257: ! 258: /*#define PERF*/ ! 259: #ifdef PERF ! 260: int test_read_size = 512; ! 261: int test_read_nreads = 1000; ! 262: int test_read_bdev = 0; ! 263: int test_read_or_write = 1; ! 264: ! 265: #include <sys/time.h> ! 266: #include <machine/machspl.h> /* spl */ ! 267: ! 268: test_read(max) ! 269: { ! 270: int i, ssk, usecs; ! 271: struct timeval start, stop; ! 272: spl_t s; ! 273: ! 274: if (max != 0) ! 275: test_read_nreads = max; ! 276: ! 277: s = spl0(); ! 278: start = time; ! 279: if (test_read_or_write) read_test(); else write_test(); ! 280: stop = time; ! 281: splx(s); ! 282: ! 283: usecs = stop.tv_usec - start.tv_usec; ! 284: if (usecs < 0) { ! 285: stop.tv_sec -= 1; ! 286: usecs += 1000000; ! 287: } ! 288: printf("Size %d count %d time %3d sec %d us\n", ! 289: test_read_size, test_read_nreads, ! 290: stop.tv_sec - start.tv_sec, usecs); ! 291: } ! 292: ! 293: read_test() ! 294: { ! 295: struct io_req io, io1; ! 296: register int i; ! 297: ! 298: bzero(&io, sizeof(io)); ! 299: io.io_unit = test_read_bdev; ! 300: io.io_op = IO_READ; ! 301: io.io_count = test_read_size; ! 302: io.io_data = (char*)sccpu_buffer; ! 303: io1 = io; ! 304: ! 305: sccpu_strategy(&io); ! 306: for (i = 1; i < test_read_nreads; i += 2) { ! 307: io1.io_op = IO_READ; ! 308: sccpu_strategy(&io1); ! 309: iowait(&io); ! 310: io.io_op = IO_READ; ! 311: sccpu_strategy(&io); ! 312: iowait(&io1); ! 313: } ! 314: iowait(&io); ! 315: } ! 316: ! 317: write_test() ! 318: { ! 319: struct io_req io, io1; ! 320: register int i; ! 321: ! 322: bzero(&io, sizeof(io)); ! 323: io.io_unit = test_read_bdev; ! 324: io.io_op = IO_WRITE; ! 325: io.io_count = test_read_size; ! 326: io.io_data = (char*)sccpu_buffer; ! 327: io1 = io; ! 328: ! 329: sccpu_strategy(&io); ! 330: for (i = 1; i < test_read_nreads; i += 2) { ! 331: io1.io_op = IO_WRITE; ! 332: sccpu_strategy(&io1); ! 333: iowait(&io); ! 334: io.io_op = IO_WRITE; ! 335: sccpu_strategy(&io); ! 336: iowait(&io1); ! 337: } ! 338: iowait(&io); ! 339: } ! 340: ! 341: tur_test() ! 342: { ! 343: struct io_req io; ! 344: register int i; ! 345: char *a; ! 346: struct timeval start, stop; ! 347: spl_t s; ! 348: target_info_t *tgt; ! 349: ! 350: bzero(&io, sizeof(io)); ! 351: io.io_unit = test_read_bdev; ! 352: io.io_data = (char*)&io;/*unused but kernel space*/ ! 353: ! 354: rz_check(io.io_unit, &a, &tgt); ! 355: s = spl0(); ! 356: start = time; ! 357: for (i = 0; i < test_read_nreads; i++) { ! 358: io.io_op = IO_INTERNAL; ! 359: scsi_test_unit_ready(tgt,&io); ! 360: } ! 361: stop = time; ! 362: splx(s); ! 363: i = stop.tv_usec - start.tv_usec; ! 364: if (i < 0) { ! 365: stop.tv_sec -= 1; ! 366: i += 1000000; ! 367: } ! 368: printf("%d test-unit-ready took %3d sec %d us\n", ! 369: test_read_nreads, ! 370: stop.tv_sec - start.tv_sec, i); ! 371: } ! 372: ! 373: /*#define MEM_PERF*/ ! 374: #ifdef MEM_PERF ! 375: int mem_read_size = 1024; /* ints! */ ! 376: int mem_read_nreads = 1000; ! 377: volatile int *mem_read_address = (volatile int*)0xb0080000; ! 378: volatile int *mem_write_address = (volatile int*)0xb0081000; ! 379: ! 380: mem_test(max, which) ! 381: { ! 382: int i, ssk, usecs; ! 383: struct timeval start, stop; ! 384: int (*fun)(), mwrite_test(), mread_test(), mcopy_test(); ! 385: spl_t s; ! 386: ! 387: if (max == 0) ! 388: max = mem_read_nreads; ! 389: ! 390: switch (which) { ! 391: case 1: fun = mwrite_test; break; ! 392: case 2: fun = mcopy_test; break; ! 393: default:fun = mread_test; break; ! 394: } ! 395: ! 396: s = spl0(); ! 397: start = time; ! 398: for (i = 0; i < max; i++) ! 399: (*fun)(mem_read_size); ! 400: stop = time; ! 401: splx(s); ! 402: ! 403: usecs = stop.tv_usec - start.tv_usec; ! 404: if (usecs < 0) { ! 405: stop.tv_sec -= 1; ! 406: usecs += 1000000; ! 407: } ! 408: printf("Size %d count %d time %3d sec %d us\n", ! 409: mem_read_size*4, max, ! 410: stop.tv_sec - start.tv_sec, usecs); ! 411: } ! 412: ! 413: mread_test(max) ! 414: register int max; ! 415: { ! 416: register int i; ! 417: register volatile int *addr = mem_read_address; ! 418: ! 419: for (i = 0; i < max; i++) { ! 420: register int j = *addr++; ! 421: } ! 422: } ! 423: mwrite_test(max) ! 424: register int max; ! 425: { ! 426: register int i; ! 427: register volatile int *addr = mem_read_address; ! 428: ! 429: for (i = 0; i < max; i++) { ! 430: *addr++ = i; ! 431: } ! 432: } ! 433: ! 434: mcopy_test(max) ! 435: register int max; ! 436: { ! 437: register volatile int *from = mem_read_address; ! 438: register volatile int *to = mem_write_address; ! 439: register volatile int *endaddr; ! 440: ! 441: endaddr = to + max; ! 442: while (to < endaddr) ! 443: *to++ = *from++; ! 444: ! 445: } ! 446: #endif /*MEM_PERF*/ ! 447: ! 448: #endif /*PERF*/ ! 449: ! 450: #endif /* NSCSI > 0 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.