void statement(int loop, Swtch swp, int lev) { float ref = refinc; if (Aflag >= 2 && lev == 15) warning("more than 15 levels of nested statements\n"); switch (t) { case IF: ifstmt(genlabel(2), loop, swp, lev + 1); break; case WHILE: whilestmt(genlabel(3), swp, lev + 1); break; case DO: dostmt(genlabel(3), swp, lev + 1); expect(';'); break; case FOR: forstmt(genlabel(4), swp, lev + 1); break; case BREAK: walk(NULL, 0, 0); definept(NULL); if (swp && swp->lab > loop) branch(swp->lab + 1); else if (loop) branch(loop + 2); else error("illegal break statement\n"); t = gettok(); expect(';'); break; case CONTINUE: walk(NULL, 0, 0); definept(NULL); if (loop) branch(loop + 1); else error("illegal continue statement\n"); t = gettok(); expect(';'); break; case SWITCH: swstmt(loop, genlabel(2), lev + 1); break; case CASE: { int lab = genlabel(1); if (swp == NULL) error("illegal case label\n"); definelab(lab); while (t == CASE) { static char stop[] = { IF, ID, 0 }; Tree p; t = gettok(); p = constexpr(0); if (generic(p->op) == CNST && isint(p->type)) { if (swp) { needconst++; p = cast(p, swp->sym->type); if (p->type->op == UNSIGNED) p->u.v.i = extend(p->u.v.u, p->type); needconst--; caselabel(swp, p->u.v.i, lab); } } else error("case label must be a constant integer expression\n"); test(':', stop); } statement(loop, swp, lev); } break; case DEFAULT: if (swp == NULL) error("illegal default label\n"); else if (swp->deflab) error("extra default label\n"); else { swp->deflab = findlabel(swp->lab); definelab(swp->deflab->u.l.label); } t = gettok(); expect(':'); statement(loop, swp, lev); break; case RETURN: { Type rty = freturn(cfunc->type); t = gettok(); definept(NULL); if (t != ';') if (rty == voidtype) { error("extraneous return value\n"); expr(0); retcode(NULL); } else retcode(expr(0)); else { if (rty != voidtype) warning("missing return value\n"); retcode(NULL); } branch(cfunc->u.f.label); } expect(';'); break; case '{': compound(loop, swp, lev + 1); break; case ';': definept(NULL); t = gettok(); break; case GOTO: walk(NULL, 0, 0); definept(NULL); t = gettok(); if (t == ID) { Symbol p = lookup(token, stmtlabs); if (p == NULL) { p = install(token, &stmtlabs, 0, FUNC); p->scope = LABELS; p->u.l.label = genlabel(1); p->src = src; } use(p, src); branch(p->u.l.label); t = gettok(); } else error("missing label in goto\n"); expect(';'); break; case ID: if (getchr() == ':') { stmtlabel(); statement(loop, swp, lev); break; } default: definept(NULL); if (kind[t] != ID) { error("unrecognized statement\n"); t = gettok(); } else { Tree e = expr0(0); listnodes(e, 0, 0); if (nodecount == 0 || nodecount > 200) walk(NULL, 0, 0); else if (glevel) walk(NULL, 0, 0); deallocate(STMT); } expect(';'); break; } if (kind[t] != IF && kind[t] != ID && t != '}' && t != EOI) { static char stop[] = { IF, ID, '}', 0 }; error("illegal statement termination\n"); skipto(0, stop); } refinc = ref; }
static int internal_command(unsigned char target, unsigned char lun, const void *cmnd, void *buff, int bufflen, int reselect) { int len = 0; unsigned char *data = NULL; struct scatterlist *buffer = NULL; int nobuffs = 0; int clock; int temp; #ifdef SLOW_HANDSHAKE int borken; /* Does the current target require Very Slow I/O ? */ #endif #if (DEBUG & PHASE_DATAIN) || (DEBUG & PHASE_DATOUT) int transfered = 0; #endif #if (((DEBUG & PHASE_ETC) == PHASE_ETC) || (DEBUG & PRINT_COMMAND) || \ (DEBUG & PHASE_EXIT)) int i; #endif #if ((DEBUG & PHASE_ETC) == PHASE_ETC) int phase=0, newphase; #endif int done = 0; unsigned char status = 0; unsigned char message = 0; register unsigned char status_read; unsigned transfersize = 0, underflow = 0; incommand = 0; st0x_aborted = 0; #ifdef SLOW_HANDSHAKE borken = (int) SCint->device->borken; #endif #if (DEBUG & PRINT_COMMAND) printk ("scsi%d : target = %d, command = ", hostno, target); print_command((unsigned char *) cmnd); printk("\n"); #endif #if (DEBUG & PHASE_RESELECT) switch (reselect) { case RECONNECT_NOW : printk("scsi%d : reconnecting\n", hostno); break; #ifdef LINKED case LINKED_RIGHT : printk("scsi%d : connected, can reconnect\n", hostno); break; case LINKED_WRONG : printk("scsi%d : connected to wrong target, can reconnect\n", hostno); break; #endif case CAN_RECONNECT : printk("scsi%d : allowed to reconnect\n", hostno); break; default : printk("scsi%d : not allowed to reconnect\n", hostno); } #endif if (target == (controller_type == SEAGATE ? 7 : 6)) return DID_BAD_TARGET; /* * We work it differently depending on if this is "the first time," * or a reconnect. If this is a reselect phase, then SEL will * be asserted, and we must skip selection / arbitration phases. */ switch (reselect) { case RECONNECT_NOW: #if (DEBUG & PHASE_RESELECT) printk("scsi%d : phase RESELECT \n", hostno); #endif /* * At this point, we should find the logical or of our ID and the original * target's ID on the BUS, with BSY, SEL, and I/O signals asserted. * * After ARBITRATION phase is completed, only SEL, BSY, and the * target ID are asserted. A valid initiator ID is not on the bus * until IO is asserted, so we must wait for that. */ clock = jiffies + 10; for (;;) { temp = STATUS; if ((temp & STAT_IO) && !(temp & STAT_BSY)) break; if (jiffies > clock) { #if (DEBUG & PHASE_RESELECT) printk("scsi%d : RESELECT timed out while waiting for IO .\n", hostno); #endif return (DID_BAD_INTR << 16); } } /* * After I/O is asserted by the target, we can read our ID and its * ID off of the BUS. */ if (!((temp = DATA) & (controller_type == SEAGATE ? 0x80 : 0x40))) { #if (DEBUG & PHASE_RESELECT) printk("scsi%d : detected reconnect request to different target.\n" "\tData bus = %d\n", hostno, temp); #endif return (DID_BAD_INTR << 16); } if (!(temp & (1 << current_target))) { printk("scsi%d : Unexpected reselect interrupt. Data bus = %d\n", hostno, temp); return (DID_BAD_INTR << 16); } buffer=current_buffer; cmnd=current_cmnd; /* WDE add */ data=current_data; /* WDE add */ len=current_bufflen; /* WDE add */ nobuffs=current_nobuffs; /* * We have determined that we have been selected. At this point, * we must respond to the reselection by asserting BSY ourselves */ #if 1 CONTROL = (BASE_CMD | CMD_DRVR_ENABLE | CMD_BSY); #else CONTROL = (BASE_CMD | CMD_BSY); #endif /* * The target will drop SEL, and raise BSY, at which time we must drop * BSY. */ for (clock = jiffies + 10; (jiffies < clock) && (STATUS & STAT_SEL);); if (jiffies >= clock) { CONTROL = (BASE_CMD | CMD_INTR); #if (DEBUG & PHASE_RESELECT) printk("scsi%d : RESELECT timed out while waiting for SEL.\n", hostno); #endif return (DID_BAD_INTR << 16); } CONTROL = BASE_CMD; /* * At this point, we have connected with the target and can get * on with our lives. */ break; case CAN_RECONNECT: #ifdef LINKED /* * This is a bletcherous hack, just as bad as the Unix #! interpreter stuff. * If it turns out we are using the wrong I_T_L nexus, the easiest way to deal * with it is to go into our INFORMATION TRANSFER PHASE code, send a ABORT * message on MESSAGE OUT phase, and then loop back to here. */ connect_loop : #endif #if (DEBUG & PHASE_BUS_FREE) printk ("scsi%d : phase = BUS FREE \n", hostno); #endif /* * BUS FREE PHASE * * On entry, we make sure that the BUS is in a BUS FREE * phase, by insuring that both BSY and SEL are low for * at least one bus settle delay. Several reads help * eliminate wire glitch. */ clock = jiffies + ST0X_BUS_FREE_DELAY; #if !defined (ARBITRATE) while (((STATUS | STATUS | STATUS) & (STAT_BSY | STAT_SEL)) && (!st0x_aborted) && (jiffies < clock)); if (jiffies > clock) return retcode(DID_BUS_BUSY); else if (st0x_aborted) return retcode(st0x_aborted); #endif #if (DEBUG & PHASE_SELECTION) printk("scsi%d : phase = SELECTION\n", hostno); #endif clock = jiffies + ST0X_SELECTION_DELAY; /* * Arbitration/selection procedure : * 1. Disable drivers * 2. Write HOST adapter address bit * 3. Set start arbitration. * 4. We get either ARBITRATION COMPLETE or SELECT at this * point. * 5. OR our ID and targets on bus. * 6. Enable SCSI drivers and asserted SEL and ATTN */ #if defined(ARBITRATE) cli(); CONTROL = 0; DATA = (controller_type == SEAGATE) ? 0x80 : 0x40; CONTROL = CMD_START_ARB; sti(); while (!((status_read = STATUS) & (STAT_ARB_CMPL | STAT_SEL)) && (jiffies < clock) && !st0x_aborted); if (!(status_read & STAT_ARB_CMPL)) { #if (DEBUG & PHASE_SELECTION) if (status_read & STAT_SEL) printk("scsi%d : arbitration lost\n", hostno); else printk("scsi%d : arbitration timeout.\n", hostno); #endif CONTROL = BASE_CMD; return retcode(DID_NO_CONNECT); }; #if (DEBUG & PHASE_SELECTION) printk("scsi%d : arbitration complete\n", hostno); #endif #endif /* * When the SCSI device decides that we're gawking at it, it will * respond by asserting BUSY on the bus. * * Note : the Seagate ST-01/02 product manual says that we should * twiddle the DATA register before the control register. However, * this does not work reliably so we do it the other way around. * * Probably could be a problem with arbitration too, we really should * try this with a SCSI protocol or logic analyzer to see what is * going on. */ cli(); DATA = (unsigned char) ((1 << target) | (controller_type == SEAGATE ? 0x80 : 0x40)); CONTROL = BASE_CMD | CMD_DRVR_ENABLE | CMD_SEL | (reselect ? CMD_ATTN : 0); sti(); while (!((status_read = STATUS) & STAT_BSY) && (jiffies < clock) && !st0x_aborted) #if 0 && (DEBUG & PHASE_SELECTION) { temp = clock - jiffies; if (!(jiffies % 5)) printk("seagate_st0x_timeout : %d \r",temp); } printk("Done. \n"); printk("scsi%d : status = %02x, seagate_st0x_timeout = %d, aborted = %02x \n", hostno, status_read, temp, st0x_aborted); #else ; #endif if ((jiffies >= clock) && !(status_read & STAT_BSY)) { #if (DEBUG & PHASE_SELECTION) printk ("scsi%d : NO CONNECT with target %d, status = %x \n", hostno, target, STATUS); #endif return retcode(DID_NO_CONNECT); } /* * If we have been aborted, and we have a command in progress, IE the * target still has BSY asserted, then we will reset the bus, and * notify the midlevel driver to expect sense. */ if (st0x_aborted) { CONTROL = BASE_CMD; if (STATUS & STAT_BSY) { printk("scsi%d : BST asserted after we've been aborted.\n", hostno); seagate_st0x_reset(NULL, 0); return retcode(DID_RESET); } return retcode(st0x_aborted); } /* Establish current pointers. Take into account scatter / gather */ if ((nobuffs = SCint->use_sg)) { #if (DEBUG & DEBUG_SG) { int i; printk("scsi%d : scatter gather requested, using %d buffers.\n", hostno, nobuffs); for (i = 0; i < nobuffs; ++i) printk("scsi%d : buffer %d address = %08x length = %d\n", hostno, i, buffer[i].address, buffer[i].length); } #endif buffer = (struct scatterlist *) SCint->buffer; len = buffer->length; data = (unsigned char *) buffer->address; } else { #if (DEBUG & DEBUG_SG) printk("scsi%d : scatter gather not requested.\n", hostno); #endif buffer = NULL; len = SCint->request_bufflen; data = (unsigned char *) SCint->request_buffer; } #if (DEBUG & (PHASE_DATAIN | PHASE_DATAOUT)) printk("scsi%d : len = %d\n", hostno, len); #endif break; #ifdef LINKED case LINKED_RIGHT: break; case LINKED_WRONG: break; #endif } /* * There are several conditions under which we wish to send a message : * 1. When we are allowing disconnect / reconnect, and need to establish * the I_T_L nexus via an IDENTIFY with the DiscPriv bit set. * * 2. When we are doing linked commands, are have the wrong I_T_L nexus * established and want to send an ABORT message. */ CONTROL = BASE_CMD | CMD_DRVR_ENABLE | (((reselect == CAN_RECONNECT) #ifdef LINKED || (reselect == LINKED_WRONG) #endif ) ? CMD_ATTN : 0) ; /* * INFORMATION TRANSFER PHASE * * The nasty looking read / write inline assembler loops we use for * DATAIN and DATAOUT phases are approximately 4-5 times as fast as * the 'C' versions - since we're moving 1024 bytes of data, this * really adds up. */ #if ((DEBUG & PHASE_ETC) == PHASE_ETC) printk("scsi%d : phase = INFORMATION TRANSFER\n", hostno); #endif incommand = 1; transfersize = SCint->transfersize; underflow = SCint->underflow; /* * Now, we poll the device for status information, * and handle any requests it makes. Note that since we are unsure of * how much data will be flowing across the system, etc and cannot * make reasonable timeouts, that we will instead have the midlevel * driver handle any timeouts that occur in this phase. */ while (((status_read = STATUS) & STAT_BSY) && !st0x_aborted && !done) { #ifdef PARITY if (status_read & STAT_PARITY) { printk("scsi%d : got parity error\n", hostno); st0x_aborted = DID_PARITY; } #endif if (status_read & STAT_REQ) { #if ((DEBUG & PHASE_ETC) == PHASE_ETC) if ((newphase = (status_read & REQ_MASK)) != phase) { phase = newphase; switch (phase) { case REQ_DATAOUT: printk("scsi%d : phase = DATA OUT\n", hostno); break; case REQ_DATAIN : printk("scsi%d : phase = DATA IN\n", hostno); break; case REQ_CMDOUT : printk("scsi%d : phase = COMMAND OUT\n", hostno); break; case REQ_STATIN : printk("scsi%d : phase = STATUS IN\n", hostno); break; case REQ_MSGOUT : printk("scsi%d : phase = MESSAGE OUT\n", hostno); break; case REQ_MSGIN : printk("scsi%d : phase = MESSAGE IN\n", hostno); break; default : printk("scsi%d : phase = UNKNOWN\n", hostno); st0x_aborted = DID_ERROR; } } #endif switch (status_read & REQ_MASK) { case REQ_DATAOUT : /* * If we are in fast mode, then we simply splat the data out * in word-sized chunks as fast as we can. */ #ifdef FAST if (!len) { #if 0 printk("scsi%d: underflow to target %d lun %d \n", hostno, target, lun); st0x_aborted = DID_ERROR; fast = 0; #endif break; } if (fast && transfersize && !(len % transfersize) && (len >= transfersize) #ifdef FAST32 && !(transfersize % 4) #endif ) { #if (DEBUG & DEBUG_FAST) printk("scsi%d : FAST transfer, underflow = %d, transfersize = %d\n" " len = %d, data = %08x\n", hostno, SCint->underflow, SCint->transfersize, len, data); #endif { #ifdef FAST32 unsigned int *iop = phys_to_virt (st0x_dr); const unsigned int *dp = (unsigned int *) data; int xferlen = transfersize >> 2; #else unsigned char *iop = phys_to_virt (st0x_dr); const unsigned char *dp = data; int xferlen = transfersize; #endif for (; xferlen; --xferlen) *iop = *dp++; } len -= transfersize; data += transfersize; #if (DEBUG & DEBUG_FAST) printk("scsi%d : FAST transfer complete len = %d data = %08x\n", hostno, len, data); #endif } else #endif { /* * We loop as long as we are in a data out phase, there is data to send, * and BSY is still active. */ while (len) { unsigned char stat; stat = STATUS; if (!(stat & STAT_BSY) || ((stat & REQ_MASK) != REQ_DATAOUT)) break; if (stat & STAT_REQ) { WRITE_DATA (*data++); --len; } } } if (!len && nobuffs) { --nobuffs; ++buffer; len = buffer->length; data = (unsigned char *) buffer->address; #if (DEBUG & DEBUG_SG) printk("scsi%d : next scatter-gather buffer len = %d address = %08x\n", hostno, len, data); #endif } break; case REQ_DATAIN : #ifdef SLOW_HANDSHAKE if (borken) { #if (DEBUG & (PHASE_DATAIN)) transfered += len; #endif for (; len && (STATUS & (REQ_MASK | STAT_REQ)) == (REQ_DATAIN | STAT_REQ); --len) { *data++ = DATA; borken_wait(); } #if (DEBUG & (PHASE_DATAIN)) transfered -= len; #endif } else #endif #ifdef FAST if (fast && transfersize && !(len % transfersize) && (len >= transfersize) #ifdef FAST32 && !(transfersize % 4) #endif ) { #if (DEBUG & DEBUG_FAST) printk("scsi%d : FAST transfer, underflow = %d, transfersize = %d\n" " len = %d, data = %08x\n", hostno, SCint->underflow, SCint->transfersize, len, data); #endif { #ifdef FAST32 const unsigned int *iop = phys_to_virt (st0x_dr); unsigned int *dp = (unsigned int *) data; int xferlen = len >> 2; #else const unsigned char *iop = phys_to_virt (st0x_dr); unsigned char *dp = data; int xferlen = len; #endif for (; xferlen; --xferlen) *dp++ = *iop; } len -= transfersize; data += transfersize; #if (DEBUG & PHASE_DATAIN) printk("scsi%d: transfered += %d\n", hostno, transfersize); transfered += transfersize; #endif #if (DEBUG & DEBUG_FAST) printk("scsi%d : FAST transfer complete len = %d data = %08x\n", hostno, len, data); #endif } else #endif {