config root man

Current Path : /sys/dev/hptmv/

FreeBSD hs32.drive.ne.jp 9.1-RELEASE FreeBSD 9.1-RELEASE #1: Wed Jan 14 12:18:08 JST 2015 root@hs32.drive.ne.jp:/sys/amd64/compile/hs32 amd64
Upload File :
Current File : //sys/dev/hptmv/hptproc.c

/*
 * Copyright (c) 2004-2005 HighPoint Technologies, Inc.
 * 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.
 *
 * 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.
 *
 * $FreeBSD: release/9.1.0/sys/dev/hptmv/hptproc.c 219819 2011-03-21 09:40:01Z jeff $
 */
/*
 * hptproc.c  sysctl support
 */
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/sysctl.h>
#include <machine/stdarg.h>

#ifndef __KERNEL__
#define __KERNEL__
#endif

#include <dev/hptmv/global.h>
#include <dev/hptmv/hptintf.h>
#include <dev/hptmv/osbsd.h>
#include <dev/hptmv/access601.h>

int hpt_rescan_all(void);

/***************************************************************************/

static char hptproc_buffer[256];
extern char DRIVER_VERSION[];

#define FORMAL_HANDLER_ARGS struct sysctl_oid *oidp, void *arg1,	\
	intptr_t arg2, struct sysctl_req *req
#define REAL_HANDLER_ARGS oidp, arg1, arg2, req
typedef struct sysctl_req HPT_GET_INFO;

