kernel: Add D_MPSAFE to the ops of mfi(4), mrsas(4) and twa(4).
[dragonfly.git] / sys / dev / raid / hptmv / ioctl.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: 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 }