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/ioctl.c,v 1.9 2009/04/07 16:38:25 delphij Exp $
27 */
28 /*
29 * ioctl.c ioctl interface implementation
30 */
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/malloc.h>
35
36 #ifndef __KERNEL__
37 #define __KERNEL__
38 #endif
39
40 #include <dev/raid/hptmv/global.h>
41 #include <dev/raid/hptmv/hptintf.h>
42 #include <dev/raid/hptmv/osbsd.h>
43 #include <dev/raid/hptmv/access601.h>
44
45 #pragma pack(1)
46
47 typedef struct _HPT_REBUILD_PARAM
48 {
49 DEVICEID idMirror;
50 DWORD Lba;
51 UCHAR nSector;
52 } HPT_REBUILD_PARAM, *PHPT_REBUILD_PARAM;
53
54 #pragma pack()
55
56 #define MAX_EVENTS 10
57 static HPT_EVENT hpt_event_queue[MAX_EVENTS];
58 static int event_queue_head=0, event_queue_tail=0;
59
60 static int hpt_get_event(PHPT_EVENT pEvent);
61 static int hpt_set_array_state(DEVICEID idArray, DWORD state);
62 static void lock_driver_idle(IAL_ADAPTER_T *pAdapter);
63 static void HPTLIBAPI thread_io_done(_VBUS_ARG PCommand pCmd);
64 static int HPTLIBAPI R1ControlSgl(_VBUS_ARG PCommand pCmd,
65 FPSCAT_GATH pSgTable, int logical);
66
67 static void
68 get_disk_location(PDevice pDev, int *controller, int *channel)
69 {
70 IAL_ADAPTER_T *pAdapTemp;
71 int i, j;
72
73 *controller = *channel = 0;
74
75 for (i=1, pAdapTemp = gIal_Adapter; pAdapTemp; pAdapTemp = pAdapTemp->next, i++) {
76 for (j=0; j<MV_SATA_CHANNELS_NUM; j++) {
77 if (pDev == &pAdapTemp->VDevices[j].u.disk) {
78 *controller = i;
79 *channel = j;
80 return;
81 }
82 }
83 }
84 }
85
86 static int
87 event_queue_add(PHPT_EVENT pEvent)
88 {
89 int p;
90 p = (event_queue_tail + 1) % MAX_EVENTS;
91 if (p==event_queue_head)
92 {
93 return -1;
94 }
95 hpt_event_queue[event_queue_tail] = *pEvent;
96 event_queue_tail = p;
97 return 0;
98 }
99
100 static int
101 event_queue_remove(PHPT_EVENT pEvent)
102 {
103 if (event_queue_head != event_queue_tail)
104 {
105 *pEvent = hpt_event_queue[event_queue_head];
106 event_queue_head++;
107 event_queue_head %= MAX_EVENTS;
108 return 0;
109 }
110 return -1;
111 }
112
113 void HPTLIBAPI
114 ioctl_ReportEvent(UCHAR event, PVOID param)
115 {
116 HPT_EVENT e;
117 ZeroMemory(&e, sizeof(e));
118 e.EventType = event;
119 switch(event)
120 {
121 case ET_INITIALIZE_ABORTED:
122 case ET_INITIALIZE_FAILED:
123 memcpy(e.Data, ((PVDevice)param)->u.array.ArrayName, MAX_ARRAY_NAME);
124 case ET_INITIALIZE_STARTED:
125 case ET_INITIALIZE_FINISHED:
126
127 case ET_REBUILD_STARTED:
128 case ET_REBUILD_ABORTED:
129 case ET_REBUILD_FAILED:
130 case ET_REBUILD_FINISHED:
131
132 case ET_VERIFY_STARTED:
133 case ET_VERIFY_ABORTED:
134 case ET_VERIFY_FAILED:
135 case ET_VERIFY_FINISHED:
136 case ET_VERIFY_DATA_ERROR:
137
138 case ET_SPARE_TOOK_OVER:
139 case ET_DEVICE_REMOVED:
140 case ET_DEVICE_PLUGGED:
141 case ET_DEVICE_ERROR:
142 e.DeviceID = VDEV_TO_ID((PVDevice)param);
143 break;
144
145 default:
146 break;
147 }
148 event_queue_add(&e);
149 if (event==ET_DEVICE_REMOVED) {
150 int controller, channel;
151 get_disk_location(&((PVDevice)param)->u.disk, &controller, &channel);
152 hpt_printk(("Device removed: controller %d channel %d\n", controller, channel));
153 }
154 }
155
156 static int
157 hpt_delete_array(_VBUS_ARG DEVICEID id, DWORD options)
158 {
159 PVDevice pArray = ID_TO_VDEV(id);
160 BOOLEAN del_block0 = (options & DAF_KEEP_DATA_IF_POSSIBLE)?0:1;
161 int i;
162 PVDevice pa;
163
164 if ((id==0) || check_VDevice_valid(pArray))
165 return -1;
166
167 if(!mIsArray(pArray)) return -1;
168
169 if (pArray->u.array.rf_rebuilding || pArray->u.array.rf_verifying ||
170 pArray->u.array.rf_initializing)
171 return -1;
172
173 for(i=0; i<pArray->u.array.bArnMember; i++) {
174 pa = pArray->u.array.pMember[i];
175 if (pa && mIsArray(pa)) {
176 if (pa->u.array.rf_rebuilding || pa->u.array.rf_verifying ||
177 pa->u.array.rf_initializing)
178 return -1;
179 }
180 }
181
182 if (pArray->pVBus!=_vbus_p) { HPT_ASSERT(0); return -1;}
183 fDeleteArray(_VBUS_P pArray, del_block0);
184 return 0;
185
186 }
187
188 /* just to prevent driver from sending more commands */
189 static void HPTLIBAPI nothing(_VBUS_ARG void *notused){}
190
191 void
192 lock_driver_idle(IAL_ADAPTER_T *pAdapter)
193 {
194 _VBUS_INST(&pAdapter->VBus)
195 lock_driver();
196 while (pAdapter->outstandingCommands) {
197 KdPrint(("outstandingCommands is %d, wait..\n", pAdapter->outstandingCommands));
198 if (!mWaitingForIdle(_VBUS_P0)) CallWhenIdle(_VBUS_P nothing, 0);
199 unlock_driver();
200 /*Schedule out*/
201 tsleep(lock_driver_idle, 0, "switch", 1);
202 lock_driver();
203 }
204 CheckIdleCall(_VBUS_P0);
205 }
206
207 int Kernel_DeviceIoControl(_VBUS_ARG
208 DWORD dwIoControlCode, /* operation control code */
209 PVOID lpInBuffer, /* input data buffer */
210 DWORD nInBufferSize, /* size of input data buffer */
211 PVOID lpOutBuffer, /* output data buffer */
212 DWORD nOutBufferSize, /* size of output data buffer */
213 PDWORD lpBytesReturned /* byte count */
214 )
215 {
216 IAL_ADAPTER_T *pAdapter;
217
218 switch(dwIoControlCode) {
219 case HPT_IOCTL_DELETE_ARRAY:
220 {
221 DEVICEID idArray;
222 int iSuccess;
223 int i;
224 PVDevice pArray;
225 PVBus _vbus_p;
226 struct cam_periph *periph = NULL;
227
228 if (nInBufferSize!=sizeof(DEVICEID)+sizeof(DWORD)) return -1;
229 if (nOutBufferSize!=sizeof(int)) return -1;
230 idArray = *(DEVICEID *)lpInBuffer;
231
232 pArray = ID_TO_VDEV(idArray);
233
234 if((idArray == 0) || check_VDevice_valid(pArray))
235 return -1;
236
237 if(!mIsArray(pArray))
238 return -1;
239
240 _vbus_p=pArray->pVBus;
241 pAdapter = (IAL_ADAPTER_T *)_vbus_p->OsExt;
242
243 for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++) {
244 if(pArray == _vbus_p->pVDevice[i])
245 {
246 periph = hpt_get_periph(pAdapter->mvSataAdapter.adapterId, i);
247 if (periph != NULL && periph->refcount >= 1)
248 {
249 hpt_printk(("Can not delete a mounted device.\n"));
250 return -1;
251 }
252 }
253 /* the Mounted Disk isn't delete */
254 }
255
256 iSuccess = hpt_delete_array(_VBUS_P idArray, *(DWORD*)((DEVICEID *)lpInBuffer+1));
257
258 *(int*)lpOutBuffer = iSuccess;
259
260 if(iSuccess != 0)
261 return -1;
262 break;
263 }
264
265 case HPT_IOCTL_GET_EVENT:
266 {
267 PHPT_EVENT pInfo;
268
269 if (nInBufferSize!=0) return -1;
270 if (nOutBufferSize!=sizeof(HPT_EVENT)) return -1;
271
272 pInfo = (PHPT_EVENT)lpOutBuffer;
273
274 if (hpt_get_event(pInfo)!=0)
275 return -1;
276 }
277 break;
278
279 case HPT_IOCTL_SET_ARRAY_STATE:
280 {
281 DEVICEID idArray;
282 DWORD state;
283
284 if (nInBufferSize!=sizeof(HPT_SET_STATE_PARAM)) return -1;
285 if (nOutBufferSize!=0) return -1;
286
287 idArray = ((PHPT_SET_STATE_PARAM)lpInBuffer)->idArray;
288 state = ((PHPT_SET_STATE_PARAM)lpInBuffer)->state;
289
290 if(hpt_set_array_state(idArray, state)!=0)
291 return -1;
292 }
293 break;
294
295 case HPT_IOCTL_RESCAN_DEVICES:
296 {
297 if (nInBufferSize!=0) return -1;
298 if (nOutBufferSize!=0) return -1;
299
300 #ifndef FOR_DEMO
301 /* stop buzzer if user perform rescan */
302 for (pAdapter=gIal_Adapter; pAdapter; pAdapter=pAdapter->next) {
303 if (pAdapter->beeping) {
304 pAdapter->beeping = 0;
305 BeepOff(pAdapter->mvSataAdapter.adapterIoBaseAddress);
306 }
307 }
308 #endif
309 }
310 break;
311
312 default:
313 {
314 PVDevice pVDev;
315 switch(dwIoControlCode) {
316 /* read-only ioctl functions can be called directly. */
317 case HPT_IOCTL_GET_VERSION:
318 case HPT_IOCTL_GET_CONTROLLER_IDS:
319 case HPT_IOCTL_GET_CONTROLLER_COUNT:
320 case HPT_IOCTL_GET_CONTROLLER_INFO:
321 case HPT_IOCTL_GET_CHANNEL_INFO:
322 case HPT_IOCTL_GET_LOGICAL_DEVICES:
323 case HPT_IOCTL_GET_DEVICE_INFO:
324 case HPT_IOCTL_GET_DEVICE_INFO_V2:
325 case HPT_IOCTL_GET_EVENT:
326 case HPT_IOCTL_GET_DRIVER_CAPABILITIES:
327 if(hpt_default_ioctl(_VBUS_P dwIoControlCode, lpInBuffer, nInBufferSize,
328 lpOutBuffer, nOutBufferSize, lpBytesReturned) == -1) return -1;
329 break;
330
331 default:
332 /*
333 * GUI always use /proc/scsi/hptmv/0, so the _vbus_p param will be
334 * wrong for second controller.
335 */
336 switch(dwIoControlCode) {
337 case HPT_IOCTL_CREATE_ARRAY:
338 pVDev = ID_TO_VDEV(((PCREATE_ARRAY_PARAMS)lpInBuffer)->Members[0]); break;
339 case HPT_IOCTL_CREATE_ARRAY_V2:
340 pVDev = ID_TO_VDEV(((PCREATE_ARRAY_PARAMS_V2)lpInBuffer)->Members[0]); break;
341 case HPT_IOCTL_SET_ARRAY_INFO:
342 pVDev = ID_TO_VDEV(((PHPT_SET_ARRAY_INFO)lpInBuffer)->idArray); break;
343 case HPT_IOCTL_SET_DEVICE_INFO:
344 pVDev = ID_TO_VDEV(((PHPT_SET_DEVICE_INFO)lpInBuffer)->idDisk); break;
345 case HPT_IOCTL_SET_DEVICE_INFO_V2:
346 pVDev = ID_TO_VDEV(((PHPT_SET_DEVICE_INFO_V2)lpInBuffer)->idDisk); break;
347 case HPT_IOCTL_SET_BOOT_MARK:
348 case HPT_IOCTL_ADD_SPARE_DISK:
349 case HPT_IOCTL_REMOVE_SPARE_DISK:
350 pVDev = ID_TO_VDEV(*(DEVICEID *)lpInBuffer); break;
351 case HPT_IOCTL_ADD_DISK_TO_ARRAY:
352 pVDev = ID_TO_VDEV(((PHPT_ADD_DISK_TO_ARRAY)lpInBuffer)->idArray); break;
353 default:
354 pVDev = 0;
355 }
356
357 if (pVDev && !check_VDevice_valid(pVDev)){
358 _vbus_p = pVDev->pVBus;
359
360 pAdapter = (IAL_ADAPTER_T *)_vbus_p->OsExt;
361 /*
362 * create_array, and other functions can't be executed while channel is
363 * perform I/O commands. Wait until driver is idle.
364 */
365 lock_driver_idle(pAdapter);
366 if (hpt_default_ioctl(_VBUS_P dwIoControlCode, lpInBuffer, nInBufferSize,
367 lpOutBuffer, nOutBufferSize, lpBytesReturned) == -1) {
368 unlock_driver();
369 return -1;
370 }
371 unlock_driver();
372 }
373 else
374 return -1;
375 break;
376 }
377
378 #ifdef SUPPORT_ARRAY
379 switch(dwIoControlCode)
380 {
381 case HPT_IOCTL_CREATE_ARRAY:
382 {
383 pAdapter=(IAL_ADAPTER_T *)(ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->pVBus->OsExt;
384 lock_driver();
385 if(((PCREATE_ARRAY_PARAMS)lpInBuffer)->CreateFlags & CAF_CREATE_AND_DUPLICATE)
386 {
387 (ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->u.array.rf_auto_rebuild = 0;
388 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), DUPLICATE);
389 }
390 else if(((PCREATE_ARRAY_PARAMS)lpInBuffer)->CreateFlags & CAF_CREATE_R5_ZERO_INIT)
391 {
392 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), INITIALIZE);
393 }
394 else if(((PCREATE_ARRAY_PARAMS)lpInBuffer)->CreateFlags & CAF_CREATE_R5_BUILD_PARITY)
395 {
396 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), REBUILD_PARITY);
397 }
398 unlock_driver();
399 break;
400 }
401
402
403 case HPT_IOCTL_CREATE_ARRAY_V2:
404 {
405 pAdapter=(IAL_ADAPTER_T *)(ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->pVBus->OsExt;
406 lock_driver();
407 if(((PCREATE_ARRAY_PARAMS_V2)lpInBuffer)->CreateFlags & CAF_CREATE_AND_DUPLICATE) {
408 (ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->u.array.rf_auto_rebuild = 0;
409 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), DUPLICATE);
410 } else if(((PCREATE_ARRAY_PARAMS_V2)lpInBuffer)->CreateFlags & CAF_CREATE_R5_ZERO_INIT) {
411 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), INITIALIZE);
412 } else if(((PCREATE_ARRAY_PARAMS_V2)lpInBuffer)->CreateFlags & CAF_CREATE_R5_BUILD_PARITY) {
413 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), REBUILD_PARITY);
414 }
415 unlock_driver();
416 break;
417 }
418 case HPT_IOCTL_ADD_DISK_TO_ARRAY:
419 {
420 PVDevice pArray = ID_TO_VDEV(((PHPT_ADD_DISK_TO_ARRAY)lpInBuffer)->idArray);
421 pAdapter=(IAL_ADAPTER_T *)pArray->pVBus->OsExt;
422 if(pArray->u.array.rf_rebuilding == 0)
423 {
424 DWORD timeout = 0;
425 lock_driver();
426 pArray->u.array.rf_auto_rebuild = 0;
427 pArray->u.array.rf_abort_rebuild = 0;
428 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, DUPLICATE);
429 unlock_driver();
430 while (!pArray->u.array.rf_rebuilding)
431 {
432 tsleep((caddr_t)Kernel_DeviceIoControl, 0, "pause", 1);
433 if ( timeout >= hz*3)
434 break;
435 timeout ++;
436 }
437 }
438 break;
439 }
440 }
441 #endif
442 return 0;
443 }
444 }
445
446 if (lpBytesReturned)
447 *lpBytesReturned = nOutBufferSize;
448 return 0;
449 }
450
451 static int
452 hpt_get_event(PHPT_EVENT pEvent)
453 {
454 lock_driver();
455 int ret = event_queue_remove(pEvent);
456 unlock_driver();
457 return ret;
458 }
459
460 static int
461 hpt_set_array_state(DEVICEID idArray, DWORD state)
462 {
463 IAL_ADAPTER_T *pAdapter;
464 PVDevice pVDevice = ID_TO_VDEV(idArray);
465 int i;
466 DWORD timeout = 0;
467
468 if(idArray == 0 || check_VDevice_valid(pVDevice)) return -1;
469 if(!mIsArray(pVDevice))
470 return -1;
471 if(!pVDevice->vf_online || pVDevice->u.array.rf_broken) return -1;
472
473 pAdapter=(IAL_ADAPTER_T *)pVDevice->pVBus->OsExt;
474
475 switch(state)
476 {
477 case MIRROR_REBUILD_START:
478 {
479 if (pVDevice->u.array.rf_rebuilding ||
480 pVDevice->u.array.rf_verifying ||
481 pVDevice->u.array.rf_initializing)
482 return -1;
483
484 lock_driver();
485
486 pVDevice->u.array.rf_auto_rebuild = 0;
487 pVDevice->u.array.rf_abort_rebuild = 0;
488
489 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pVDevice,
490 (UCHAR)((pVDevice->u.array.CriticalMembers || pVDevice->VDeviceType == VD_RAID_1)? DUPLICATE : REBUILD_PARITY));
491
492 unlock_driver();
493
494 while (!pVDevice->u.array.rf_rebuilding)
495 {
496 tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1);
497 if ( timeout >= hz*20)
498 break;
499 timeout ++;
500 }
501 }
502
503 break;
504
505 case MIRROR_REBUILD_ABORT:
506 {
507 for(i = 0; i < pVDevice->u.array.bArnMember; i++) {
508 if(pVDevice->u.array.pMember[i] != 0 && pVDevice->u.array.pMember[i]->VDeviceType == VD_RAID_1)
509 hpt_set_array_state(VDEV_TO_ID(pVDevice->u.array.pMember[i]), state);
510 }
511
512 if(pVDevice->u.array.rf_rebuilding != 1)
513 return -1;
514
515 lock_driver();
516 pVDevice->u.array.rf_abort_rebuild = 1;
517 unlock_driver();
518
519 while (pVDevice->u.array.rf_abort_rebuild)
520 {
521 tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1);
522 if ( timeout >= hz*20)
523 break;
524 timeout ++;
525 }
526 }
527 break;
528
529 case AS_VERIFY_START:
530 {
531 /*if(pVDevice->u.array.rf_verifying)
532 return -1;*/
533 if (pVDevice->u.array.rf_rebuilding ||
534 pVDevice->u.array.rf_verifying ||
535 pVDevice->u.array.rf_initializing)
536 return -1;
537
538 lock_driver();
539 pVDevice->u.array.RebuildSectors = 0;
540 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pVDevice, VERIFY);
541 unlock_driver();
542
543 while (!pVDevice->u.array.rf_verifying)
544 {
545 tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1);
546 if ( timeout >= hz*20)
547 break;
548 timeout ++;
549 }
550 }
551 break;
552
553 case AS_VERIFY_ABORT:
554 {
555 if(pVDevice->u.array.rf_verifying != 1)
556 return -1;
557
558 lock_driver();
559 pVDevice->u.array.rf_abort_rebuild = 1;
560 unlock_driver();
561
562 while (pVDevice->u.array.rf_abort_rebuild)
563 {
564 tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1);
565 if ( timeout >= hz*80)
566 break;
567 timeout ++;
568 }
569 }
570 break;
571
572 case AS_INITIALIZE_START:
573 {
574 if (pVDevice->u.array.rf_rebuilding ||
575 pVDevice->u.array.rf_verifying ||
576 pVDevice->u.array.rf_initializing)
577 return -1;
578
579 lock_driver();
580 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pVDevice, VERIFY);
581 unlock_driver();
582
583 while (!pVDevice->u.array.rf_initializing)
584 {
585 tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1);
586 if ( timeout >= hz*80)
587 break;
588 timeout ++;
589 }
590 }
591 break;
592
593 case AS_INITIALIZE_ABORT:
594 {
595 if(pVDevice->u.array.rf_initializing != 1)
596 return -1;
597
598 lock_driver();
599 pVDevice->u.array.rf_abort_rebuild = 1;
600 unlock_driver();
601
602 while (pVDevice->u.array.rf_abort_rebuild)
603 {
604 tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1);
605 if ( timeout >= hz*80)
606 break;
607 timeout ++;
608 }
609 }
610 break;
611
612 default:
613 return -1;
614 }
615
616 return 0;
617 }
618
619 int HPTLIBAPI
620 R1ControlSgl(_VBUS_ARG PCommand pCmd, FPSCAT_GATH pSgTable, int logical)
621 {
622 ULONG bufferSize = SECTOR_TO_BYTE(pCmd->uCmd.R1Control.nSectors);
623 if (pCmd->uCmd.R1Control.Command==CTRL_CMD_VERIFY)
624 bufferSize<<=1;
625 if (logical) {
626 pSgTable->dSgAddress = (ULONG_PTR)pCmd->uCmd.R1Control.Buffer;
627 pSgTable->wSgSize = (USHORT)bufferSize;
628 pSgTable->wSgFlag = SG_FLAG_EOT;
629 }
630 else {
631 /* build physical SG table for pCmd->uCmd.R1Control.Buffer */
632 ADDRESS dataPointer, v, nextpage, currvaddr, nextvaddr, currphypage, nextphypage;
633 ULONG length;
634 int idx = 0;
635
636 v = pCmd->uCmd.R1Control.Buffer;
637 dataPointer = (ADDRESS)fOsPhysicalAddress(v);
638
639 if ((ULONG_PTR)dataPointer & 0x1)
640 return FALSE;
641
642 #define ON64KBOUNDARY(x) (((ULONG_PTR)(x) & 0xFFFF) == 0)
643 #define NOTNEIGHBORPAGE(highvaddr, lowvaddr) ((ULONG_PTR)(highvaddr) - (ULONG_PTR)(lowvaddr) != PAGE_SIZE)
644
645 do {
646 if (idx >= MAX_SG_DESCRIPTORS) return FALSE;
647
648 pSgTable[idx].dSgAddress = fOsPhysicalAddress(v);
649 currvaddr = v;
650 currphypage = (ADDRESS)fOsPhysicalAddress((void*)trunc_page((ULONG_PTR)currvaddr));
651
652
653 do {
654 nextpage = (ADDRESS)trunc_page(((ULONG_PTR)currvaddr + PAGE_SIZE));
655 nextvaddr = (ADDRESS)MIN(((ULONG_PTR)v + bufferSize), (ULONG_PTR)(nextpage));
656
657 if (nextvaddr == (ADDRESS)((ULONG_PTR)v + bufferSize)) break;
658 nextphypage = (ADDRESS)fOsPhysicalAddress(nextpage);
659
660 if (NOTNEIGHBORPAGE(nextphypage, currphypage) || ON64KBOUNDARY(nextphypage)) {
661 nextvaddr = nextpage;
662 break;
663 }
664
665 currvaddr = nextvaddr;
666 currphypage = nextphypage;
667 }while (1);
668
669 length = (ULONG_PTR)nextvaddr - (ULONG_PTR)v;
670 v = nextvaddr;
671 bufferSize -= length;
672
673 pSgTable[idx].wSgSize = (USHORT)length;
674 pSgTable[idx].wSgFlag = (bufferSize)? 0 : SG_FLAG_EOT;
675 idx++;
676
677 }while (bufferSize);
678 }
679 return 1;
680 }
681
682 static int End_Job=0;
683 void HPTLIBAPI
684 thread_io_done(_VBUS_ARG PCommand pCmd)
685 {
686 End_Job = 1;
687 wakeup((caddr_t)pCmd);
688 }
689
690 void
691 hpt_rebuild_data_block(IAL_ADAPTER_T *pAdapter, PVDevice pArray, UCHAR flags)
692 {
693 DWORD timeout = 0;
694 ULONG capacity = pArray->VDeviceCapacity / (pArray->u.array.bArnMember-1);
695 PCommand pCmd;
696 UINT result;
697 int needsync=0, retry=0, needdelete=0;
698 void *buffer = NULL;
699
700 _VBUS_INST(&pAdapter->VBus)
701
702 if (pArray->u.array.rf_broken==1 ||
703 pArray->u.array.RebuildSectors>=capacity)
704 return;
705
706 lock_driver();
707
708 switch(flags)
709 {
710 case DUPLICATE:
711 case REBUILD_PARITY:
712 if(pArray->u.array.rf_rebuilding == 0)
713 {
714 pArray->u.array.rf_rebuilding = 1;
715 hpt_printk(("Rebuilding started.\n"));
716 ioctl_ReportEvent(ET_REBUILD_STARTED, pArray);
717 }
718 break;
719
720 case INITIALIZE:
721 if(pArray->u.array.rf_initializing == 0)
722 {
723 pArray->u.array.rf_initializing = 1;
724 hpt_printk(("Initializing started.\n"));
725 ioctl_ReportEvent(ET_INITIALIZE_STARTED, pArray);
726 }
727 break;
728
729 case VERIFY:
730 if(pArray->u.array.rf_verifying == 0)
731 {
732 pArray->u.array.rf_verifying = 1;
733 hpt_printk(("Verifying started.\n"));
734 ioctl_ReportEvent(ET_VERIFY_STARTED, pArray);
735 }
736 break;
737 }
738
739 retry_cmd:
740 pCmd = AllocateCommand(_VBUS_P0);
741 HPT_ASSERT(pCmd);
742 pCmd->cf_control = 1;
743 End_Job = 0;
744
745 if (pArray->VDeviceType==VD_RAID_1)
746 {
747 #define MAX_REBUILD_SECTORS 0x40
748
749 /* take care for discontinuous buffer in R1ControlSgl */
750 unlock_driver();
751 buffer = kmalloc(SECTOR_TO_BYTE(MAX_REBUILD_SECTORS), M_DEVBUF, M_NOWAIT);
752 lock_driver();
753 if(!buffer) {
754 FreeCommand(_VBUS_P pCmd);
755 hpt_printk(("can't allocate rebuild buffer\n"));
756 goto fail;
757 }
758 switch(flags)
759 {
760 case DUPLICATE:
761 pCmd->uCmd.R1Control.Command = CTRL_CMD_REBUILD;
762 pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS;
763 break;
764
765 case VERIFY:
766 pCmd->uCmd.R1Control.Command = CTRL_CMD_VERIFY;
767 pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS/2;
768 break;
769
770 case INITIALIZE:
771 pCmd->uCmd.R1Control.Command = CTRL_CMD_REBUILD;
772 pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS;
773 break;
774 }
775
776 pCmd->uCmd.R1Control.Lba = pArray->u.array.RebuildSectors;
777
778 if (capacity - pArray->u.array.RebuildSectors < pCmd->uCmd.R1Control.nSectors)
779 pCmd->uCmd.R1Control.nSectors = capacity - pArray->u.array.RebuildSectors;
780
781 pCmd->uCmd.R1Control.Buffer = buffer;
782 pCmd->pfnBuildSgl = R1ControlSgl;
783 }
784 else if (pArray->VDeviceType==VD_RAID_5)
785 {
786 switch(flags)
787 {
788 case DUPLICATE:
789 case REBUILD_PARITY:
790 pCmd->uCmd.R5Control.Command = CTRL_CMD_REBUILD; break;
791 case VERIFY:
792 pCmd->uCmd.R5Control.Command = CTRL_CMD_VERIFY; break;
793 case INITIALIZE:
794 pCmd->uCmd.R5Control.Command = CTRL_CMD_INIT; break;
795 }
796 pCmd->uCmd.R5Control.StripeLine=pArray->u.array.RebuildSectors>>pArray->u.array.bArBlockSizeShift;
797 }
798 else
799 HPT_ASSERT(0);
800
801 pCmd->pVDevice = pArray;
802 pCmd->pfnCompletion = thread_io_done;
803 pArray->pfnSendCommand(_VBUS_P pCmd);
804 CheckPendingCall(_VBUS_P0);
805
806 if (!End_Job) {
807 unlock_driver();
808 while (!End_Job) {
809 tsleep((caddr_t)pCmd, 0, "pause", hz);
810 if (timeout++>60) break;
811 }
812 lock_driver();
813 if (!End_Job) {
814 hpt_printk(("timeout, reset\n"));
815 fResetVBus(_VBUS_P0);
816 }
817 }
818
819 result = pCmd->Result;
820 FreeCommand(_VBUS_P pCmd);
821 unlock_driver();
822 if (buffer) kfree(buffer, M_DEVBUF);
823 lock_driver();
824 KdPrintI(("cmd finished %d", result));
825
826 switch(result)
827 {
828 case RETURN_SUCCESS:
829 if (!pArray->u.array.rf_abort_rebuild)
830 {
831 if(pArray->u.array.RebuildSectors < capacity)
832 {
833 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, flags);
834 }
835 else
836 {
837 switch (flags)
838 {
839 case DUPLICATE:
840 case REBUILD_PARITY:
841 needsync = 1;
842 pArray->u.array.rf_rebuilding = 0;
843 pArray->u.array.rf_need_rebuild = 0;
844 pArray->u.array.CriticalMembers = 0;
845 pArray->u.array.RebuildSectors = MAX_LBA_T;
846 pArray->u.array.rf_duplicate_and_create = 0;
847 hpt_printk(("Rebuilding finished.\n"));
848 ioctl_ReportEvent(ET_REBUILD_FINISHED, pArray);
849 break;
850 case INITIALIZE:
851 needsync = 1;
852 pArray->u.array.rf_initializing = 0;
853 pArray->u.array.rf_need_rebuild = 0;
854 pArray->u.array.RebuildSectors = MAX_LBA_T;
855 hpt_printk(("Initializing finished.\n"));
856 ioctl_ReportEvent(ET_INITIALIZE_FINISHED, pArray);
857 break;
858 case VERIFY:
859 pArray->u.array.rf_verifying = 0;
860 hpt_printk(("Verifying finished.\n"));
861 ioctl_ReportEvent(ET_VERIFY_FINISHED, pArray);
862 break;
863 }
864 }
865 }
866 else
867 {
868 pArray->u.array.rf_abort_rebuild = 0;
869 if (pArray->u.array.rf_rebuilding)
870 {
871 hpt_printk(("Abort rebuilding.\n"));
872 pArray->u.array.rf_rebuilding = 0;
873 pArray->u.array.rf_duplicate_and_create = 0;
874 ioctl_ReportEvent(ET_REBUILD_ABORTED, pArray);
875 }
876 else if (pArray->u.array.rf_verifying)
877 {
878 hpt_printk(("Abort verifying.\n"));
879 pArray->u.array.rf_verifying = 0;
880 ioctl_ReportEvent(ET_VERIFY_ABORTED, pArray);
881 }
882 else if (pArray->u.array.rf_initializing)
883 {
884 hpt_printk(("Abort initializing.\n"));
885 pArray->u.array.rf_initializing = 0;
886 ioctl_ReportEvent(ET_INITIALIZE_ABORTED, pArray);
887 }
888 needdelete=1;
889 }
890 break;
891
892 case RETURN_DATA_ERROR:
893 if (flags==VERIFY)
894 {
895 needsync = 1;
896 pArray->u.array.rf_verifying = 0;
897 pArray->u.array.rf_need_rebuild = 1;
898 hpt_printk(("Verifying failed: found inconsistency\n"));
899 ioctl_ReportEvent(ET_VERIFY_DATA_ERROR, pArray);
900 ioctl_ReportEvent(ET_VERIFY_FAILED, pArray);
901
902 if (!pArray->vf_online || pArray->u.array.rf_broken) break;
903
904 pArray->u.array.rf_auto_rebuild = 0;
905 pArray->u.array.rf_abort_rebuild = 0;
906 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray,
907 (pArray->VDeviceType == VD_RAID_1) ? DUPLICATE : REBUILD_PARITY);
908 }
909 break;
910
911 default:
912 hpt_printk(("command failed with error %d\n", result));
913 if (++retry<3)
914 {
915 hpt_printk(("retry (%d)\n", retry));
916 goto retry_cmd;
917 }
918 fail:
919 pArray->u.array.rf_abort_rebuild = 0;
920 switch (flags)
921 {
922 case DUPLICATE:
923 case REBUILD_PARITY:
924 needsync = 1;
925 pArray->u.array.rf_rebuilding = 0;
926 pArray->u.array.rf_duplicate_and_create = 0;
927 hpt_printk(((flags==DUPLICATE)? "Duplicating failed.\n":"Rebuilding failed.\n"));
928 ioctl_ReportEvent(ET_REBUILD_FAILED, pArray);
929 break;
930
931 case INITIALIZE:
932 needsync = 1;
933 pArray->u.array.rf_initializing = 0;
934 hpt_printk(("Initializing failed.\n"));
935 ioctl_ReportEvent(ET_INITIALIZE_FAILED, pArray);
936 break;
937
938 case VERIFY:
939 needsync = 1;
940 pArray->u.array.rf_verifying = 0;
941 hpt_printk(("Verifying failed.\n"));
942 ioctl_ReportEvent(ET_VERIFY_FAILED, pArray);
943 break;
944 }
945 needdelete=1;
946 }
947
948 while (pAdapter->outstandingCommands)
949 {
950 KdPrintI(("currcmds is %d, wait..\n", pAdapter->outstandingCommands));
951 /* put this to have driver stop processing system commands quickly */
952 if (!mWaitingForIdle(_VBUS_P0)) CallWhenIdle(_VBUS_P nothing, 0);
953 unlock_driver();
954 /*Schedule out*/
955 tsleep(hpt_rebuild_data_block, 0, "switch", 1);
956 lock_driver();
957 }
958
959 if (needsync) SyncArrayInfo(pArray);
960 if(needdelete && (pArray->u.array.rf_duplicate_must_done || (flags == INITIALIZE)))
961 fDeleteArray(_VBUS_P pArray, TRUE);
962
963 Check_Idle_Call(pAdapter);
964 unlock_driver();
965 }
Cache object: af769eaac0d4e40bb0c52754d88d8d0b
|