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