]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/hptmv/ioctl.c
Add support for USB 3.0 XHCI via ACPI
[FreeBSD/FreeBSD.git] / 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 }