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