static int
hpt_set_asc_info(IAL_ADAPTER_T *pAdapter, char *buffer,int length)
{
	int orig_length = length+4;
	PVBus _vbus_p = &pAdapter->VBus;
	PVDevice	 pArray;
	PVDevice pSubArray, pVDev;
	UINT	i, iarray, ichan;
	struct cam_periph *periph = NULL;
	intrmask_t oldspl;

#ifdef SUPPORT_ARRAY	
	if (length>=8 && strncmp(buffer, "rebuild ", 8)==0) 
	{
		buffer+=8;
		length-=8;
		if (length>=5 && strncmp(buffer, "start", 5)==0) 
		{
			oldspl = lock_driver();
			for(i = 0; i < MAX_ARRAY_PER_VBUS; i++)
				if ((pArray=ArrayTables(i))->u.array.dArStamp==0)
					continue; 
				else{
					if (pArray->u.array.rf_need_rebuild && !pArray->u.array.rf_rebuilding)
	                    hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, 
							(UCHAR)((pArray->u.array.CriticalMembers || pArray->VDeviceType == VD_RAID_1)? DUPLICATE : REBUILD_PARITY));
				}
			unlock_driver(oldspl);
			return orig_length;
		}
		else if (length>=4 && strncmp(buffer, "stop", 4)==0) 
		{
			oldspl = lock_driver();
			for(i = 0; i < MAX_ARRAY_PER_VBUS; i++)
				if ((pArray=ArrayTables(i))->u.array.dArStamp==0)
					continue; 
				else{
					if (pArray->u.array.rf_rebuilding)
					    pArray->u.array.rf_abort_rebuild = 1;
				}
			unlock_driver(oldspl);
			return orig_length;
		}	
		else if (length>=3 && buffer[1]==','&& buffer[0]>='1'&& buffer[2]>='1')	
		{
			iarray = buffer[0]-'1';
	        ichan = buffer[2]-'1';

            if(iarray >= MAX_VDEVICE_PER_VBUS || ichan >= MV_SATA_CHANNELS_NUM) return -EINVAL;

			pArray = _vbus_p->pVDevice[iarray];
	        if (!pArray || (pArray->vf_online == 0)) return -EINVAL;

            for (i=0;i<MV_SATA_CHANNELS_NUM;i++)
				if(i == ichan)
				    goto rebuild;

	        return -EINVAL;

rebuild:
	        pVDev = &pAdapter->VDevices[ichan];
	        if(!pVDev->u.disk.df_on_line || pVDev->pParent) return -EINVAL;

	        /* Not allow to use a mounted disk ??? test*/
			for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++)
			    if(pVDev == _vbus_p->pVDevice[i])
			    {
					periph = hpt_get_periph(pAdapter->mvSataAdapter.adapterId,i);
					if (periph != NULL && periph->refcount >= 1)
					{
						hpt_printk(("Can not use disk used by OS!\n"));
	                    return -EINVAL;	
					}
					/* the Mounted Disk isn't delete */
				} 
			
			switch(pArray->VDeviceType)
			{
				case VD_RAID_1:
				case VD_RAID_5:
				{
					pSubArray = pArray;
loop:
					oldspl = lock_driver();
					if(hpt_add_disk_to_array(_VBUS_P VDEV_TO_ID(pSubArray), VDEV_TO_ID(pVDev)) == -1) {
						unlock_driver(oldspl);
						return -EINVAL;
					}
					pSubArray->u.array.rf_auto_rebuild = 0;
					pSubArray->u.array.rf_abort_rebuild = 0;
					hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pSubArray, DUPLICATE);
					unlock_driver(oldspl);
					break;
				}
				case VD_RAID_0:
					for (i = 0; (UCHAR)i < pArray->u.array.bArnMember; i++) 
						if(pArray->u.array.pMember[i] && mIsArray(pArray->u.array.pMember[i]) &&
						   (pArray->u.array.pMember[i]->u.array.rf_broken == 1))
						{
							  pSubArray = pArray->u.array.pMember[i];
							  goto loop;
						}
				default:
					return -EINVAL;
			}
			return orig_length;
		}
	}
	else if (length>=7 && strncmp(buffer, "verify ", 7)==0)
	{
		buffer+=7;
		length-=7;
        if (length>=6 && strncmp(buffer, "start ", 6)==0) 
		{
            buffer+=6;
		    length-=6;
            if (length>=1 && *buffer>='1') 
			{
				iarray = *buffer-'1';
				if(iarray >= MAX_VDEVICE_PER_VBUS) return -EINVAL;

				pArray = _vbus_p->pVDevice[iarray];
				if (!pArray || (pArray->vf_online == 0)) return -EINVAL;
				
				if(pArray->VDeviceType != VD_RAID_1 && pArray->VDeviceType != VD_RAID_5)
					return -EINVAL;

				if (!(pArray->u.array.rf_need_rebuild ||
					pArray->u.array.rf_rebuilding ||
					pArray->u.array.rf_verifying ||
					pArray->u.array.rf_initializing))
				{
					oldspl = lock_driver();
					pArray->u.array.RebuildSectors = 0;
					hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, VERIFY);
					unlock_driver(oldspl);
				}
                return orig_length;
			}
		}
		else if (length>=5 && strncmp(buffer, "stop ", 5)==0)
		{
			buffer+=5;
		    length-=5;
            if (length>=1 && *buffer>='1') 
			{
				iarray = *buffer-'1';
				if(iarray >= MAX_VDEVICE_PER_VBUS) return -EINVAL;

				pArray = _vbus_p->pVDevice[iarray];
				if (!pArray || (pArray->vf_online == 0)) return -EINVAL;
				if(pArray->u.array.rf_verifying) 
				{
					oldspl = lock_driver();
				    pArray->u.array.rf_abort_rebuild = 1;
				    unlock_driver(oldspl);
				}
			    return orig_length;
			}
		}
	}
	else
#ifdef _RAID5N_
	if (length>=10 && strncmp(buffer, "writeback ", 10)==0) {
	    	buffer+=10;
		length-=10;
		if (length>=1 && *buffer>='0' && *buffer<='1') {
			_vbus_(r5.enable_write_back) = *buffer-'0';
			if (_vbus_(r5.enable_write_back))
				hpt_printk(("RAID5 write back enabled"));
			return orig_length;
		}
	}
	else
#endif
#endif
	if (0) {} /* just to compile */
#ifdef DEBUG
	else if (length>=9 && strncmp(buffer, "dbglevel ", 9)==0) {
	    	buffer+=9;
		length-=9;
		if (length>=1 && *buffer>='0' && *buffer<='3') {
			hpt_dbg_level = *buffer-'0';
			return orig_length;
		}
	}
	else if (length>=8 && strncmp(buffer, "disable ", 8)==0) {
		/* TO DO */
	}
#endif

	return -EINVAL;
}

/*
 * Since we have only one sysctl node, add adapter ID in the command 
 * line string: e.g. "hpt 0 rebuild start"
 */
