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