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

📄 isp_linux.c

📁 这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自测试~但就算用来做参考资料也是非常好的
💻 C
📖 第 1 页 / 共 5 页
字号:
/* @(#)isp_linux.c 1.48 *//* * Qlogic ISP Host Adapter Common Bus Linux routies *--------------------------------------- * * Copyright (c) 1998, 1999, 2000, 2001 by Matthew Jacob * 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, *    without modification, immediately at the beginning of the file. * 2. The name of the author may not be used to endorse or promote products *    derived from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * the GNU Public License ("GPL"). * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. *  * Matthew Jacob * Feral Software * PMB #825 * 5214-F Diamond Hts Blvd * San Francisco, CA, 94131 * mjacob@feral.com * *-------- * Bug fixes from Janice McLaughlin (janus@somemore.com) * gratefully acknowledged. */#define	ISP_MODULE	1#include "isp_linux.h"#include "linux/smp_lock.h"#ifdef	ISP_PRIVATE_ASYNC#define	isp_async	isp_async_level1#endifextern void scsi_add_timer(Scsi_Cmnd *, int, void ((*)(Scsi_Cmnd *)));extern int scsi_delete_timer(Scsi_Cmnd *);static int isp_task_thread(void *);struct ispsoftc *isplist = NULL;int isp_debug = 0;int isp_throttle = 0;int isp_cmd_per_lun = 0;int isp_unit_seed = 0;int isp_disable = 0;int isp_nofwreload = 0;int isp_nonvram = 0;int isp_maxluns = 8;int isp_fcduplex = 0;int isp_nport_only = 0;int isp_loop_only = 0;int isp_deadloop_time = 30;	/* how long to wait before assume loop dead */int isp_xtime = 0;static char *isp_roles;static char *isp_wwpns;static char *isp_wwnns;#ifdef	LINUX_ISP_TARGET_MODE#ifndef	ISP_PARENT_TARGET#define	ISP_PARENT_TARGET	scsi_target_handler#endifextern void ISP_PARENT_TARGET (qact_e, void *);static void isp_attach_target(struct ispsoftc *);static void isp_detach_target(struct ispsoftc *);static void isp_taction(qact_e, void *);static INLINE int nolunsenabled(struct ispsoftc *, int);static void isp_target_start_ctio(struct ispsoftc *, tmd_cmd_t *);static int isp_handle_platform_atio(struct ispsoftc *, at_entry_t *);static int isp_handle_platform_atio2(struct ispsoftc *, at2_entry_t *);static int isp_handle_platform_ctio(struct ispsoftc *, void *);static void isp_target_putback_atio(struct ispsoftc *, tmd_cmd_t *);static void isp_complete_ctio(struct ispsoftc *, tmd_cmd_t *);static int isp_en_dis_lun(struct ispsoftc *, int, int, int, int);#endif#if	LINUX_VERSION_CODE < KERNEL_VERSION(2,3,27)struct proc_dir_entry proc_scsi_qlc = {    PROC_SCSI_QLOGICISP, 3, "isp", S_IFDIR | S_IRUGO | S_IXUGO, 2};#endifstatic const char *class3_roles[4] = {    "None", "Target", "Initiator", "Target/Initiator"};extern int isplinux_pci_detect(Scsi_Host_Template *);extern void isplinux_pci_release(struct Scsi_Host *);intisplinux_proc_info(char *buf, char **st, off_t off, int len, int host, int io){#define	PBF	(&buf[size])    int size, pos, begin, i, lim;    struct ispsoftc *isp;    isp = isplist;    while (isp) {	if (isp->isp_host->host_no == host) {	    break;	}	isp = isp->isp_next;    }    if (isp == NULL) {	return (-ENODEV);    }    if (io) {	buf[len] = 0;	io = -ENOSYS;	if (strncmp(buf, "debug=", 6) == 0) {	    unsigned long debug;	    char *p = &buf[6], *q;	    debug = simple_strtoul(p, &q, 16);	    if (q == &buf[6]) {		isp_prt(isp, ISP_LOGERR, "Garbled Debug Line '%s'", buf);		return (-EINVAL);	    }	    isp_prt(isp, ISP_LOGINFO, "setting debug level to 0x%lx", debug);	    ISP_LOCKU_SOFTC(isp);	    isp->isp_dblev = debug;	    ISP_UNLKU_SOFTC(isp);	    io = len;	} else if (strncmp(buf, "rescan", 6) == 0) {	    if (IS_FC(isp)) {		SEND_THREAD_EVENT(isp, ISP_THREAD_FC_RESCAN, 1);		io = len;	    }	} else if (strncmp(buf, "lip", 3) == 0) {	    if (IS_FC(isp)) {		ISP_LOCKU_SOFTC(isp);		(void) isp_control(isp, ISPCTL_SEND_LIP, 0);		ISP_UNLKU_SOFTC(isp);		io = len;	    }	} else if (strncmp(buf, "busreset=", 9) == 0) {	    char *p = &buf[6], *q;	    int bus = (int) simple_strtoul(p, &q, 16);	    if (q == &buf[6]) {		isp_prt(isp, ISP_LOGERR, "Garbled Bus Reset Line '%s'", buf);		return (-EINVAL);	    }	    ISP_LOCKU_SOFTC(isp);	    (void) isp_control(isp, ISPCTL_RESET_BUS, &bus);	    ISP_UNLKU_SOFTC(isp);	    io = len;	} else if (strncmp(buf, "devreset=", 9) == 0) {	    char *p = &buf[6], *q;	    int dev = (int) simple_strtoul(p, &q, 16);	    if (q == &buf[6]) {		isp_prt(isp, ISP_LOGERR, "Garbled Dev Reset Line '%s'", buf);		return (-EINVAL);	    }	    /* always bus 0 */	    ISP_LOCKU_SOFTC(isp);	    (void) isp_control(isp, ISPCTL_RESET_DEV, &dev);	    ISP_UNLKU_SOFTC(isp);	    io = len;	}#ifdef	LINUX_ISP_TARGET_MODE	/*	 * Note that this cannot enable or disable luns on other than bus 0.	 */	else if (strncmp(buf, "enable_lun=", 11) == 0) {	    unsigned long lun;	    char *p = &buf[11], *q;	    lun = simple_strtoul(p, &q, 10);	    if (q == &buf[11]) {		isp_prt(isp, ISP_LOGERR,		    "attempted enable of invalid lun (%s)", buf);		return (-EINVAL);	    }	    io = isp_en_dis_lun(isp, 1, 0, -1, (int) lun);	    if (io >= 0)		io = len;	} else if (strncmp(buf, "disable_lun=", 12) == 0) {	    unsigned long lun;	    char *p = &buf[12], *q; 	    lun = simple_strtoul(p, &q, 10);	    if (q == &buf[12]) {		isp_prt(isp, ISP_LOGERR,		    "attempted disable of invalid lun (%s)", buf);		return (-EINVAL);	    }	    io = isp_en_dis_lun(isp, 0, 0, -1, (int) lun);	    if (io >= 0)		io = len;	}#endif#ifdef	ISP_FW_CRASH_DUMP	else if (strncmp(buf, "fwcrash", 7) == 0) {	    if (IS_FC(isp)) {		ISP_LOCKU_SOFTC(isp);		SEND_THREAD_EVENT(isp, ISP_THREAD_FW_CRASH_DUMP, 0);		ISP_UNLKU_SOFTC(isp);		io = len;	    }	}#endif	return (io);    }    ISP_LOCKU_SOFTC(isp);    begin = size = 0;    size += sprintf(PBF, isplinux_info(isp->isp_host));#ifdef	HBA_VERSION    size += sprintf(PBF, "\n HBA Version %s, built %s, %s",	HBA_VERSION, __DATE__, __TIME__);#endif    size += sprintf(PBF, "\n DEVID %x role %d\n",	isp->isp_osinfo.device_id, isp->isp_role);    size += sprintf(PBF,        " Interrupt Stats:\n"	"  total=0x%08x%08x bogus=0x%08x%08x\n"	"  MboxC=0x%08x%08x async=0x%08x%08x\n"	"  CRslt=0x%08x%08x CPost=0x%08x%08x\n"	"  RspnsCHiWater=0x%04x FastPostC_Hiwater=0x%04x\n",	(u_int32_t) (isp->isp_intcnt >> 32),	(u_int32_t) (isp->isp_intcnt & 0xffffffff),	(u_int32_t) (isp->isp_intbogus >> 32),	(u_int32_t) (isp->isp_intbogus & 0xffffffff),	(u_int32_t) (isp->isp_intmboxc >> 32),	(u_int32_t) (isp->isp_intmboxc & 0xffffffff),	(u_int32_t) (isp->isp_intoasync >> 32),	(u_int32_t) (isp->isp_intoasync & 0xffffffff),	(u_int32_t) (isp->isp_rsltccmplt >> 32),	(u_int32_t) (isp->isp_rsltccmplt & 0xffffffff),	(u_int32_t) (isp->isp_fphccmplt >> 32),	(u_int32_t) (isp->isp_fphccmplt & 0xffffffff),	isp->isp_rscchiwater, isp->isp_fpcchiwater);    size += sprintf(PBF,	" Request In %d Request Out %d Result %d Nactv %d"	" HiWater %u QAVAIL %d WtQHi %d\n",	isp->isp_reqidx, isp->isp_reqodx, isp->isp_residx, isp->isp_nactive,	isp->isp_osinfo.hiwater, ISP_QAVAIL(isp),	isp->isp_osinfo.wqhiwater);    for (lim = i = 0; i < isp->isp_maxcmds; i++) {	if (isp->isp_xflist[i]) {	    size += sprintf(PBF, " %d:%p", i, isp->isp_xflist[i]);	    if (lim++ > 5) {		size += sprintf(PBF, "...");		break;	    }	}    }    size += sprintf(PBF, "\n");    if (isp->isp_osinfo.wqnext) {	Scsi_Cmnd *f = isp->isp_osinfo.wqnext;	size += sprintf(PBF, "WaitQ(%d)", isp->isp_osinfo.wqcnt);	lim = 0;	while (f) {	    size += sprintf(PBF, "->%p", f);	    f = (Scsi_Cmnd *) f->host_scribble;	    if (lim++ > 5) {		size += sprintf(PBF, "...");		break;	    }	}	size += sprintf(PBF, "\n");    }    if (isp->isp_osinfo.dqnext) {	Scsi_Cmnd *f = isp->isp_osinfo.dqnext;	size += sprintf(PBF, "DoneQ");	lim = 0;	while (f) {	    size += sprintf(PBF, "->%p", f);	    f = (Scsi_Cmnd *) f->host_scribble;	    if (lim++ > 5) {		size += sprintf(PBF, "...");		break;	    }	}        size += sprintf(PBF, "\n");    }    if (IS_FC(isp)) {	fcparam *fcp = isp->isp_param;	size += sprintf(PBF,	    "Loop ID: %d AL_PA 0x%x Port ID 0x%x FW State %x Loop State %x\n",	    fcp->isp_loopid, fcp->isp_alpa, fcp->isp_portid, fcp->isp_fwstate,	    fcp->isp_loopstate);	size += sprintf(PBF, "Port WWN 0x%08x%08x Node WWN 0x%08x%08x\n",	    (unsigned int) (ISP_PORTWWN(isp) >> 32),	    (unsigned int) (ISP_PORTWWN(isp) & 0xffffffff),	    (unsigned int) (ISP_NODEWWN(isp) >> 32),	    (unsigned int) (ISP_NODEWWN(isp) & 0xffffffff));	for (i = 0; i < MAX_FC_TARG; i++) {	    if (fcp->portdb[i].valid == 0 && i < FL_PORT_ID)		continue;	    if (fcp->portdb[i].port_wwn == 0)		continue;	    size += sprintf(PBF, "TGT % 3d Loop ID % 3d Port id 0x%04x, role %s"		"\n Port WWN 0x%08x%08x Node WWN 0x%08x%08x\n\n", i,		fcp->portdb[i].loopid,		fcp->portdb[i].portid, class3_roles[fcp->portdb[i].roles],		(unsigned int) (fcp->portdb[i].port_wwn >> 32),		(unsigned int) (fcp->portdb[i].port_wwn & 0xffffffff),		(unsigned int) (fcp->portdb[i].node_wwn >> 32),		(unsigned int) (fcp->portdb[i].node_wwn & 0xffffffff));	}    } else {	sdparam *sdp = (sdparam *)isp->isp_param;	size += sprintf(PBF, "Initiator ID: %d\n", sdp->isp_initiator_id);	size += sprintf(PBF, "Target Flag  Period Offset\n");	for (i = 0; i < MAX_TARGETS; i++) {	    size += sprintf(PBF, "%6d: 0x%04x 0x%04x 0x%x\n",		i, sdp->isp_devparam[i].actv_flags,		sdp->isp_devparam[i].actv_offset,		sdp->isp_devparam[i].actv_period);	}	if (IS_DUALBUS(isp)) {	    sdp++;  	    size += sprintf(PBF, "\nInitiator ID: %d, Channel B\n",		sdp->isp_initiator_id);	    size += sprintf(PBF,		"Target     CurFlag    DevFlag  Period Offset B-Channel\n");	    for (i = 0; i < MAX_TARGETS; i++) {		    size += sprintf(PBF, "%6d: 0x%04x 0x%04x 0x%x\n",			i, sdp->isp_devparam[i].actv_flags,			sdp->isp_devparam[i].actv_offset,			sdp->isp_devparam[i].actv_period);	    }	}    }    ISP_UNLKU_SOFTC(isp);    pos = size;    if (pos < off) {	size = 0;	begin = pos;    }    *st = buf + (off - begin);    size -= (off - begin);    if (size > len)	size = len;    return (size);}intisplinux_detect(Scsi_Host_Template *tmpt){    int rval;#if	LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)    tmpt->proc_name = "isp";#else    tmpt->proc_dir = &proc_scsi_qlc;#endif    ISP_DRIVER_ENTRY_LOCK(isp);    rval = isplinux_pci_detect(tmpt);    ISP_DRIVER_EXIT_LOCK(isp);    return (rval);}#ifdef	MODULE/* io_request_lock *not* held here */intisplinux_release(struct Scsi_Host *host){    struct ispsoftc *isp = (struct ispsoftc *) host->hostdata;    if (isp->isp_osinfo.task_thread) {        SEND_THREAD_EVENT(isp, ISP_THREAD_EXIT, 1);    }    ISP_LOCKU_SOFTC(isp);    isp->dogactive = 0;    del_timer(&isp->isp_osinfo.timer);    DISABLE_INTS(isp);    if (isp->isp_bustype == ISP_BT_PCI) {	isplinux_pci_release(host);    }    ISP_UNLKU_SOFTC(isp);#ifdef	ISP_FW_CRASH_DUMP    if (FCPARAM(isp)->isp_dump_data) {	isp_prt(isp, ISP_LOGCONFIG, "freeing crash dump area");	vfree(FCPARAM(isp)->isp_dump_data);	FCPARAM(isp)->isp_dump_data = 0;    }#endif#ifdef	ISP_TARGET_MODE    isp_detach_target(isp);#endif    return (1);}#endifconst char *isplinux_info(struct Scsi_Host *host){    struct ispsoftc *isp = (struct ispsoftc *) host->hostdata;    if (IS_FC(isp)) {	static char *foo = "Driver for a Qlogic ISP 2X00 Host Adapter";	if (isp->isp_type == ISP_HA_FC_2100)	    foo[25] = '1';	else if (isp->isp_type == ISP_HA_FC_2200)	    foo[25] = '2';	else if (isp->isp_type == ISP_HA_FC_2300)	    foo[25] = '3';	else if (isp->isp_type == ISP_HA_FC_2312) {	    foo[25] = '3';	    foo[26] = '1';	    foo[27] = '2';	}	return (foo);    } else if (IS_1240(isp)) {	return ("Driver for a Qlogic ISP 1240 Host Adapter");    } else if (IS_1080(isp)) {	return ("Driver for a Qlogic ISP 1080 Host Adapter");    } else if (IS_1280(isp)) {	return ("Driver for a Qlogic ISP 1280 Host Adapter");    } else if (IS_12160(isp)) {	return ("Driver for a Qlogic ISP 12160 Host Adapter");    } else {	return ("Driver for a Qlogic ISP 1020/1040 Host Adapter");    }}static INLINE voidisplinux_append_to_waitq(struct ispsoftc *isp, Scsi_Cmnd *Cmnd){    /*     * If we're a fibre channel card and we consider the loop to be     * down, we just finish the command here and now.     */    if (IS_FC(isp) && isp->isp_deadloop) {	XS_INITERR(Cmnd);	XS_SETERR(Cmnd, DID_NO_CONNECT);	/*	 * Add back a timer else scsi_done drops this on the floor.	 */	scsi_add_timer(Cmnd, Cmnd->timeout_per_command, Cmnd->done);	isp_prt(isp, ISP_LOGDEBUG0, "giving up on target %d", Cmnd->target);	ISP_UNLK_SOFTC(isp);	ISP_LOCK_SCSI_DONE(isp);	(*Cmnd->scsi_done)(Cmnd);	ISP_UNLK_SCSI_DONE(isp);	ISP_LOCK_SOFTC(isp);	return;    }    isp->isp_osinfo.wqcnt++;    if (isp->isp_osinfo.wqhiwater < isp->isp_osinfo.wqcnt)	isp->isp_osinfo.wqhiwater = isp->isp_osinfo.wqcnt;    if (isp->isp_osinfo.wqnext == NULL) {	isp->isp_osinfo.wqtail = isp->isp_osinfo.wqnext = Cmnd;    } else {	isp->isp_osinfo.wqtail->host_scribble = (unsigned char *) Cmnd;	isp->isp_osinfo.wqtail = Cmnd;    }    Cmnd->host_scribble = NULL;    /*     * Stop the clock for this command.     */    (void) scsi_delete_timer(Cmnd);}static INLINE voidisplinux_insert_head_waitq(struct ispsoftc *isp, Scsi_Cmnd *Cmnd){    isp->isp_osinfo.wqcnt++;    if (isp->isp_osinfo.wqnext == NULL) {	isp->isp_osinfo.wqtail = isp->isp_osinfo.wqnext = Cmnd;	Cmnd->host_scribble = NULL;    } else {	Cmnd->host_scribble = (unsigned char *) isp->isp_osinfo.wqnext;	isp->isp_osinfo.wqnext = Cmnd;    }}static INLINE Scsi_Cmnd *isp_remove_from_waitq(Scsi_Cmnd *Cmnd){    struct ispsoftc *isp;    Scsi_Cmnd *f;    if (Cmnd == NULL)	return (Cmnd);    isp = (struct ispsoftc *) Cmnd->host->hostdata;    if ((f = isp->isp_osinfo.wqnext) == Cmnd) {	isp->isp_osinfo.wqnext = (Scsi_Cmnd *) Cmnd->host_scribble;    } else {	Scsi_Cmnd *b = f;	while (f) {

⌨️ 快捷键说明

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