static int
hpt_set_info(int length)
{
	int retval;

#ifdef SUPPORT_IOCTL
	PUCHAR ke_area;
	int err;
	DWORD dwRet;
	PHPT_IOCTL_PARAM piop;
#endif
	char *buffer = hptproc_buffer;
	if (length >= 6) {
		if (strncmp(buffer,"hpt ",4) == 0) {
			IAL_ADAPTER_T *pAdapter;
			retval = buffer[4]-'0';
			for (pAdapter=gIal_Adapter; pAdapter; pAdapter=pAdapter->next) {
				if (pAdapter->mvSataAdapter.adapterId==retval)
					return (retval = hpt_set_asc_info(pAdapter, buffer+6, length-6)) >= 0? retval : -EINVAL;
			}
			return -EINVAL;
		}
#ifdef SUPPORT_IOCTL	
		piop = (PHPT_IOCTL_PARAM)buffer;
		if (piop->Magic == HPT_IOCTL_MAGIC || 
			piop->Magic == HPT_IOCTL_MAGIC32) 	{
			KdPrintE(("ioctl=%d in=%p len=%d out=%p len=%d\n", 
				piop->dwIoControlCode,
        			piop->lpInBuffer,
        			piop->nInBufferSize,
        			piop->lpOutBuffer,
	        		piop->nOutBufferSize));

			/*
        	 	 * map buffer to kernel.
        	 	 */
        		if (piop->nInBufferSize+piop->nOutBufferSize > PAGE_SIZE) {
        			KdPrintE(("User buffer too large\n"));
        			return -EINVAL;
        		}
        		
        		ke_area = malloc(piop->nInBufferSize+piop->nOutBufferSize, M_DEVBUF, M_NOWAIT);
				if (ke_area == NULL) {
					KdPrintE(("Couldn't allocate kernel mem.\n"));
					return -EINVAL;
				}

			if (piop->nInBufferSize)
				copyin((void*)(ULONG_PTR)piop->lpInBuffer, ke_area, piop->nInBufferSize);

			/*
			  * call kernel handler.
			  */    
			err = Kernel_DeviceIoControl(&gIal_Adapter->VBus,
				piop->dwIoControlCode, ke_area, piop->nInBufferSize,
				ke_area + piop->nInBufferSize, piop->nOutBufferSize, &dwRet);    
			
			if (err==0) {
				if (piop->nOutBufferSize)
					copyout(ke_area + piop->nInBufferSize, (void*)(ULONG_PTR)piop->lpOutBuffer, piop->nOutBufferSize);
				
				if (piop->lpBytesReturned)
					copyout(&dwRet, (void*)(ULONG_PTR)piop->lpBytesReturned, sizeof(DWORD));
			
				free(ke_area, M_DEVBUF);
				return length;
			}
			else  KdPrintW(("Kernel_ioctl(): return %d\n", err));

			free(ke_area, M_DEVBUF);
            		return -EINVAL;
		} else 	{
    		KdPrintW(("Wrong signature: %x\n", piop->Magic));
    		return -EINVAL;
		}
#endif
	}

	return -EINVAL;
}

#define shortswap(w) ((WORD)((w)>>8 | ((w) & 0xFF)<<8))

static void
get_disk_name(char *name, PDevice pDev)
{
	int i;
	MV_SATA_CHANNEL *pMvSataChannel = pDev->mv;
	IDENTIFY_DATA2 *pIdentifyData = (IDENTIFY_DATA2 *)pMvSataChannel->identifyDevice;
	
	for (i = 0; i < 10; i++) 
		((WORD*)name)[i] = shortswap(pIdentifyData->ModelNumber[i]);
	name[20] = '\0';
}

static int
hpt_copy_info(HPT_GET_INFO *pinfo, char *fmt, ...) 
{
	int printfretval;
	va_list ap;
	
	if(fmt == NULL) {
		*hptproc_buffer = 0;
		return (SYSCTL_OUT(pinfo, hptproc_buffer, 1));
	}
	else 
	{
		va_start(ap, fmt);
		printfretval = vsnprintf(hptproc_buffer, sizeof(hptproc_buffer), fmt, ap);
		va_end(ap);
		return(SYSCTL_OUT(pinfo, hptproc_buffer, strlen(hptproc_buffer)));
	}
}

