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