Exemple #1
0
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() */
Exemple #2
0
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);
}