static void
hpt_copy_disk_info(HPT_GET_INFO *pinfo, PVDevice pVDev, UINT iChan)
{
	char name[32], arrayname[16], *status;

	get_disk_name(name, &pVDev->u.disk);
	
	if (!pVDev->u.disk.df_on_line)
		status = "Disabled";
	else if (pVDev->VDeviceType==VD_SPARE)
		status = "Spare   ";
	else
		status = "Normal  ";

#ifdef SUPPORT_ARRAY
	if(pVDev->pParent) {
		memcpy(arrayname, pVDev->pParent->u.array.ArrayName, MAX_ARRAY_NAME);
		if (pVDev->pParent->u.array.CriticalMembers & (1<<pVDev->bSerialNumber))
			status = "Degraded";
	}
	else
#endif
		arrayname[0]=0;
	
	hpt_copy_info(pinfo, "Channel %d  %s  %5dMB  %s %s\n",
		iChan+1, 
		name, pVDev->VDeviceCapacity>>11, status, arrayname);
}

#ifdef SUPPORT_ARRAY
static void
hpt_copy_array_info(HPT_GET_INFO *pinfo, int nld, PVDevice pArray)
{
	int i;
	char *sType=0, *sStatus=0;
	char buf[32];
    PVDevice pTmpArray;

	switch (pArray->VDeviceType) {
		case VD_RAID_0:
			for (i = 0; (UCHAR)i < pArray->u.array.bArnMember; i++) 
		  		if(pArray->u.array.pMember[i])	{
			  		if(mIsArray(pArray->u.array.pMember[i]))
				 		sType = "RAID 1/0   ";
			  			/* TO DO */
			  		else
				 		sType = "RAID 0     ";
			  		break;
		  		}
			break;
			
		case VD_RAID_1:
			sType = "RAID 1     ";
			break;
			
		case VD_JBOD:
			sType = "JBOD       ";
			break;
			
		case VD_RAID_5:
       		sType = "RAID 5     ";
			break;
			
		default:
			sType = "N/A        ";
			break;
	}
	
	if (pArray->vf_online == 0)
		sStatus = "Disabled";
	else if (pArray->u.array.rf_broken)
		sStatus = "Critical";
	for (i = 0; (UCHAR)i < pArray->u.array.bArnMember; i++)
	{
		if (!sStatus) 
		{
			if(mIsArray(pArray->u.array.pMember[i]))
                		pTmpArray = pArray->u.array.pMember[i];
			else
			   	pTmpArray = pArray;
			
			if (pTmpArray->u.array.rf_rebuilding) {
#ifdef DEBUG
				sprintf(buf, "Rebuilding %lldMB", (pTmpArray->u.array.RebuildSectors>>11));
#else 
				sprintf(buf, "Rebuilding %d%%", (UINT)((pTmpArray->u.array.RebuildSectors>>11)*100/((pTmpArray->VDeviceCapacity/(pTmpArray->u.array.bArnMember-1))>>11)));
#endif
				sStatus = buf;
			}
			else if (pTmpArray->u.array.rf_verifying) {
				sprintf(buf, "Verifying %d%%", (UINT)((pTmpArray->u.array.RebuildSectors>>11)*100/((pTmpArray->VDeviceCapacity/(pTmpArray->u.array.bArnMember-1))>>11)));
				sStatus = buf;
			}
			else if (pTmpArray->u.array.rf_need_rebuild)
				sStatus = "Critical";
			else if (pTmpArray->u.array.rf_broken)
				sStatus = "Critical";
			
			if(pTmpArray == pArray) goto out;
		}
		else
			goto out;
	}
out:	
	if (!sStatus) sStatus = "Normal";
	hpt_copy_info(pinfo, "%2d  %11s  %-20s  %5lldMB  %-16s", nld, sType, pArray->u.array.ArrayName, pArray->VDeviceCapacity>>11, sStatus);
}
#endif

