struct buf * afs_get_bioreq() { struct buf *bp = NULL; struct buf *bestbp; struct buf **bestlbpP, **lbpP; long bestage, stop; struct buf *t1P, *t2P; /* temp pointers for list manipulation */ int oldPriority; afs_uint32 wait_ret; struct afs_bioqueue *s; /* ??? Does the forward pointer of the returned buffer need to be NULL? */ /* Disable interrupts from the strategy function, and save the * prior priority level and lock access to the afs_asyncbuf. */ AFS_GUNLOCK(); oldPriority = disable_lock(INTMAX, &afs_asyncbuf_lock); while (1) { if (afs_asyncbuf) { /* look for oldest buffer */ bp = bestbp = afs_asyncbuf; bestage = (long)bestbp->av_back; bestlbpP = &afs_asyncbuf; while (1) { lbpP = &bp->av_forw; bp = *lbpP; if (!bp) break; if ((long)bp->av_back - bestage < 0) { bestbp = bp; bestlbpP = lbpP; bestage = (long)bp->av_back; } } bp = bestbp; *bestlbpP = bp->av_forw; break; } else { /* If afs_asyncbuf is null, it is necessary to go to sleep. * e_wakeup_one() ensures that only one thread wakes. */ int interrupted; /* The LOCK_HANDLER indicates to e_sleep_thread to only drop the * lock on an MP machine. */ interrupted = e_sleep_thread(&afs_asyncbuf_cv, &afs_asyncbuf_lock, LOCK_HANDLER | INTERRUPTIBLE); if (interrupted == THREAD_INTERRUPTED) { /* re-enable interrupts from strategy */ unlock_enable(oldPriority, &afs_asyncbuf_lock); AFS_GLOCK(); return (NULL); } } /* end of "else asyncbuf is empty" */ } /* end of "inner loop" */ /*assert (bp); */ unlock_enable(oldPriority, &afs_asyncbuf_lock); AFS_GLOCK(); /* For the convenience of other code, replace the gnodes in * the b_vp field of bp and the other buffers on the b_work * chain with the corresponding vnodes. * * ??? what happens to the gnodes? They're not just cut loose, * are they? */ for (t1P = bp;;) { t2P = (struct buf *)t1P->b_work; t1P->b_vp = ((struct gnode *)t1P->b_vp)->gn_vnode; if (!t2P) break; t1P = (struct buf *)t2P->b_work; t2P->b_vp = ((struct gnode *)t2P->b_vp)->gn_vnode; if (!t1P) break; } /* If the buffer does not specify I/O, it may immediately * be returned to the caller. This condition is detected * by examining the buffer's flags (the b_flags field). If * the B_PFPROT bit is set, the buffer represents a protection * violation, rather than a request for I/O. The remainder * of the outer loop handles the case where the B_PFPROT bit is clear. */ if (bp->b_flags & B_PFPROT) { return (bp); } return (bp); } /* end of function get_bioreq() */
static int gsccmd(dev_t dev, scmd_t *argcmd, ulong dflag) { gsc_softc_t *sp; scmd_t local, *l; char sbyte, albits; struct sc_buf *usc; struct buf *Ubp; int r, r2, ival, upin, unit, rqvalid, once; unit = minor(dev); Trace2(1, "%d: cmd for unit %d", __LINE__, minor(dev)); if (unit < 0 || unit >= MAX_UNITS) { setuerror(ENXIO); return (ENXIO); } sp = &softinfo[unit]; if (sp->iscfg == 0 || sp->fp == NULL) { Trace2(0, "gsccmd: bad unit %d (cfg=%d)", unit, sp->iscfg); r = ENODEV; setuerror(r); return (r); } simple_lock(&sp->dd_lock); l = &local; if (dflag & DKERNEL) { l = argcmd; } else { r = copyin((caddr_t) argcmd, (caddr_t) l, sizeof (scmd_t)); if (r != 0) { Trace2(0, "%d: copyin=%d", __LINE__, r); setuerror(r); MJ_RTN (r); } } Trace6(1, "%d: cdblen%d datalen%d snslen%d rw=%d tv=%d", __LINE__, l->cdblen, l->datalen, l->senselen, l->rw, l->timeval); sbyte = 0; rqvalid = upin = r = r2 = 0; usc = &sp->cmdbuf; Ubp = &usc->bufstruct; memset(usc, 0, sizeof (struct sc_buf)); /* * Check some parameters... */ if (l->cdblen > sizeof (struct sc_cmd)) { r = EINVAL; goto out; } /* * Setup sc_buf structure */ Ubp->b_iodone = gscdd_intr; Ubp->b_dev = sp->dev; Ubp->b_flags = B_BUSY | B_MPSAFE; Ubp->b_resid = Ubp->b_bcount = l->datalen; Ubp->b_xmemd.aspace_id = XMEM_INVAL; Ubp->b_event = EVENT_NULL; if (l->datalen) { Ubp->b_un.b_addr = l->data_buf; if (l->rw) { Ubp->b_flags |= B_READ; } if (dflag & DKERNEL) { r = pinu(l->data_buf, l->datalen, UIO_SYSSPACE); } else { r = pinu(l->data_buf, l->datalen, UIO_USERSPACE); } if (r) { Trace2(0, "%d: pinu buf %d", __LINE__, r); goto out; } upin++; if (dflag & DKERNEL) { r = xmattach(l->data_buf, l->datalen, &Ubp->b_xmemd, SYS_ADSPACE); } else { r = xmattach(l->data_buf, l->datalen, &Ubp->b_xmemd, USER_ADSPACE); } if (r != XMEM_SUCC) { Trace2(0, "%d: xmattach %d", __LINE__, r); r = EFAULT; goto out; } upin++; r = xmemdma(&Ubp->b_xmemd, l->data_buf, XMEM_UNHIDE); if (r == XMEM_FAIL) { Trace2(0, "%d: xmemdma %d", __LINE__, r); r = EFAULT; goto out; } r = 0; } usc->scsi_command.scsi_id = sp->tgt; usc->scsi_command.scsi_length = l->cdblen; if (dflag & DKERNEL) { bcopy(l->cdb, (caddr_t)&usc->scsi_command.scsi_cmd, l->cdblen); } else { r = copyin(l->cdb, (caddr_t) & usc->scsi_command.scsi_cmd, l->cdblen); if (r != 0) { goto out; } } /* Setting lun in SCSI CDB as well as sc_buf structure */ usc->lun = sp->lun; usc->scsi_command.scsi_cmd.lun &= 0x1F; usc->scsi_command.scsi_cmd.lun |= (sp->lun << 5) & 0xE0; albits = usc->scsi_command.scsi_cmd.lun; usc->timeout_value = l->timeval; if (sp->needresume) { usc->flags |= SC_RESUME; sp->needresume = 0; } if (scudebug > 1) { char *c = (char *) &usc->scsi_command.scsi_cmd; char cdbuf[64]; (void) sprintf(cdbuf, "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x " "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8], c[9], c[10], c[11]); Trace2(0, "%d: cdb=%s", __LINE__, cdbuf); } once = 0; again: Ubp->b_flags &= ~B_DONE; r = devstrat(Ubp); if (r == 0) { ival = disable_lock(INTCLASS1, &sp->buf_lock); while ((Ubp->b_flags & B_DONE) == 0) { e_sleep_thread(&Ubp->b_event, &sp->buf_lock, LOCK_HANDLER); } unlock_enable(ival, &sp->buf_lock); } else { /* * If ENXIO, We never actually got started. */ if (r == ENXIO && once == 0) { once++; usc->flags |= SC_RESUME|SC_DELAY_CMD; goto again; } sp->needresume = 1; Trace2(1, "%d: devstrat=%d", __LINE__, r); goto out; } Trace4(1, "%d: b_flags %x b_error %d b_resid %d", __LINE__, Ubp->b_flags, Ubp->b_error, Ubp->b_resid); Trace5(1, "%d: sv %x st %x gc %x as %x", __LINE__, usc->status_validity, usc->scsi_status, usc->general_card_status, usc->adap_q_status); if (Ubp->b_flags & B_ERROR) { r = Ubp->b_error; sp->needresume = 1; } if (usc->status_validity & SC_SCSI_ERROR) { sbyte = (usc->scsi_status & SCSI_STATUS_MASK); sp->needresume = 1; if (sbyte == SC_CHECK_CONDITION && l->senselen) { struct sc_buf *usl; struct buf *Sbp; r = make_rqs(sp, albits, l->sense_buf, l->senselen, (dflag & DKERNEL) != 0); if (r) { Trace2(0, "%d: make_rqs=%d", __LINE__, r); goto out; } usl = &sp->rqsbuf; Sbp = &usl->bufstruct; r = devstrat(Sbp); if (r == 0) { ival = disable_lock(INTCLASS1, &sp->buf_lock); while ((Sbp->b_flags & B_DONE) == 0) { e_sleep_thread(&Sbp->b_event, &sp->buf_lock, LOCK_HANDLER); } unlock_enable(ival, &sp->buf_lock); } else { Trace2(0, "%d:ds=%d for rqs", __LINE__, r); goto out; } xmdetach(&Sbp->b_xmemd); if (dflag & DKERNEL) { (void) unpinu(l->sense_buf, l->senselen, UIO_SYSSPACE); } else { (void) unpinu(l->sense_buf, l->senselen, UIO_USERSPACE); } Trace4(1, "%d SENSE: b_flags %x b_error %d b_resid %d", __LINE__, Sbp->b_flags, Sbp->b_error, Sbp->b_resid); Trace5(1, "%d: sv %x st %x gc %x as %x", __LINE__, usl->status_validity, usl->scsi_status, usl->general_card_status, usl->adap_q_status); if (usl->scsi_status || usl->general_card_status) { r = EIO; } else { rqvalid = 1; } } } if (usc->status_validity & SC_ADAPTER_ERROR) { sp->needresume = 1; Trace2(0, "%d: adapter error 0x%x", __LINE__, usc->general_card_status); Ubp->b_flags |= B_ERROR; switch (usc->general_card_status) { case SC_NO_DEVICE_RESPONSE: case SC_HOST_IO_BUS_ERR: case SC_SCSI_BUS_FAULT: case SC_CMD_TIMEOUT: case SC_ADAPTER_HDW_FAILURE: case SC_ADAPTER_SFW_FAILURE: case SC_FUSE_OR_TERMINAL_PWR: case SC_SCSI_BUS_RESET: default: r = EIO; break; } } /* * Log errors through errsave function */ if (usc->status_validity & (SC_SCSI_ERROR|SC_ADAPTER_ERROR)) { struct sc_error_log_df log; memset(&log, 0, sizeof (log)); /* * All errors are 'temporary unknown driver error' */ log.error_id = ERRID_SCSI_ERR6; (void) sprintf(log.resource_name, "gsc%d", unit); memcpy(&log.scsi_command, &usc->scsi_command, sizeof (struct scsi)); log.status_validity = usc->status_validity; log.scsi_status = usc->scsi_status; log.general_card_status = usc->general_card_status; if (rqvalid) { int amt; if (l->senselen > 128) amt = 128; else amt = l->senselen; (void) copyin(l->sense_buf, log.req_sense_data, amt); } errsave(&log, sizeof (struct sc_error_log_df)); } if (dflag & DKERNEL) { *l->statusp = sbyte; } else { r2 = copyout(&sbyte, l->statusp, 1); if (r2 != 0) { if (r == 0) r = r2; goto out; } } out: if (l->datalen) { if (upin > 1) { xmdetach(&Ubp->b_xmemd); upin--; } if (upin > 0) { if (dflag & DKERNEL) { (void) unpinu(l->data_buf, l->datalen, UIO_SYSSPACE); } else { (void) unpinu(l->data_buf, l->datalen, UIO_USERSPACE); } upin--; } } Trace2(1, "%d: returning %d", __LINE__, r); if (r) setuerror(r); MJ_RTN (r); }