⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scsi_base.c

📁 MIPS处理器的bootloader,龙芯就是用的修改过的PMON2
💻 C
📖 第 1 页 / 共 3 页
字号:
/*	$OpenBSD: scsi_base.c,v 1.28 2001/02/18 22:38:44 fgsch Exp $	*//*	$NetBSD: scsi_base.c,v 1.43 1997/04/02 02:29:36 mycroft Exp $	*//* * Copyright (c) 1994, 1995, 1997 Charles M. Hannum.  All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by Charles M. Hannum. * 4. The name of the author may not be used to endorse or promote products *    derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *//* * Originally written by Julian Elischer (julian@dialix.oz.au) * Detailed SCSI error printing Copyright 1997 by Matthew Jacob. */#include <sys/types.h>#include <sys/param.h>#include <sys/systm.h>#include <sys/kernel.h>#include <sys/buf.h>#include <sys/uio.h>#include <sys/malloc.h>#include <sys/errno.h>#include <sys/device.h>#include <sys/proc.h>#include <scsi/scsi_all.h>#include <scsi/scsi_disk.h>#include <scsi/scsiconf.h>LIST_HEAD(xs_free_list, scsi_xfer) xs_free_list;static __inline struct scsi_xfer *scsi_make_xs __P((struct scsi_link *,    struct scsi_generic *, int cmdlen, u_char *data_addr,    int datalen, int retries, int timeout, struct buf *, int flags));static __inline void asc2ascii __P((u_char asc, u_char ascq, char *result));int sc_err1 __P((struct scsi_xfer *, int));int scsi_interpret_sense __P((struct scsi_xfer *));char *scsi_decode_sense __P((void *, int));/* * Get a scsi transfer structure for the caller. Charge the structure * to the device that is referenced by the sc_link structure. If the  * sc_link structure has no 'credits' then the device already has the * maximum number or outstanding operations under way. In this stage, * wait on the structure so that when one is freed, we are awoken again * If the SCSI_NOSLEEP flag is set, then do not wait, but rather, return * a NULL pointer, signifying that no slots were available * Note in the link structure, that we are waiting on it. */struct scsi_xfer *scsi_get_xs(sc_link, flags)	struct scsi_link *sc_link;	/* who to charge the xs to */	int flags;			/* if this call can sleep */{	struct scsi_xfer *xs;	int s;	SC_DEBUG(sc_link, SDEV_DB3, ("scsi_get_xs\n"));	s = splbio();	while (sc_link->openings <= 0) {		SC_DEBUG(sc_link, SDEV_DB3, ("sleeping\n"));		if ((flags & SCSI_NOSLEEP) != 0) {			splx(s);			return 0;		}		sc_link->flags |= SDEV_WAITING;		(void) tsleep(sc_link, PRIBIO, "getxs", 0);	}	sc_link->openings--;	if ((xs = xs_free_list.lh_first) != NULL) {		LIST_REMOVE(xs, free_list);		splx(s);	} else {		splx(s);		SC_DEBUG(sc_link, SDEV_DB3, ("making\n"));		xs = malloc(sizeof(*xs), M_DEVBUF,		    ((flags & SCSI_NOSLEEP) != 0 ? M_NOWAIT : M_WAITOK));		if (!xs) {			sc_print_addr(sc_link);			printf("cannot allocate scsi xs\n");			return 0;		}	}	SC_DEBUG(sc_link, SDEV_DB3, ("returning\n"));	xs->flags = flags;	return xs;}/* * Given a scsi_xfer struct, and a device (referenced through sc_link) * return the struct to the free pool and credit the device with it * If another process is waiting for an xs, do a wakeup, let it proceed */void scsi_free_xs(xs, flags)	struct scsi_xfer *xs;	int flags;{	struct scsi_link *sc_link = xs->sc_link;	LIST_INSERT_HEAD(&xs_free_list, xs, free_list);	SC_DEBUG(sc_link, SDEV_DB3, ("scsi_free_xs\n"));	/* if was 0 and someone waits, wake them up */	sc_link->openings++;	if ((sc_link->flags & SDEV_WAITING) != 0) {		sc_link->flags &= ~SDEV_WAITING;		wakeup(sc_link);	} else {		if (sc_link->device->start) {			SC_DEBUG(sc_link, SDEV_DB2, ("calling private start()\n"));			(*(sc_link->device->start)) (sc_link->device_softc);		}	}}/* * Make a scsi_xfer, and return a pointer to it. */static __inline struct scsi_xfer *scsi_make_xs(sc_link, scsi_cmd, cmdlen, data_addr, datalen,	     retries, timeout, bp, flags)	struct scsi_link *sc_link;	struct scsi_generic *scsi_cmd;	int cmdlen;	u_char *data_addr;	int datalen;	int retries;	int timeout;	struct buf *bp;	int flags;{	struct scsi_xfer *xs;	if ((xs = scsi_get_xs(sc_link, flags)) == NULL)		return NULL;	/*	 * Fill out the scsi_xfer structure.  We don't know whose context	 * the cmd is in, so copy it.	 */	xs->sc_link = sc_link;	bcopy(scsi_cmd, &xs->cmdstore, cmdlen);	xs->cmd = &xs->cmdstore;	xs->cmdlen = cmdlen;	xs->data = data_addr;	xs->datalen = datalen;	xs->retries = retries;	xs->timeout = timeout;	xs->bp = bp;	xs->req_sense_length = 0;	/* XXX - not used by scsi internals */	/*	 * Set the LUN in the CDB.  This may only be needed if we have an	 * older device.  However, we also set it for more modern SCSI	 * devices "just in case".  The old code assumed everything newer	 * than SCSI-2 would not need it, but why risk it?  This was the	 * old conditional:	 *	 * if ((sc_link->scsi_version & SID_ANSII) <= 2)	 */	xs->cmd->bytes[0] &= ~SCSI_CMD_LUN_MASK;	xs->cmd->bytes[0] |=	    ((sc_link->lun << SCSI_CMD_LUN_SHIFT) & SCSI_CMD_LUN_MASK);	return xs;}/* * Find out from the device what its capacity is. */u_longscsi_size(sc_link, flags)	struct scsi_link *sc_link;	int flags;{	struct scsi_read_cap_data rdcap;	struct scsi_read_capacity scsi_cmd;	/*	 * make up a scsi command and ask the scsi driver to do	 * it for you.	 */	bzero(&scsi_cmd, sizeof(scsi_cmd));	scsi_cmd.opcode = READ_CAPACITY;	/*	 * If the command works, interpret the result as a 4 byte	 * number of blocks	 */	if (scsi_scsi_cmd(sc_link, (struct scsi_generic *)&scsi_cmd,			  sizeof(scsi_cmd), (u_char *)&rdcap, sizeof(rdcap),			  2, 20000, NULL, flags | SCSI_DATA_IN) != 0) {		sc_print_addr(sc_link);		printf("could not get size\n");		return 0;	}	return _4btol(rdcap.addr) + 1;}/* * Get scsi driver to send a "are you ready?" command */int scsi_test_unit_ready(sc_link, flags)	struct scsi_link *sc_link;	int flags;{	struct scsi_test_unit_ready scsi_cmd;	bzero(&scsi_cmd, sizeof(scsi_cmd));	scsi_cmd.opcode = TEST_UNIT_READY;	return scsi_scsi_cmd(sc_link, (struct scsi_generic *) &scsi_cmd,			     sizeof(scsi_cmd), 0, 0, 5, 10000, NULL, flags);}/* * Do a scsi operation, asking a device to run as SCSI-II if it can. */int scsi_change_def(sc_link, flags)	struct scsi_link *sc_link;	int flags;{	struct scsi_changedef scsi_cmd;	bzero(&scsi_cmd, sizeof(scsi_cmd));	scsi_cmd.opcode = CHANGE_DEFINITION;	scsi_cmd.how = SC_SCSI_2;	return scsi_scsi_cmd(sc_link, (struct scsi_generic *) &scsi_cmd,			     sizeof(scsi_cmd), 0, 0, 2, 100000, NULL, flags);}/* * Do a scsi operation asking a device what it is * Use the scsi_cmd routine in the switch table. */int scsi_inquire(sc_link, inqbuf, flags)	struct scsi_link *sc_link;	struct scsi_inquiry_data *inqbuf;	int flags;{	struct scsi_inquiry scsi_cmd;	bzero(&scsi_cmd, sizeof(scsi_cmd));	scsi_cmd.opcode = INQUIRY;	scsi_cmd.length = sizeof(struct scsi_inquiry_data);	return scsi_scsi_cmd(sc_link, (struct scsi_generic *) &scsi_cmd,			     sizeof(scsi_cmd), (u_char *) inqbuf,			     sizeof(struct scsi_inquiry_data), 2, 10000, NULL,			     SCSI_DATA_IN | flags);}/* * Prevent or allow the user to remove the media */int scsi_prevent(sc_link, type, flags)	struct scsi_link *sc_link;	int type, flags;{	struct scsi_prevent scsi_cmd;	bzero(&scsi_cmd, sizeof(scsi_cmd));	scsi_cmd.opcode = PREVENT_ALLOW;	scsi_cmd.how = type;	return scsi_scsi_cmd(sc_link, (struct scsi_generic *) &scsi_cmd,			     sizeof(scsi_cmd), 0, 0, 2, 5000, NULL, flags);}/* * Get scsi driver to send a "start up" command */int scsi_start(sc_link, type, flags)	struct scsi_link *sc_link;	int type, flags;{	struct scsi_start_stop scsi_cmd;	if ((sc_link->quirks & SDEV_NOSTARTUNIT) == SDEV_NOSTARTUNIT)		return 0;	bzero(&scsi_cmd, sizeof(scsi_cmd));	scsi_cmd.opcode = START_STOP;	scsi_cmd.byte2 = 0x00;	scsi_cmd.how = type;	return scsi_scsi_cmd(sc_link, (struct scsi_generic *) &scsi_cmd,			     sizeof(scsi_cmd), 0, 0, 2,			     type == SSS_START ? 30000 : 10000, NULL, flags);}/* * This routine is called by the scsi interrupt when the transfer is complete. */void scsi_done(xs)	struct scsi_xfer *xs;{	struct scsi_link *sc_link = xs->sc_link;	struct buf *bp;	int error;	SC_DEBUG(sc_link, SDEV_DB2, ("scsi_done\n"));#ifdef	SCSIDEBUG	if ((sc_link->flags & SDEV_DB1) != 0)		show_scsi_cmd(xs);#endif /* SCSIDEBUG */#ifndef PMON	/* 	 * If it's a user level request, bypass all usual completion processing, 	 * let the user work it out.. We take reponsibility for freeing the 	 * xs when the user returns. (and restarting the device's queue). 	 */	if ((xs->flags & SCSI_USER) != 0) {		SC_DEBUG(sc_link, SDEV_DB3, ("calling user done()\n"));		scsi_user_done(xs); /* to take a copy of the sense etc. */		SC_DEBUG(sc_link, SDEV_DB3, ("returned from user done()\n "));		scsi_free_xs(xs, SCSI_NOSLEEP); /* restarts queue too */		SC_DEBUG(sc_link, SDEV_DB3, ("returning to adapter\n"));		return;	}#endif	if (!((xs->flags & (SCSI_NOSLEEP | SCSI_POLL)) == SCSI_NOSLEEP)) {		/*		 * if it's a normal upper level request, then ask		 * the upper level code to handle error checking		 * rather than doing it here at interrupt time		 */		wakeup(xs);		return;	}	/*	 * Go and handle errors now.	 * If it returns ERESTART then we should RETRY	 */retry:	error = sc_err1(xs, 1);	if (error == ERESTART) {		switch ((*(sc_link->adapter->scsi_cmd)) (xs)) {		case SUCCESSFULLY_QUEUED:			return;		case TRY_AGAIN_LATER:			xs->error = XS_BUSY;		case COMPLETE:			goto retry;		}	}	bp = xs->bp;	if (bp) {		if (error) {			bp->b_error = error;			bp->b_flags |= B_ERROR;			bp->b_resid = bp->b_bcount;		} else {			bp->b_error = 0;			bp->b_resid = xs->resid;		}	}	if (sc_link->device->done) {		/*		 * Tell the device the operation is actually complete.		 * No more will happen with this xfer.  This for		 * notification of the upper-level driver only; they		 * won't be returning any meaningful information to us.		 */		(*sc_link->device->done)(xs);	}	scsi_free_xs(xs, SCSI_NOSLEEP);	if (bp)		biodone(bp);}intscsi_execute_xs(xs)	struct scsi_xfer *xs;{	int error;	int s;	xs->flags &= ~ITSDONE;	xs->error = XS_NOERROR;	xs->resid = xs->datalen;	xs->status = 0;retry:	/*	 * Do the transfer. If we are polling we will return:	 * COMPLETE,  Was poll, and scsi_done has been called	 * TRY_AGAIN_LATER, Adapter short resources, try again	 * 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -