/* * ppb_MS_loop() * * Execute a microseq loop * */ int ppb_MS_loop(device_t bus, device_t dev, struct ppb_microseq *prolog, struct ppb_microseq *body, struct ppb_microseq *epilog, int iter, int *ret) { struct ppb_microseq loop_microseq[] = { MS_CALL(0), /* execute prolog */ MS_SET(MS_UNKNOWN), /* set size of transfer */ /* loop: */ MS_CALL(0), /* execute body */ MS_DBRA(-1 /* loop: */), MS_CALL(0), /* execute epilog */ MS_RET(0) }; /* initialize the structure */ loop_microseq[0].arg[0].p = (void *)prolog; loop_microseq[1].arg[0].i = iter; loop_microseq[2].arg[0].p = (void *)body; loop_microseq[4].arg[0].p = (void *)epilog; /* execute the loop */ return (ppb_MS_microseq(bus, dev, loop_microseq, ret)); }
static char vpoio_select(struct vpoio_data *vpo, int initiator, int target) { device_t ppbus = device_get_parent(vpo->vpo_dev); int ret; struct ppb_microseq select_microseq[] = { /* parameter list */ #define SELECT_TARGET MS_PARAM(0, 1, MS_TYP_INT) #define SELECT_INITIATOR MS_PARAM(3, 1, MS_TYP_INT) /* send the select command to the drive */ MS_DASS(MS_UNKNOWN), MS_CASS(H_nAUTO | H_nSELIN | H_INIT | H_STROBE), MS_CASS( H_AUTO | H_nSELIN | H_INIT | H_STROBE), MS_DASS(MS_UNKNOWN), MS_CASS( H_AUTO | H_nSELIN | H_nINIT | H_STROBE), /* now, wait until the drive is ready */ MS_SET(VP0_SELTMO), /* loop: */ MS_BRSET(H_ACK, 2 /* ready */), MS_DBRA(-2 /* loop */), /* error: */ MS_RET(1), /* ready: */ MS_RET(0) }; /* initialize the select microsequence */ ppb_MS_init_msq(select_microseq, 2, SELECT_TARGET, 1 << target, SELECT_INITIATOR, 1 << initiator); ppb_MS_microseq(ppbus, vpo->vpo_dev, select_microseq, &ret); if (ret) return (VP0_ESELECT_TIMEOUT); return (0); }
/* * ppb_MS_exec() * * Execute any microsequence opcode - expensive * */ int ppb_MS_exec(device_t bus, device_t dev, int opcode, union ppb_insarg param1, union ppb_insarg param2, union ppb_insarg param3, int *ret) { struct ppb_microseq msq[] = { { MS_UNKNOWN, { { MS_UNKNOWN }, { MS_UNKNOWN }, { MS_UNKNOWN } } }, MS_RET(0) }; /* initialize the corresponding microseq */ msq[0].opcode = opcode; msq[0].arg[0] = param1; msq[0].arg[1] = param2; msq[0].arg[2] = param3; /* execute the microseq */ return (ppb_MS_microseq(bus, dev, msq, ret)); }
/* * vpoio_reset() * * SCSI reset signal, the drive must be in disk mode */ static void vpoio_reset(struct vpoio_data *vpo) { device_t ppbus = device_get_parent(vpo->vpo_dev); int ret; struct ppb_microseq reset_microseq[] = { #define INITIATOR MS_PARAM(0, 1, MS_TYP_INT) MS_DASS(MS_UNKNOWN), MS_CASS(H_AUTO | H_nSELIN | H_nINIT | H_STROBE), MS_DELAY(25), MS_CASS(H_AUTO | H_nSELIN | H_INIT | H_STROBE), MS_RET(0) }; ppb_MS_init_msq(reset_microseq, 1, INITIATOR, 1 << VP0_INITIATOR); ppb_MS_microseq(ppbus, vpo->vpo_dev, reset_microseq, &ret); return; }
H_AUTO | H_SELIN | H_INIT | H_STROBE, VP0_PULSE, H_AUTO | H_nSELIN | H_INIT | H_STROBE, VP0_PULSE }; #define trig_c_pulse MS_TRIG(MS_REG_CTR,5,MS_UNKNOWN /* c_pulse */) static char c_pulse[] = { H_AUTO | H_nSELIN | H_INIT | H_STROBE, 0, H_AUTO | H_SELIN | H_INIT | H_STROBE, 0, H_nAUTO | H_SELIN | H_INIT | H_STROBE, VP0_PULSE, H_AUTO | H_SELIN | H_INIT | H_STROBE, 0, H_AUTO | H_nSELIN | H_INIT | H_STROBE, VP0_PULSE }; static struct ppb_microseq disconnect_microseq[] = { MS_DASS(0x0), trig_d_pulse, MS_DASS(0x3c), trig_d_pulse, MS_DASS(0x20), trig_d_pulse, MS_DASS(0xf), trig_d_pulse, MS_RET(0) }; static struct ppb_microseq connect_epp_microseq[] = { MS_DASS(0x0), trig_c_pulse, MS_DASS(0x3c), trig_c_pulse, MS_DASS(0x20), trig_c_pulse, MS_DASS(0xcf), trig_c_pulse, MS_RET(0) }; static struct ppb_microseq connect_spp_microseq[] = { MS_DASS(0x0), trig_c_pulse, MS_DASS(0x3c), trig_c_pulse, MS_DASS(0x20), trig_c_pulse, MS_DASS(0x8f), trig_c_pulse, MS_RET(0) }; /* * nibble_inbyte_hook() *
/* * ppb_MS_microseq() * * Interprete a microsequence. Some microinstructions are executed at adapter * level to avoid function call overhead between ppbus and the adapter */ int ppb_MS_microseq(device_t bus, device_t dev, struct ppb_microseq *msq, int *ret) { struct ppb_data *ppb = (struct ppb_data *)device_get_softc(bus); struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev); struct ppb_microseq *mi; /* current microinstruction */ int error; struct ppb_xfer *xfer; /* microsequence executed to initialize the transfer */ struct ppb_microseq initxfer[] = { MS_PTR(MS_UNKNOWN), /* set ptr to buffer */ MS_SET(MS_UNKNOWN), /* set transfer size */ MS_RET(0) }; if (ppb->ppb_owner != dev) return (EACCES); #define INCR_PC (mi ++) mi = msq; for (;;) { switch (mi->opcode) { case MS_OP_PUT: case MS_OP_GET: /* attempt to choose the best mode for the device */ xfer = mode2xfer(bus, ppbdev, mi->opcode); /* figure out if we should use ieee1284 code */ if (!xfer->loop) { if (mi->opcode == MS_OP_PUT) { if ((error = PPBUS_WRITE( device_get_parent(bus), (char *)mi->arg[0].p, mi->arg[1].i, 0))) goto error; INCR_PC; goto next; } else panic("%s: IEEE1284 read not supported", __func__); } /* XXX should use ppb_MS_init_msq() */ initxfer[0].arg[0].p = mi->arg[0].p; initxfer[1].arg[0].i = mi->arg[1].i; /* initialize transfer */ ppb_MS_microseq(bus, dev, initxfer, &error); if (error) goto error; /* the xfer microsequence should not contain any * MS_OP_PUT or MS_OP_GET! */ ppb_MS_microseq(bus, dev, xfer->loop, &error); if (error) goto error; INCR_PC; break; case MS_OP_RET: if (ret) *ret = mi->arg[0].i; /* return code */ return (0); break; default: /* executing microinstructions at ppc level is * faster. This is the default if the microinstr * is unknown here */ if ((error = PPBUS_EXEC_MICROSEQ( device_get_parent(bus), &mi))) goto error; break; } next: continue; } error: return (error); }