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