xref: /freebsd/sys/dev/hptmv/hptproc.c (revision 6ae1554a5d9b318f8ad53ccc39fa5a961403da73)
1 /*
2  * Copyright (c) 2004-2005 HighPoint Technologies, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28 /*
29  * hptproc.c  sysctl support
30  */
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/malloc.h>
35 #include <sys/sysctl.h>
36 #include <machine/stdarg.h>
37 
38 #ifndef __KERNEL__
39 #define __KERNEL__
40 #endif
41 
42 #include <dev/hptmv/global.h>
43 #include <dev/hptmv/hptintf.h>
44 #include <dev/hptmv/osbsd.h>
45 #include <dev/hptmv/access601.h>
46 
47 int hpt_rescan_all(void);
48 
49 /***************************************************************************/
50 
51 static char hptproc_buffer[256];
52 extern char DRIVER_VERSION[];
53 
54 #define FORMAL_HANDLER_ARGS struct sysctl_oid *oidp, void *arg1,	\
55 	intptr_t arg2, struct sysctl_req *req
56 #define REAL_HANDLER_ARGS oidp, arg1, arg2, req
57 typedef struct sysctl_req HPT_GET_INFO;
58 
59 static int
60 hpt_set_asc_info(IAL_ADAPTER_T *pAdapter, char *buffer,int length)
61 {
62 	int orig_length = length+4;
63 	PVBus _vbus_p = &pAdapter->VBus;
64 	PVDevice	 pArray;
65 	PVDevice pSubArray, pVDev;
66 	UINT	i, iarray, ichan;
67 	struct cam_periph *periph = NULL;
68 
69 	mtx_lock(&pAdapter->lock);
70 #ifdef SUPPORT_ARRAY
71 	if (length>=8 && strncmp(buffer, "rebuild ", 8)==0)
72 	{
73 		buffer+=8;
74 		length-=8;
75 		if (length>=5 && strncmp(buffer, "start", 5)==0)
76 		{
77 			for(i = 0; i < MAX_ARRAY_PER_VBUS; i++)
78 				if ((pArray=ArrayTables(i))->u.array.dArStamp==0)
79 					continue;
80 				else{
81 					if (pArray->u.array.rf_need_rebuild && !pArray->u.array.rf_rebuilding)
82 	                    hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray,
83 							(UCHAR)((pArray->u.array.CriticalMembers || pArray->VDeviceType == VD_RAID_1)? DUPLICATE : REBUILD_PARITY));
84 				}
85 			mtx_unlock(&pAdapter->lock);
86 			return orig_length;
87 		}
88 		else if (length>=4 && strncmp(buffer, "stop", 4)==0)
89 		{
90 			for(i = 0; i < MAX_ARRAY_PER_VBUS; i++)
91 				if ((pArray=ArrayTables(i))->u.array.dArStamp==0)
92 					continue;
93 				else{
94 					if (pArray->u.array.rf_rebuilding)
95 					    pArray->u.array.rf_abort_rebuild = 1;
96 				}
97 			mtx_unlock(&pAdapter->lock);
98 			return orig_length;
99 		}
100 		else if (length>=3 && buffer[1]==','&& buffer[0]>='1'&& buffer[2]>='1')
101 		{
102 			iarray = buffer[0]-'1';
103 	        ichan = buffer[2]-'1';
104 
105             if(iarray >= MAX_VDEVICE_PER_VBUS || ichan >= MV_SATA_CHANNELS_NUM) return -EINVAL;
106 
107 			pArray = _vbus_p->pVDevice[iarray];
108 			if (!pArray || (pArray->vf_online == 0)) {
109 				mtx_unlock(&pAdapter->lock);
110 				return -EINVAL;
111 			}
112 
113             for (i=0;i<MV_SATA_CHANNELS_NUM;i++)
114 				if(i == ichan)
115 				    goto rebuild;
116 
117 	        mtx_unlock(&pAdapter->lock);
118 	        return -EINVAL;
119 
120 rebuild:
121 	        pVDev = &pAdapter->VDevices[ichan];
122 	        if(!pVDev->u.disk.df_on_line || pVDev->pParent) {
123 			mtx_unlock(&pAdapter->lock);
124 			return -EINVAL;
125 		}
126 
127 	        /* Not allow to use a mounted disk ??? test*/
128 			for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++)
129 			    if(pVDev == _vbus_p->pVDevice[i])
130 			    {
131 					periph = hpt_get_periph(pAdapter->mvSataAdapter.adapterId,i);
132 					if (periph != NULL && periph->refcount >= 1)
133 					{
134 						hpt_printk(("Can not use disk used by OS!\n"));
135 			    mtx_unlock(&pAdapter->lock);
136 	                    return -EINVAL;
137 					}
138 					/* the Mounted Disk isn't delete */
139 				}
140 
141 			switch(pArray->VDeviceType)
142 			{
143 				case VD_RAID_1:
144 				case VD_RAID_5:
145 				{
146 					pSubArray = pArray;
147 loop:
148 					if(hpt_add_disk_to_array(_VBUS_P VDEV_TO_ID(pSubArray), VDEV_TO_ID(pVDev)) == -1) {
149 						mtx_unlock(&pAdapter->lock);
150 						return -EINVAL;
151 					}
152 					pSubArray->u.array.rf_auto_rebuild = 0;
153 					pSubArray->u.array.rf_abort_rebuild = 0;
154 					hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pSubArray, DUPLICATE);
155 					break;
156 				}
157 				case VD_RAID_0:
158 					for (i = 0; (UCHAR)i < pArray->u.array.bArnMember; i++)
159 						if(pArray->u.array.pMember[i] && mIsArray(pArray->u.array.pMember[i]) &&
160 						   (pArray->u.array.pMember[i]->u.array.rf_broken == 1))
161 						{
162 							  pSubArray = pArray->u.array.pMember[i];
163 							  goto loop;
164 						}
165 				default:
166 					mtx_unlock(&pAdapter->lock);
167 					return -EINVAL;
168 			}
169 			mtx_unlock(&pAdapter->lock);
170 			return orig_length;
171 		}
172 	}
173 	else if (length>=7 && strncmp(buffer, "verify ", 7)==0)
174 	{
175 		buffer+=7;
176 		length-=7;
177         if (length>=6 && strncmp(buffer, "start ", 6)==0)
178 		{
179             buffer+=6;
180 		    length-=6;
181             if (length>=1 && *buffer>='1')
182 			{
183 				iarray = *buffer-'1';
184 				if(iarray >= MAX_VDEVICE_PER_VBUS) {
185 					mtx_unlock(&pAdapter->lock);
186 					return -EINVAL;
187 				}
188 
189 				pArray = _vbus_p->pVDevice[iarray];
190 				if (!pArray || (pArray->vf_online == 0)) {
191 					mtx_unlock(&pAdapter->lock);
192 					return -EINVAL;
193 				}
194 
195 				if(pArray->VDeviceType != VD_RAID_1 && pArray->VDeviceType != VD_RAID_5) {
196 					mtx_unlock(&pAdapter->lock);
197 					return -EINVAL;
198 				}
199 
200 				if (!(pArray->u.array.rf_need_rebuild ||
201 					pArray->u.array.rf_rebuilding ||
202 					pArray->u.array.rf_verifying ||
203 					pArray->u.array.rf_initializing))
204 				{
205 					pArray->u.array.RebuildSectors = 0;
206 					hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, VERIFY);
207 				}
208 		mtx_unlock(&pAdapter->lock);
209                 return orig_length;
210 			}
211 		}
212 		else if (length>=5 && strncmp(buffer, "stop ", 5)==0)
213 		{
214 			buffer+=5;
215 		    length-=5;
216             if (length>=1 && *buffer>='1')
217 			{
218 				iarray = *buffer-'1';
219 				if(iarray >= MAX_VDEVICE_PER_VBUS) {
220 					mtx_unlock(&pAdapter->lock);
221 					return -EINVAL;
222 				}
223 
224 				pArray = _vbus_p->pVDevice[iarray];
225 				if (!pArray || (pArray->vf_online == 0)) {
226 					mtx_unlock(&pAdapter->lock);
227 					return -EINVAL;
228 				}
229 				if(pArray->u.array.rf_verifying)
230 				{
231 				    pArray->u.array.rf_abort_rebuild = 1;
232 				}
233 			    mtx_unlock(&pAdapter->lock);
234 			    return orig_length;
235 			}
236 		}
237 	}
238 	else
239 #ifdef _RAID5N_
240 	if (length>=10 && strncmp(buffer, "writeback ", 10)==0) {
241 	    	buffer+=10;
242 		length-=10;
243 		if (length>=1 && *buffer>='0' && *buffer<='1') {
244 			_vbus_(r5.enable_write_back) = *buffer-'0';
245 			if (_vbus_(r5.enable_write_back))
246 				hpt_printk(("RAID5 write back enabled"));
247 			mtx_unlock(&pAdapter->lock);
248 			return orig_length;
249 		}
250 	}
251 	else
252 #endif
253 #endif
254 	if (0) {} /* just to compile */
255 #ifdef DEBUG
256 	else if (length>=9 && strncmp(buffer, "dbglevel ", 9)==0) {
257 	    	buffer+=9;
258 		length-=9;
259 		if (length>=1 && *buffer>='0' && *buffer<='3') {
260 			hpt_dbg_level = *buffer-'0';
261 			mtx_unlock(&pAdapter->lock);
262 			return orig_length;
263 		}
264 	}
265 	else if (length>=8 && strncmp(buffer, "disable ", 8)==0) {
266 		/* TO DO */
267 	}
268 #endif
269 	mtx_unlock(&pAdapter->lock);
270 
271 	return -EINVAL;
272 }
273 
274 /*
275  * Since we have only one sysctl node, add adapter ID in the command
276  * line string: e.g. "hpt 0 rebuild start"
277  */
278 static int
279 hpt_set_info(int length)
280 {
281 	int retval;
282 
283 #ifdef SUPPORT_IOCTL
284 	PUCHAR ke_area;
285 	int err;
286 	DWORD dwRet;
287 	PHPT_IOCTL_PARAM piop;
288 #endif
289 	char *buffer = hptproc_buffer;
290 	if (length >= 6) {
291 		if (strncmp(buffer,"hpt ",4) == 0) {
292 			IAL_ADAPTER_T *pAdapter;
293 			retval = buffer[4]-'0';
294 			for (pAdapter=gIal_Adapter; pAdapter; pAdapter=pAdapter->next) {
295 				if (pAdapter->mvSataAdapter.adapterId==retval)
296 					return (retval = hpt_set_asc_info(pAdapter, buffer+6, length-6)) >= 0? retval : -EINVAL;
297 			}
298 			return -EINVAL;
299 		}
300 #ifdef SUPPORT_IOCTL
301 		piop = (PHPT_IOCTL_PARAM)buffer;
302 		if (piop->Magic == HPT_IOCTL_MAGIC ||
303 			piop->Magic == HPT_IOCTL_MAGIC32) 	{
304 			KdPrintE(("ioctl=%d in=%p len=%d out=%p len=%d\n",
305 				piop->dwIoControlCode,
306         			piop->lpInBuffer,
307         			piop->nInBufferSize,
308         			piop->lpOutBuffer,
309 	        		piop->nOutBufferSize));
310 
311 			/*
312         	 	 * map buffer to kernel.
313         	 	 */
314         		if (piop->nInBufferSize+piop->nOutBufferSize > PAGE_SIZE) {
315         			KdPrintE(("User buffer too large\n"));
316         			return -EINVAL;
317         		}
318 
319         		ke_area = malloc(piop->nInBufferSize+piop->nOutBufferSize, M_DEVBUF, M_NOWAIT);
320 				if (ke_area == NULL) {
321 					KdPrintE(("Couldn't allocate kernel mem.\n"));
322 					return -EINVAL;
323 				}
324 
325 			if (piop->nInBufferSize)
326 				copyin((void*)(ULONG_PTR)piop->lpInBuffer, ke_area, piop->nInBufferSize);
327 
328 			/*
329 			  * call kernel handler.
330 			  */
331 			err = Kernel_DeviceIoControl(&gIal_Adapter->VBus,
332 				piop->dwIoControlCode, ke_area, piop->nInBufferSize,
333 				ke_area + piop->nInBufferSize, piop->nOutBufferSize, &dwRet);
334 
335 			if (err==0) {
336 				if (piop->nOutBufferSize)
337 					copyout(ke_area + piop->nInBufferSize, (void*)(ULONG_PTR)piop->lpOutBuffer, piop->nOutBufferSize);
338 
339 				if (piop->lpBytesReturned)
340 					copyout(&dwRet, (void*)(ULONG_PTR)piop->lpBytesReturned, sizeof(DWORD));
341 
342 				free(ke_area, M_DEVBUF);
343 				return length;
344 			}
345 			else  KdPrintW(("Kernel_ioctl(): return %d\n", err));
346 
347 			free(ke_area, M_DEVBUF);
348             		return -EINVAL;
349 		} else 	{
350     		KdPrintW(("Wrong signature: %x\n", piop->Magic));
351     		return -EINVAL;
352 		}
353 #endif
354 	}
355 
356 	return -EINVAL;
357 }
358 
359 #define shortswap(w) ((WORD)((w)>>8 | ((w) & 0xFF)<<8))
360 
361 static void
362 get_disk_name(char *name, PDevice pDev)
363 {
364 	int i;
365 	MV_SATA_CHANNEL *pMvSataChannel = pDev->mv;
366 	IDENTIFY_DATA2 *pIdentifyData = (IDENTIFY_DATA2 *)pMvSataChannel->identifyDevice;
367 
368 	for (i = 0; i < 10; i++)
369 		((WORD*)name)[i] = shortswap(pIdentifyData->ModelNumber[i]);
370 	name[20] = '\0';
371 }
372 
373 static int
374 hpt_copy_info(HPT_GET_INFO *pinfo, char *fmt, ...)
375 {
376 	int printfretval;
377 	va_list ap;
378 
379 	if(fmt == NULL) {
380 		*hptproc_buffer = 0;
381 		return (SYSCTL_OUT(pinfo, hptproc_buffer, 1));
382 	}
383 	else
384 	{
385 		va_start(ap, fmt);
386 		printfretval = vsnprintf(hptproc_buffer, sizeof(hptproc_buffer), fmt, ap);
387 		va_end(ap);
388 		return(SYSCTL_OUT(pinfo, hptproc_buffer, strlen(hptproc_buffer)));
389 	}
390 }
391 
392 static void
393 hpt_copy_disk_info(HPT_GET_INFO *pinfo, PVDevice pVDev, UINT iChan)
394 {
395 	char name[32], arrayname[16], *status;
396 
397 	get_disk_name(name, &pVDev->u.disk);
398 
399 	if (!pVDev->u.disk.df_on_line)
400 		status = "Disabled";
401 	else if (pVDev->VDeviceType==VD_SPARE)
402 		status = "Spare   ";
403 	else
404 		status = "Normal  ";
405 
406 #ifdef SUPPORT_ARRAY
407 	if(pVDev->pParent) {
408 		memcpy(arrayname, pVDev->pParent->u.array.ArrayName, MAX_ARRAY_NAME);
409 		if (pVDev->pParent->u.array.CriticalMembers & (1<<pVDev->bSerialNumber))
410 			status = "Degraded";
411 	}
412 	else
413 #endif
414 		arrayname[0]=0;
415 
416 	hpt_copy_info(pinfo, "Channel %d  %s  %5dMB  %s %s\n",
417 		iChan+1,
418 		name, pVDev->VDeviceCapacity>>11, status, arrayname);
419 }
420 
421 #ifdef SUPPORT_ARRAY
422 static void
423 hpt_copy_array_info(HPT_GET_INFO *pinfo, int nld, PVDevice pArray)
424 {
425 	int i;
426 	char *sType=0, *sStatus=0;
427 	char buf[32];
428     PVDevice pTmpArray;
429 
430 	switch (pArray->VDeviceType) {
431 		case VD_RAID_0:
432 			for (i = 0; (UCHAR)i < pArray->u.array.bArnMember; i++)
433 		  		if(pArray->u.array.pMember[i])	{
434 			  		if(mIsArray(pArray->u.array.pMember[i]))
435 				 		sType = "RAID 1/0   ";
436 			  			/* TO DO */
437 			  		else
438 				 		sType = "RAID 0     ";
439 			  		break;
440 		  		}
441 			break;
442 
443 		case VD_RAID_1:
444 			sType = "RAID 1     ";
445 			break;
446 
447 		case VD_JBOD:
448 			sType = "JBOD       ";
449 			break;
450 
451 		case VD_RAID_5:
452        		sType = "RAID 5     ";
453 			break;
454 
455 		default:
456 			sType = "N/A        ";
457 			break;
458 	}
459 
460 	if (pArray->vf_online == 0)
461 		sStatus = "Disabled";
462 	else if (pArray->u.array.rf_broken)
463 		sStatus = "Critical";
464 	for (i = 0; (UCHAR)i < pArray->u.array.bArnMember; i++)
465 	{
466 		if (!sStatus)
467 		{
468 			if(mIsArray(pArray->u.array.pMember[i]))
469                 		pTmpArray = pArray->u.array.pMember[i];
470 			else
471 			   	pTmpArray = pArray;
472 
473 			if (pTmpArray->u.array.rf_rebuilding) {
474 #ifdef DEBUG
475 				sprintf(buf, "Rebuilding %lldMB", (pTmpArray->u.array.RebuildSectors>>11));
476 #else
477 				sprintf(buf, "Rebuilding %d%%", (UINT)((pTmpArray->u.array.RebuildSectors>>11)*100/((pTmpArray->VDeviceCapacity/(pTmpArray->u.array.bArnMember-1))>>11)));
478 #endif
479 				sStatus = buf;
480 			}
481 			else if (pTmpArray->u.array.rf_verifying) {
482 				sprintf(buf, "Verifying %d%%", (UINT)((pTmpArray->u.array.RebuildSectors>>11)*100/((pTmpArray->VDeviceCapacity/(pTmpArray->u.array.bArnMember-1))>>11)));
483 				sStatus = buf;
484 			}
485 			else if (pTmpArray->u.array.rf_need_rebuild)
486 				sStatus = "Critical";
487 			else if (pTmpArray->u.array.rf_broken)
488 				sStatus = "Critical";
489 
490 			if(pTmpArray == pArray) goto out;
491 		}
492 		else
493 			goto out;
494 	}
495 out:
496 	if (!sStatus) sStatus = "Normal";
497 	hpt_copy_info(pinfo, "%2d  %11s  %-20s  %5lldMB  %-16s", nld, sType, pArray->u.array.ArrayName, pArray->VDeviceCapacity>>11, sStatus);
498 }
499 #endif
500 
501 static int
502 hpt_get_info(IAL_ADAPTER_T *pAdapter, HPT_GET_INFO *pinfo)
503 {
504 	PVBus _vbus_p = &pAdapter->VBus;
505 	struct cam_periph *periph = NULL;
506 	UINT channel,j,i;
507 	PVDevice pVDev;
508 
509 #ifndef FOR_DEMO
510 	mtx_lock(&pAdapter->lock);
511 	if (pAdapter->beeping) {
512 		pAdapter->beeping = 0;
513 		BeepOff(pAdapter->mvSataAdapter.adapterIoBaseAddress);
514 	}
515 	mtx_unlock(&pAdapter->lock);
516 #endif
517 
518 	hpt_copy_info(pinfo, "Controller #%d:\n\n", pAdapter->mvSataAdapter.adapterId);
519 
520 	hpt_copy_info(pinfo, "Physical device list\n");
521 	hpt_copy_info(pinfo, "Channel    Model                Capacity  Status   Array\n");
522 	hpt_copy_info(pinfo, "-------------------------------------------------------------------\n");
523 
524     for (channel = 0; channel < MV_SATA_CHANNELS_NUM; channel++)
525 	{
526 		pVDev = &(pAdapter->VDevices[channel]);
527 		if(pVDev->u.disk.df_on_line)
528 			 hpt_copy_disk_info(pinfo, pVDev, channel);
529 	}
530 
531 	hpt_copy_info(pinfo, "\nLogical device list\n");
532 	hpt_copy_info(pinfo, "No. Type         Name                 Capacity  Status            OsDisk\n");
533 	hpt_copy_info(pinfo, "--------------------------------------------------------------------------\n");
534 
535 	j=1;
536 	for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++){
537         pVDev = _vbus_p->pVDevice[i];
538 		if(pVDev){
539 			j=i+1;
540 #ifdef SUPPORT_ARRAY
541 			if (mIsArray(pVDev))
542 			{
543 		is_array:
544 				hpt_copy_array_info(pinfo, j, pVDev);
545 			}
546 			else
547 #endif
548 			{
549 				char name[32];
550 				/* it may be add to an array after driver loaded, check it */
551 #ifdef SUPPORT_ARRAY
552 				if (pVDev->pParent)
553 					/* in this case, pVDev can only be a RAID 1 source disk. */
554 					if (pVDev->pParent->VDeviceType==VD_RAID_1 && pVDev==pVDev->pParent->u.array.pMember[0])
555 						goto is_array;
556 #endif
557 				get_disk_name(name, &pVDev->u.disk);
558 
559 				hpt_copy_info(pinfo, "%2d  %s  %s  %5dMB  %-16s",
560 					j, "Single disk", name, pVDev->VDeviceCapacity>>11,
561 					/* gmm 2001-6-19: Check if pDev has been added to an array. */
562 					((pVDev->pParent) ? "Unavailable" : "Normal"));
563 			}
564 			periph = hpt_get_periph(pAdapter->mvSataAdapter.adapterId, i);
565 			if (periph == NULL)
566 				hpt_copy_info(pinfo,"  %s\n","not registered");
567 			else
568 				hpt_copy_info(pinfo,"  %s%d\n", periph->periph_name, periph->unit_number);
569 		 }
570 	}
571 	return 0;
572 }
573 
574 static __inline int
575 hpt_proc_in(FORMAL_HANDLER_ARGS, int *len)
576 {
577 	int i, error=0;
578 
579 	*len = 0;
580 	if ((req->newlen - req->newidx) >= sizeof(hptproc_buffer)) {
581 		error = EINVAL;
582 	} else {
583 		i = (req->newlen - req->newidx);
584 		error = SYSCTL_IN(req, hptproc_buffer, i);
585 		if (!error)
586 			*len = i;
587 		(hptproc_buffer)[i] = '\0';
588 	}
589 	return (error);
590 }
591 
592 static int
593 hpt_status(FORMAL_HANDLER_ARGS)
594 {
595 	int length, error=0, retval=0;
596 	IAL_ADAPTER_T *pAdapter;
597 
598 	error = hpt_proc_in(REAL_HANDLER_ARGS, &length);
599 
600     if (req->newptr != NULL)
601 	{
602 		if (error || length == 0)
603 		{
604     		KdPrint(("error!\n"));
605     		retval = EINVAL;
606     		goto out;
607 		}
608 
609 		if (hpt_set_info(length) >= 0)
610 			retval = 0;
611 		else
612 			retval = EINVAL;
613 		goto out;
614     }
615 
616 	hpt_copy_info(req, "%s Version %s\n", DRIVER_NAME, DRIVER_VERSION);
617 	for (pAdapter=gIal_Adapter; pAdapter; pAdapter=pAdapter->next) {
618 		if (hpt_get_info(pAdapter, req) < 0) {
619 			retval = EINVAL;
620 			break;
621 		}
622 	}
623 
624 	hpt_copy_info(req, NULL);
625 	goto out;
626 
627 out:
628 	return (retval);
629 }
630 
631 
632 #define xhptregister_node(name) hptregister_node(name)
633 
634 #if __FreeBSD_version >= 1100024
635 #define hptregister_node(name) \
636 	SYSCTL_ROOT_NODE(OID_AUTO, name, CTLFLAG_RW, 0, "Get/Set " #name " state root node"); \
637 	SYSCTL_OID(_ ## name, OID_AUTO, status, CTLTYPE_STRING|CTLFLAG_RW, \
638 	NULL, 0, hpt_status, "A", "Get/Set " #name " state")
639 #else
640 #define hptregister_node(name) \
641 	SYSCTL_NODE(, OID_AUTO, name, CTLFLAG_RW, 0, "Get/Set " #name " state root node"); \
642 	SYSCTL_OID(_ ## name, OID_AUTO, status, CTLTYPE_STRING|CTLFLAG_RW, \
643 	NULL, 0, hpt_status, "A", "Get/Set " #name " state")
644 #endif
645 
646 xhptregister_node(PROC_DIR_NAME);
647