static int
hpt_get_info(IAL_ADAPTER_T *pAdapter, HPT_GET_INFO *pinfo)
{
	PVBus _vbus_p = &pAdapter->VBus;
	struct cam_periph *periph = NULL;
	UINT channel,j,i;
	PVDevice pVDev;

#ifndef FOR_DEMO
	if (pAdapter->beeping) {
		intrmask_t oldspl = lock_driver();
		pAdapter->beeping = 0;
		BeepOff(pAdapter->mvSataAdapter.adapterIoBaseAddress);
		unlock_driver(oldspl);
	}
#endif

	hpt_copy_info(pinfo, "Controller #%d:\n\n", pAdapter->mvSataAdapter.adapterId);
	
	hpt_copy_info(pinfo, "Physical device list\n");
	hpt_copy_info(pinfo, "Channel    Model                Capacity  Status   Array\n");
	hpt_copy_info(pinfo, "-------------------------------------------------------------------\n");

    for (channel = 0; channel < MV_SATA_CHANNELS_NUM; channel++)
	{
		pVDev = &(pAdapter->VDevices[channel]);
		if(pVDev->u.disk.df_on_line)
			 hpt_copy_disk_info(pinfo, pVDev, channel);
	}
	
	hpt_copy_info(pinfo, "\nLogical device list\n");
	hpt_copy_info(pinfo, "No. Type         Name                 Capacity  Status            OsDisk\n");
	hpt_copy_info(pinfo, "--------------------------------------------------------------------------\n");

	j=1;
	for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++){
        pVDev = _vbus_p->pVDevice[i];
		if(pVDev){
			j=i+1;
#ifdef SUPPORT_ARRAY
			if (mIsArray(pVDev))
			{
		is_array:
				hpt_copy_array_info(pinfo, j, pVDev);
			}
			else
#endif
			{
				char name[32];
				/* it may be add to an array after driver loaded, check it */
#ifdef SUPPORT_ARRAY
				if (pVDev->pParent)
					/* in this case, pVDev can only be a RAID 1 source disk. */
					if (pVDev->pParent->VDeviceType==VD_RAID_1 && pVDev==pVDev->pParent->u.array.pMember[0]) 
						goto is_array;
#endif
				get_disk_name(name, &pVDev->u.disk);
				
				hpt_copy_info(pinfo, "%2d  %s  %s  %5dMB  %-16s",
					j, "Single disk", name, pVDev->VDeviceCapacity>>11, 
					/* gmm 2001-6-19: Check if pDev has been added to an array. */
					((pVDev->pParent) ? "Unavailable" : "Normal"));
			}
			periph = hpt_get_periph(pAdapter->mvSataAdapter.adapterId, i);
			if (periph == NULL)
				hpt_copy_info(pinfo,"  %s\n","not registered");
			else
				hpt_copy_info(pinfo,"  %s%d\n", periph->periph_name, periph->unit_number);
		 }
	}
	return 0;
}

static __inline int
hpt_proc_in(FORMAL_HANDLER_ARGS, int *len)
{
	int i, error=0;

	*len = 0;
	if ((req->newlen - req->newidx) >= sizeof(hptproc_buffer)) {
		error = EINVAL;
	} else {
		i = (req->newlen - req->newidx);
		error = SYSCTL_IN(req, hptproc_buffer, i);
		if (!error)
			*len = i;
		(hptproc_buffer)[i] = '\0';
	}
	return (error);
}

static int
hpt_status(FORMAL_HANDLER_ARGS)
{
	int length, error=0, retval=0;
	IAL_ADAPTER_T *pAdapter;

	error = hpt_proc_in(REAL_HANDLER_ARGS, &length);
	
    if (req->newptr != NULL) 	
	{
		if (error || length == 0) 	
		{
    		KdPrint(("error!\n"));
    		retval = EINVAL;
    		goto out;
		}
    		
		if (hpt_set_info(length) >= 0)
			retval = 0;
		else
			retval = EINVAL;
		goto out;
    }

	hpt_copy_info(req, "%s Version %s\n", DRIVER_NAME, DRIVER_VERSION);
	for (pAdapter=gIal_Adapter; pAdapter; pAdapter=pAdapter->next) {
		if (hpt_get_info(pAdapter, req) < 0) {
			retval = EINVAL;
			break;
		}
	}
	
	hpt_copy_info(req, NULL);
	goto out;

out:
	return (retval);
}


#define xhptregister_node(name) hptregister_node(name)

#if (__FreeBSD_version < 500043)
#define hptregister_node(name) \
	SYSCTL_NODE(, OID_AUTO,	name, CTLFLAG_RW, 0, "Get/Set " #name " state root node") \
	SYSCTL_OID(_ ## name, OID_AUTO, status, CTLTYPE_STRING|CTLFLAG_RW, \
	NULL, 0, hpt_status, "A", "Get/Set " #name " state")
#else 
#define hptregister_node(name) \
	SYSCTL_NODE(, OID_AUTO,	name, CTLFLAG_RW, 0, "Get/Set " #name " state root node"); \
	SYSCTL_OID(_ ## name, OID_AUTO, status, CTLTYPE_STRING|CTLFLAG_RW, \
	NULL, 0, hpt_status, "A", "Get/Set " #name " state");
#endif
	
xhptregister_node(PROC_DIR_NAME);

Man Man