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