xref: /openbmc/linux/drivers/scsi/aacraid/commctrl.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1 /*
2  *	Adaptec AAC series RAID controller driver
3  *	(c) Copyright 2001 Red Hat Inc.	<alan@redhat.com>
4  *
5  * based on the old aacraid driver that is..
6  * Adaptec aacraid device driver for Linux.
7  *
8  * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2, or (at your option)
13  * any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; see the file COPYING.  If not, write to
22  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23  *
24  * Module Name:
25  *  commctrl.c
26  *
27  * Abstract: Contains all routines for control of the AFA comm layer
28  *
29  */
30 
31 #include <linux/kernel.h>
32 #include <linux/init.h>
33 #include <linux/types.h>
34 #include <linux/sched.h>
35 #include <linux/pci.h>
36 #include <linux/spinlock.h>
37 #include <linux/slab.h>
38 #include <linux/completion.h>
39 #include <linux/dma-mapping.h>
40 #include <linux/blkdev.h>
41 #include <asm/semaphore.h>
42 #include <asm/uaccess.h>
43 
44 #include "aacraid.h"
45 
46 /**
47  *	ioctl_send_fib	-	send a FIB from userspace
48  *	@dev:	adapter is being processed
49  *	@arg:	arguments to the ioctl call
50  *
51  *	This routine sends a fib to the adapter on behalf of a user level
52  *	program.
53  */
54 
55 static int ioctl_send_fib(struct aac_dev * dev, void __user *arg)
56 {
57 	struct hw_fib * kfib;
58 	struct fib *fibptr;
59 
60 	fibptr = fib_alloc(dev);
61 	if(fibptr == NULL)
62 		return -ENOMEM;
63 
64 	kfib = fibptr->hw_fib;
65 	/*
66 	 *	First copy in the header so that we can check the size field.
67 	 */
68 	if (copy_from_user((void *)kfib, arg, sizeof(struct aac_fibhdr))) {
69 		fib_free(fibptr);
70 		return -EFAULT;
71 	}
72 	/*
73 	 *	Since we copy based on the fib header size, make sure that we
74 	 *	will not overrun the buffer when we copy the memory. Return
75 	 *	an error if we would.
76 	 */
77 	if (le16_to_cpu(kfib->header.Size) >
78 			sizeof(struct hw_fib) - sizeof(struct aac_fibhdr)) {
79 		fib_free(fibptr);
80 		return -EINVAL;
81 	}
82 
83 	if (copy_from_user(kfib, arg, le16_to_cpu(kfib->header.Size) +
84 				sizeof(struct aac_fibhdr))) {
85 		fib_free(fibptr);
86 		return -EFAULT;
87 	}
88 
89 	if (kfib->header.Command == cpu_to_le32(TakeABreakPt)) {
90 		aac_adapter_interrupt(dev);
91 		/*
92 		 * Since we didn't really send a fib, zero out the state to allow
93 		 * cleanup code not to assert.
94 		 */
95 		kfib->header.XferState = 0;
96 	} else {
97 		int retval = fib_send(kfib->header.Command, fibptr,
98 				le16_to_cpu(kfib->header.Size) , FsaNormal,
99 				1, 1, NULL, NULL);
100 		if (retval) {
101 			fib_free(fibptr);
102 			return retval;
103 		}
104 		if (fib_complete(fibptr) != 0) {
105 			fib_free(fibptr);
106 			return -EINVAL;
107 		}
108 	}
109 	/*
110 	 *	Make sure that the size returned by the adapter (which includes
111 	 *	the header) is less than or equal to the size of a fib, so we
112 	 *	don't corrupt application data. Then copy that size to the user
113 	 *	buffer. (Don't try to add the header information again, since it
114 	 *	was already included by the adapter.)
115 	 */
116 
117 	if (copy_to_user(arg, (void *)kfib, kfib->header.Size)) {
118 		fib_free(fibptr);
119 		return -EFAULT;
120 	}
121 	fib_free(fibptr);
122 	return 0;
123 }
124 
125 /**
126  *	open_getadapter_fib	-	Get the next fib
127  *
128  *	This routine will get the next Fib, if available, from the AdapterFibContext
129  *	passed in from the user.
130  */
131 
132 static int open_getadapter_fib(struct aac_dev * dev, void __user *arg)
133 {
134 	struct aac_fib_context * fibctx;
135 	int status;
136 
137 	fibctx = kmalloc(sizeof(struct aac_fib_context), GFP_KERNEL);
138 	if (fibctx == NULL) {
139 		status = -ENOMEM;
140 	} else {
141 		unsigned long flags;
142 		struct list_head * entry;
143 		struct aac_fib_context * context;
144 
145 		fibctx->type = FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT;
146 		fibctx->size = sizeof(struct aac_fib_context);
147  		/*
148 		 *	Yes yes, I know this could be an index, but we have a
149 		 * better guarantee of uniqueness for the locked loop below.
150 		 * Without the aid of a persistent history, this also helps
151 		 * reduce the chance that the opaque context would be reused.
152 		 */
153 		fibctx->unique = (u32)((ulong)fibctx & 0xFFFFFFFF);
154 		/*
155 		 *	Initialize the mutex used to wait for the next AIF.
156 		 */
157 		init_MUTEX_LOCKED(&fibctx->wait_sem);
158 		fibctx->wait = 0;
159 		/*
160 		 *	Initialize the fibs and set the count of fibs on
161 		 *	the list to 0.
162 		 */
163 		fibctx->count = 0;
164 		INIT_LIST_HEAD(&fibctx->fib_list);
165 		fibctx->jiffies = jiffies/HZ;
166 		/*
167 		 *	Now add this context onto the adapter's
168 		 *	AdapterFibContext list.
169 		 */
170 		spin_lock_irqsave(&dev->fib_lock, flags);
171 		/* Ensure that we have a unique identifier */
172 		entry = dev->fib_list.next;
173 		while (entry != &dev->fib_list) {
174 			context = list_entry(entry, struct aac_fib_context, next);
175 			if (context->unique == fibctx->unique) {
176 				/* Not unique (32 bits) */
177 				fibctx->unique++;
178 				entry = dev->fib_list.next;
179 			} else {
180 				entry = entry->next;
181 			}
182 		}
183 		list_add_tail(&fibctx->next, &dev->fib_list);
184 		spin_unlock_irqrestore(&dev->fib_lock, flags);
185 		if (copy_to_user(arg,  &fibctx->unique,
186 						sizeof(fibctx->unique))) {
187 			status = -EFAULT;
188 		} else {
189 			status = 0;
190 		}
191 	}
192 	return status;
193 }
194 
195 /**
196  *	next_getadapter_fib	-	get the next fib
197  *	@dev: adapter to use
198  *	@arg: ioctl argument
199  *
200  * 	This routine will get the next Fib, if available, from the AdapterFibContext
201  *	passed in from the user.
202  */
203 
204 static int next_getadapter_fib(struct aac_dev * dev, void __user *arg)
205 {
206 	struct fib_ioctl f;
207 	struct fib *fib;
208 	struct aac_fib_context *fibctx;
209 	int status;
210 	struct list_head * entry;
211 	unsigned long flags;
212 
213 	if(copy_from_user((void *)&f, arg, sizeof(struct fib_ioctl)))
214 		return -EFAULT;
215 	/*
216 	 *	Verify that the HANDLE passed in was a valid AdapterFibContext
217 	 *
218 	 *	Search the list of AdapterFibContext addresses on the adapter
219 	 *	to be sure this is a valid address
220 	 */
221 	entry = dev->fib_list.next;
222 	fibctx = NULL;
223 
224 	while (entry != &dev->fib_list) {
225 		fibctx = list_entry(entry, struct aac_fib_context, next);
226 		/*
227 		 *	Extract the AdapterFibContext from the Input parameters.
228 		 */
229 		if (fibctx->unique == f.fibctx) {   /* We found a winner */
230 			break;
231 		}
232 		entry = entry->next;
233 		fibctx = NULL;
234 	}
235 	if (!fibctx) {
236 		dprintk ((KERN_INFO "Fib Context not found\n"));
237 		return -EINVAL;
238 	}
239 
240 	if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) ||
241 		 (fibctx->size != sizeof(struct aac_fib_context))) {
242 		dprintk ((KERN_INFO "Fib Context corrupt?\n"));
243 		return -EINVAL;
244 	}
245 	status = 0;
246 	spin_lock_irqsave(&dev->fib_lock, flags);
247 	/*
248 	 *	If there are no fibs to send back, then either wait or return
249 	 *	-EAGAIN
250 	 */
251 return_fib:
252 	if (!list_empty(&fibctx->fib_list)) {
253 		struct list_head * entry;
254 		/*
255 		 *	Pull the next fib from the fibs
256 		 */
257 		entry = fibctx->fib_list.next;
258 		list_del(entry);
259 
260 		fib = list_entry(entry, struct fib, fiblink);
261 		fibctx->count--;
262 		spin_unlock_irqrestore(&dev->fib_lock, flags);
263 		if (copy_to_user(f.fib, fib->hw_fib, sizeof(struct hw_fib))) {
264 			kfree(fib->hw_fib);
265 			kfree(fib);
266 			return -EFAULT;
267 		}
268 		/*
269 		 *	Free the space occupied by this copy of the fib.
270 		 */
271 		kfree(fib->hw_fib);
272 		kfree(fib);
273 		status = 0;
274 		fibctx->jiffies = jiffies/HZ;
275 	} else {
276 		spin_unlock_irqrestore(&dev->fib_lock, flags);
277 		if (f.wait) {
278 			if(down_interruptible(&fibctx->wait_sem) < 0) {
279 				status = -EINTR;
280 			} else {
281 				/* Lock again and retry */
282 				spin_lock_irqsave(&dev->fib_lock, flags);
283 				goto return_fib;
284 			}
285 		} else {
286 			status = -EAGAIN;
287 		}
288 	}
289 	return status;
290 }
291 
292 int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx)
293 {
294 	struct fib *fib;
295 
296 	/*
297 	 *	First free any FIBs that have not been consumed.
298 	 */
299 	while (!list_empty(&fibctx->fib_list)) {
300 		struct list_head * entry;
301 		/*
302 		 *	Pull the next fib from the fibs
303 		 */
304 		entry = fibctx->fib_list.next;
305 		list_del(entry);
306 		fib = list_entry(entry, struct fib, fiblink);
307 		fibctx->count--;
308 		/*
309 		 *	Free the space occupied by this copy of the fib.
310 		 */
311 		kfree(fib->hw_fib);
312 		kfree(fib);
313 	}
314 	/*
315 	 *	Remove the Context from the AdapterFibContext List
316 	 */
317 	list_del(&fibctx->next);
318 	/*
319 	 *	Invalidate context
320 	 */
321 	fibctx->type = 0;
322 	/*
323 	 *	Free the space occupied by the Context
324 	 */
325 	kfree(fibctx);
326 	return 0;
327 }
328 
329 /**
330  *	close_getadapter_fib	-	close down user fib context
331  *	@dev: adapter
332  *	@arg: ioctl arguments
333  *
334  *	This routine will close down the fibctx passed in from the user.
335  */
336 
337 static int close_getadapter_fib(struct aac_dev * dev, void __user *arg)
338 {
339 	struct aac_fib_context *fibctx;
340 	int status;
341 	unsigned long flags;
342 	struct list_head * entry;
343 
344 	/*
345 	 *	Verify that the HANDLE passed in was a valid AdapterFibContext
346 	 *
347 	 *	Search the list of AdapterFibContext addresses on the adapter
348 	 *	to be sure this is a valid address
349 	 */
350 
351 	entry = dev->fib_list.next;
352 	fibctx = NULL;
353 
354 	while(entry != &dev->fib_list) {
355 		fibctx = list_entry(entry, struct aac_fib_context, next);
356 		/*
357 		 *	Extract the fibctx from the input parameters
358 		 */
359 		if (fibctx->unique == (u32)(unsigned long)arg) {
360 			/* We found a winner */
361 			break;
362 		}
363 		entry = entry->next;
364 		fibctx = NULL;
365 	}
366 
367 	if (!fibctx)
368 		return 0; /* Already gone */
369 
370 	if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) ||
371 		 (fibctx->size != sizeof(struct aac_fib_context)))
372 		return -EINVAL;
373 	spin_lock_irqsave(&dev->fib_lock, flags);
374 	status = aac_close_fib_context(dev, fibctx);
375 	spin_unlock_irqrestore(&dev->fib_lock, flags);
376 	return status;
377 }
378 
379 /**
380  *	check_revision	-	close down user fib context
381  *	@dev: adapter
382  *	@arg: ioctl arguments
383  *
384  *	This routine returns the driver version.
385  *      Under Linux, there have been no version incompatibilities, so this is
386  *      simple!
387  */
388 
389 static int check_revision(struct aac_dev *dev, void __user *arg)
390 {
391 	struct revision response;
392 
393 	response.compat = 1;
394 	response.version = dev->adapter_info.kernelrev;
395 	response.build = dev->adapter_info.kernelbuild;
396 
397 	if (copy_to_user(arg, &response, sizeof(response)))
398 		return -EFAULT;
399 	return 0;
400 }
401 
402 /**
403  *
404  * aac_send_raw_scb
405  *
406  */
407 
408 int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
409 {
410 	struct fib* srbfib;
411 	int status;
412 	struct aac_srb *srbcmd;
413 	struct aac_srb __user *user_srb = arg;
414 	struct aac_srb_reply __user *user_reply;
415 	struct aac_srb_reply* reply;
416 	u32 fibsize = 0;
417 	u32 flags = 0;
418 	s32 rcode = 0;
419 	u32 data_dir;
420 	void __user *sg_user[32];
421 	void *sg_list[32];
422 	u32   sg_indx = 0;
423 	u32 byte_count = 0;
424 	u32 actual_fibsize = 0;
425 	int i;
426 
427 
428 	if (!capable(CAP_SYS_ADMIN)){
429 		printk(KERN_DEBUG"aacraid: No permission to send raw srb\n");
430 		return -EPERM;
431 	}
432 	/*
433 	 *	Allocate and initialize a Fib then setup a BlockWrite command
434 	 */
435 	if (!(srbfib = fib_alloc(dev))) {
436 		return -1;
437 	}
438 	fib_init(srbfib);
439 
440 	srbcmd = (struct aac_srb*) fib_data(srbfib);
441 
442 	if(copy_from_user(&fibsize, &user_srb->count,sizeof(u32))){
443 		printk(KERN_DEBUG"aacraid: Could not copy data size from user\n");
444 		rcode = -EFAULT;
445 		goto cleanup;
446 	}
447 
448 	if (fibsize > FIB_DATA_SIZE_IN_BYTES) {
449 		rcode = -EINVAL;
450 		goto cleanup;
451 	}
452 
453 	if(copy_from_user(srbcmd, user_srb,fibsize)){
454 		printk(KERN_DEBUG"aacraid: Could not copy srb from user\n");
455 		rcode = -EFAULT;
456 		goto cleanup;
457 	}
458 
459 	user_reply = arg+fibsize;
460 
461 	flags = srbcmd->flags;
462 	// Fix up srb for endian and force some values
463 	srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);	// Force this
464 	srbcmd->channel  = cpu_to_le32(srbcmd->channel);
465 	srbcmd->id	 = cpu_to_le32(srbcmd->id);
466 	srbcmd->lun      = cpu_to_le32(srbcmd->lun);
467 	srbcmd->flags    = cpu_to_le32(srbcmd->flags);
468 	srbcmd->timeout  = cpu_to_le32(srbcmd->timeout);
469 	srbcmd->retry_limit =cpu_to_le32(0); // Obsolete parameter
470 	srbcmd->cdb_size = cpu_to_le32(srbcmd->cdb_size);
471 
472 	switch (srbcmd->flags & (SRB_DataIn | SRB_DataOut)) {
473 	case SRB_DataOut:
474 		data_dir = DMA_TO_DEVICE;
475 		break;
476 	case (SRB_DataIn | SRB_DataOut):
477 		data_dir = DMA_BIDIRECTIONAL;
478 		break;
479 	case SRB_DataIn:
480 		data_dir = DMA_FROM_DEVICE;
481 		break;
482 	default:
483 		data_dir = DMA_NONE;
484 	}
485 	if (dev->dac_support == 1) {
486 		struct sgmap64* psg = (struct sgmap64*)&srbcmd->sg;
487 		byte_count = 0;
488 
489 		/*
490 		 * This should also catch if user used the 32 bit sgmap
491 		 */
492 		actual_fibsize = sizeof(struct aac_srb) -
493 			sizeof(struct sgentry) + ((srbcmd->sg.count & 0xff) *
494 			 	sizeof(struct sgentry64));
495 		if(actual_fibsize != fibsize){ // User made a mistake - should not continue
496 			printk(KERN_DEBUG"aacraid: Bad Size specified in Raw SRB command\n");
497 			rcode = -EINVAL;
498 			goto cleanup;
499 		}
500 		if ((data_dir == DMA_NONE) && psg->count) {
501 			printk(KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n");
502 			rcode = -EINVAL;
503 			goto cleanup;
504 		}
505 
506 		for (i = 0; i < psg->count; i++) {
507 			dma_addr_t addr;
508 			u64 le_addr;
509 			void* p;
510 			p = kmalloc(psg->sg[i].count,GFP_KERNEL|__GFP_DMA);
511 			if(p == 0) {
512 				printk(KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
513 				psg->sg[i].count,i,psg->count);
514 				rcode = -ENOMEM;
515 				goto cleanup;
516 			}
517 			sg_user[i] = (void __user *)psg->sg[i].addr;
518 			sg_list[i] = p; // save so we can clean up later
519 			sg_indx = i;
520 
521 			if( flags & SRB_DataOut ){
522 				if(copy_from_user(p,sg_user[i],psg->sg[i].count)){
523 					printk(KERN_DEBUG"aacraid: Could not copy sg data from user\n");
524 					rcode = -EFAULT;
525 					goto cleanup;
526 				}
527 			}
528 			addr = pci_map_single(dev->pdev, p, psg->sg[i].count, data_dir);
529 
530 			le_addr = cpu_to_le64(addr);
531 			psg->sg[i].addr[1] = (u32)(le_addr>>32);
532 			psg->sg[i].addr[0] = (u32)(le_addr & 0xffffffff);
533 			psg->sg[i].count = cpu_to_le32(psg->sg[i].count);
534 			byte_count += psg->sg[i].count;
535 		}
536 
537 		srbcmd->count = cpu_to_le32(byte_count);
538 		status = fib_send(ScsiPortCommand64, srbfib, actual_fibsize, FsaNormal, 1, 1,NULL,NULL);
539 	} else {
540 		struct sgmap* psg = &srbcmd->sg;
541 		byte_count = 0;
542 
543 		actual_fibsize = sizeof (struct aac_srb) +
544 			(((le32_to_cpu(srbcmd->sg.count) & 0xff) - 1) *
545 			 sizeof (struct sgentry));
546 		if(actual_fibsize != fibsize){ // User made a mistake - should not continue
547 			printk(KERN_DEBUG"aacraid: Bad Size specified in Raw SRB command\n");
548 			rcode = -EINVAL;
549 			goto cleanup;
550 		}
551 		if ((data_dir == DMA_NONE) && psg->count) {
552 			printk(KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n");
553 			rcode = -EINVAL;
554 			goto cleanup;
555 		}
556 		for (i = 0; i < psg->count; i++) {
557 			dma_addr_t addr;
558 			void* p;
559 			p = kmalloc(psg->sg[i].count,GFP_KERNEL);
560 			if(p == 0) {
561 				printk(KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
562 				psg->sg[i].count,i,psg->count);
563 				rcode = -ENOMEM;
564 				goto cleanup;
565 			}
566 			sg_user[i] = (void __user *)(psg->sg[i].addr);
567 			sg_list[i] = p; // save so we can clean up later
568 			sg_indx = i;
569 
570 			if( flags & SRB_DataOut ){
571 				if(copy_from_user(p,sg_user[i],psg->sg[i].count)){
572 					printk(KERN_DEBUG"aacraid: Could not copy sg data from user\n");
573 					rcode = -EFAULT;
574 					goto cleanup;
575 				}
576 			}
577 			addr = pci_map_single(dev->pdev, p, psg->sg[i].count, data_dir);
578 
579 			psg->sg[i].addr = cpu_to_le32(addr);
580 			psg->sg[i].count = cpu_to_le32(psg->sg[i].count);
581 			byte_count += psg->sg[i].count;
582 		}
583 		srbcmd->count = cpu_to_le32(byte_count);
584 		status = fib_send(ScsiPortCommand, srbfib, actual_fibsize, FsaNormal, 1, 1, NULL, NULL);
585 	}
586 
587 	if (status != 0){
588 		printk(KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n");
589 		rcode = -1;
590 		goto cleanup;
591 	}
592 
593 	if( flags & SRB_DataIn ) {
594 		for(i = 0 ; i <= sg_indx; i++){
595 			if(copy_to_user(sg_user[i],sg_list[i],le32_to_cpu(srbcmd->sg.sg[i].count))){
596 				printk(KERN_DEBUG"aacraid: Could not copy sg data to user\n");
597 				rcode = -EFAULT;
598 				goto cleanup;
599 
600 			}
601 		}
602 	}
603 
604 	reply = (struct aac_srb_reply *) fib_data(srbfib);
605 	if(copy_to_user(user_reply,reply,sizeof(struct aac_srb_reply))){
606 		printk(KERN_DEBUG"aacraid: Could not copy reply to user\n");
607 		rcode = -EFAULT;
608 		goto cleanup;
609 	}
610 
611 cleanup:
612 	for(i=0; i <= sg_indx; i++){
613 		kfree(sg_list[i]);
614 	}
615 	fib_complete(srbfib);
616 	fib_free(srbfib);
617 
618 	return rcode;
619 }
620 
621 
622 struct aac_pci_info {
623         u32 bus;
624         u32 slot;
625 };
626 
627 
628 int aac_get_pci_info(struct aac_dev* dev, void __user *arg)
629 {
630         struct aac_pci_info pci_info;
631 
632 	pci_info.bus = dev->pdev->bus->number;
633 	pci_info.slot = PCI_SLOT(dev->pdev->devfn);
634 
635        if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) {
636 		printk(KERN_DEBUG "aacraid: Could not copy pci info\n");
637                return -EFAULT;
638 	}
639         return 0;
640  }
641 
642 
643 int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg)
644 {
645 	int status;
646 
647 	/*
648 	 *	HBA gets first crack
649 	 */
650 
651 	status = aac_dev_ioctl(dev, cmd, arg);
652 	if(status != -ENOTTY)
653 		return status;
654 
655 	switch (cmd) {
656 	case FSACTL_MINIPORT_REV_CHECK:
657 		status = check_revision(dev, arg);
658 		break;
659 	case FSACTL_SENDFIB:
660 		status = ioctl_send_fib(dev, arg);
661 		break;
662 	case FSACTL_OPEN_GET_ADAPTER_FIB:
663 		status = open_getadapter_fib(dev, arg);
664 		break;
665 	case FSACTL_GET_NEXT_ADAPTER_FIB:
666 		status = next_getadapter_fib(dev, arg);
667 		break;
668 	case FSACTL_CLOSE_GET_ADAPTER_FIB:
669 		status = close_getadapter_fib(dev, arg);
670 		break;
671 	case FSACTL_SEND_RAW_SRB:
672 		status = aac_send_raw_srb(dev,arg);
673 		break;
674 	case FSACTL_GET_PCI_INFO:
675 		status = aac_get_pci_info(dev,arg);
676 		break;
677 	default:
678 		status = -ENOTTY;
679 	  	break;
680 	}
681 	return status;
682 }
683 
684