commctrl.c 17 KB
Newer Older
Alan Cox's avatar
Alan Cox committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
/*
 *	Adaptec AAC series RAID controller driver
 *	(c) Copyright 2001 Red Hat Inc.	<alan@redhat.com>
 *
 * based on the old aacraid driver that is..
 * Adaptec aacraid device driver for Linux.
 *
 * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * Module Name:
 *  commctrl.c
 *
 * Abstract: Contains all routines for control of the AFA comm layer
 *
 */

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/completion.h>
39
#include <linux/dma-mapping.h>
40
#include <linux/blkdev.h>
Alan Cox's avatar
Alan Cox committed
41 42 43 44 45 46 47 48 49 50 51 52 53 54
#include <asm/semaphore.h>
#include <asm/uaccess.h>

#include "aacraid.h"

/**
 *	ioctl_send_fib	-	send a FIB from userspace
 *	@dev:	adapter is being processed
 *	@arg:	arguments to the ioctl call
 *	
 *	This routine sends a fib to the adapter on behalf of a user level
 *	program.
 */
 
55
static int ioctl_send_fib(struct aac_dev * dev, void __user *arg)
Alan Cox's avatar
Alan Cox committed
56 57 58 59 60 61 62 63
{
	struct hw_fib * kfib;
	struct fib *fibptr;

	fibptr = fib_alloc(dev);
	if(fibptr == NULL)
		return -ENOMEM;
		
64
	kfib = fibptr->hw_fib;
Alan Cox's avatar
Alan Cox committed
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
	/*
	 *	First copy in the header so that we can check the size field.
	 */
	if (copy_from_user((void *)kfib, arg, sizeof(struct aac_fibhdr))) {
		fib_free(fibptr);
		return -EFAULT;
	}
	/*
	 *	Since we copy based on the fib header size, make sure that we
	 *	will not overrun the buffer when we copy the memory. Return
	 *	an error if we would.
	 */
	if(le32_to_cpu(kfib->header.Size) > sizeof(struct hw_fib) - sizeof(struct aac_fibhdr)) {
		fib_free(fibptr);
		return -EINVAL;
	}

	if (copy_from_user((void *) kfib, arg, le32_to_cpu(kfib->header.Size) + sizeof(struct aac_fibhdr))) {
		fib_free(fibptr);
		return -EFAULT;
	}

	if (kfib->header.Command == cpu_to_le32(TakeABreakPt)) {
		aac_adapter_interrupt(dev);
		/*
		 * Since we didn't really send a fib, zero out the state to allow 
		 * cleanup code not to assert.
		 */
		kfib->header.XferState = 0;
	} else {
95 96 97 98
		int retval = fib_send(kfib->header.Command, fibptr,
				le32_to_cpu(kfib->header.Size) , FsaNormal,
				1, 1, NULL, NULL);
		if (retval) {
Alan Cox's avatar
Alan Cox committed
99
			fib_free(fibptr);
100
			return retval;
Alan Cox's avatar
Alan Cox committed
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
		}
		if (fib_complete(fibptr) != 0) {
			fib_free(fibptr);
			return -EINVAL;
		}
	}
	/*
	 *	Make sure that the size returned by the adapter (which includes
	 *	the header) is less than or equal to the size of a fib, so we
	 *	don't corrupt application data. Then copy that size to the user
	 *	buffer. (Don't try to add the header information again, since it
	 *	was already included by the adapter.)
	 */

	if (copy_to_user(arg, (void *)kfib, kfib->header.Size)) {
		fib_free(fibptr);
		return -EFAULT;
	}
	fib_free(fibptr);
	return 0;
}

/**
 *	open_getadapter_fib	-	Get the next fib
 *
 *	This routine will get the next Fib, if available, from the AdapterFibContext
 *	passed in from the user.
 */

130
static int open_getadapter_fib(struct aac_dev * dev, void __user *arg)
Alan Cox's avatar
Alan Cox committed
131 132 133 134 135 136 137 138
{
	struct aac_fib_context * fibctx;
	int status;

	fibctx = kmalloc(sizeof(struct aac_fib_context), GFP_KERNEL);
	if (fibctx == NULL) {
		status = -ENOMEM;
	} else {
139 140 141 142
		unsigned long flags;
		struct list_head * entry;
		struct aac_fib_context * context;

Alan Cox's avatar
Alan Cox committed
143 144
		fibctx->type = FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT;
		fibctx->size = sizeof(struct aac_fib_context);
145 146 147 148 149 150 151
 		/*
		 *	Yes yes, I know this could be an index, but we have a
		 * better guarantee of uniqueness for the locked loop below.
		 * Without the aid of a persistent history, this also helps
		 * reduce the chance that the opaque context would be reused.
		 */
		fibctx->unique = (u32)((ulong)fibctx & 0xFFFFFFFF);
Alan Cox's avatar
Alan Cox committed
152 153 154 155 156 157 158 159 160 161
		/*
		 *	Initialize the mutex used to wait for the next AIF.
		 */
		init_MUTEX_LOCKED(&fibctx->wait_sem);
		fibctx->wait = 0;
		/*
		 *	Initialize the fibs and set the count of fibs on
		 *	the list to 0.
		 */
		fibctx->count = 0;
162
		INIT_LIST_HEAD(&fibctx->fib_list);
Alan Cox's avatar
Alan Cox committed
163 164 165 166 167 168
		fibctx->jiffies = jiffies/HZ;
		/*
		 *	Now add this context onto the adapter's 
		 *	AdapterFibContext list.
		 */
		spin_lock_irqsave(&dev->fib_lock, flags);
169 170 171 172 173 174 175 176 177 178 179 180
		/* Ensure that we have a unique identifier */
		entry = dev->fib_list.next;
		while (entry != &dev->fib_list) {
			context = list_entry(entry, struct aac_fib_context, next);
			if (context->unique == fibctx->unique) {
				/* Not unique (32 bits) */
				fibctx->unique++;
				entry = dev->fib_list.next;
			} else {
				entry = entry->next;
			}
		}
Alan Cox's avatar
Alan Cox committed
181 182
		list_add_tail(&fibctx->next, &dev->fib_list);
		spin_unlock_irqrestore(&dev->fib_lock, flags);
183 184
		if (copy_to_user(arg,  &fibctx->unique, 
						sizeof(fibctx->unique))) {
Alan Cox's avatar
Alan Cox committed
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
			status = -EFAULT;
		} else {
			status = 0;
		}	
	}
	return status;
}

/**
 *	next_getadapter_fib	-	get the next fib
 *	@dev: adapter to use
 *	@arg: ioctl argument
 *	
 * 	This routine will get the next Fib, if available, from the AdapterFibContext
 *	passed in from the user.
 */

202
static int next_getadapter_fib(struct aac_dev * dev, void __user *arg)
Alan Cox's avatar
Alan Cox committed
203 204
{
	struct fib_ioctl f;
205
	struct fib *fib;
206
	struct aac_fib_context *fibctx;
Alan Cox's avatar
Alan Cox committed
207 208 209 210 211 212 213 214 215 216 217 218 219
	int status;
	struct list_head * entry;
	unsigned long flags;
	
	if(copy_from_user((void *)&f, arg, sizeof(struct fib_ioctl)))
		return -EFAULT;
	/*
	 *	Verify that the HANDLE passed in was a valid AdapterFibContext
	 *
	 *	Search the list of AdapterFibContext addresses on the adapter
	 *	to be sure this is a valid address
	 */
	entry = dev->fib_list.next;
220
	fibctx = NULL;
Alan Cox's avatar
Alan Cox committed
221

222 223 224 225 226 227
	while (entry != &dev->fib_list) {
		fibctx = list_entry(entry, struct aac_fib_context, next);
		/*
		 *	Extract the AdapterFibContext from the Input parameters.
		 */
		if (fibctx->unique == f.fibctx) {   /* We found a winner */
Alan Cox's avatar
Alan Cox committed
228 229 230
			break;
		}
		entry = entry->next;
231
		fibctx = NULL;
Alan Cox's avatar
Alan Cox committed
232
	}
233 234
	if (!fibctx) {
		dprintk ((KERN_INFO "Fib Context not found\n"));
Alan Cox's avatar
Alan Cox committed
235
		return -EINVAL;
236
	}
Alan Cox's avatar
Alan Cox committed
237 238

	if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) ||
239 240
		 (fibctx->size != sizeof(struct aac_fib_context))) {
		dprintk ((KERN_INFO "Fib Context corrupt?\n"));
Alan Cox's avatar
Alan Cox committed
241
		return -EINVAL;
242
	}
Alan Cox's avatar
Alan Cox committed
243 244 245 246 247 248 249
	status = 0;
	spin_lock_irqsave(&dev->fib_lock, flags);
	/*
	 *	If there are no fibs to send back, then either wait or return
	 *	-EAGAIN
	 */
return_fib:
250 251
	if (!list_empty(&fibctx->fib_list)) {
		struct list_head * entry;
Alan Cox's avatar
Alan Cox committed
252 253 254
		/*
		 *	Pull the next fib from the fibs
		 */
255 256
		entry = fibctx->fib_list.next;
		list_del(entry);
Alan Cox's avatar
Alan Cox committed
257
		
258
		fib = list_entry(entry, struct fib, fiblink);
Alan Cox's avatar
Alan Cox committed
259 260
		fibctx->count--;
		spin_unlock_irqrestore(&dev->fib_lock, flags);
261 262 263
		if (copy_to_user(f.fib, fib->hw_fib, sizeof(struct hw_fib))) {
			kfree(fib->hw_fib);
			kfree(fib);
Alan Cox's avatar
Alan Cox committed
264 265 266 267 268
			return -EFAULT;
		}	
		/*
		 *	Free the space occupied by this copy of the fib.
		 */
269 270
		kfree(fib->hw_fib);
		kfree(fib);
Alan Cox's avatar
Alan Cox committed
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
		status = 0;
		fibctx->jiffies = jiffies/HZ;
	} else {
		spin_unlock_irqrestore(&dev->fib_lock, flags);
		if (f.wait) {
			if(down_interruptible(&fibctx->wait_sem) < 0) {
				status = -EINTR;
			} else {
				/* Lock again and retry */
				spin_lock_irqsave(&dev->fib_lock, flags);
				goto return_fib;
			}
		} else {
			status = -EAGAIN;
		}	
	}
	return status;
}

int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx)
{
292
	struct fib *fib;
Alan Cox's avatar
Alan Cox committed
293 294 295 296

	/*
	 *	First free any FIBs that have not been consumed.
	 */
297 298
	while (!list_empty(&fibctx->fib_list)) {
		struct list_head * entry;
Alan Cox's avatar
Alan Cox committed
299 300 301
		/*
		 *	Pull the next fib from the fibs
		 */
302 303 304
		entry = fibctx->fib_list.next;
		list_del(entry);
		fib = list_entry(entry, struct fib, fiblink);
Alan Cox's avatar
Alan Cox committed
305 306 307 308
		fibctx->count--;
		/*
		 *	Free the space occupied by this copy of the fib.
		 */
309 310
		kfree(fib->hw_fib);
		kfree(fib);
Alan Cox's avatar
Alan Cox committed
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
	}
	/*
	 *	Remove the Context from the AdapterFibContext List
	 */
	list_del(&fibctx->next);
	/*
	 *	Invalidate context
	 */
	fibctx->type = 0;
	/*
	 *	Free the space occupied by the Context
	 */
	kfree(fibctx);
	return 0;
}

/**
 *	close_getadapter_fib	-	close down user fib context
 *	@dev: adapter
 *	@arg: ioctl arguments
 *
 *	This routine will close down the fibctx passed in from the user.
 */
 
335
static int close_getadapter_fib(struct aac_dev * dev, void __user *arg)
Alan Cox's avatar
Alan Cox committed
336
{
337
	struct aac_fib_context *fibctx;
Alan Cox's avatar
Alan Cox committed
338 339 340 341 342 343 344 345 346 347 348 349
	int status;
	unsigned long flags;
	struct list_head * entry;

	/*
	 *	Verify that the HANDLE passed in was a valid AdapterFibContext
	 *
	 *	Search the list of AdapterFibContext addresses on the adapter
	 *	to be sure this is a valid address
	 */

	entry = dev->fib_list.next;
350
	fibctx = NULL;
Alan Cox's avatar
Alan Cox committed
351 352

	while(entry != &dev->fib_list) {
353 354 355 356 357 358
		fibctx = list_entry(entry, struct aac_fib_context, next);
		/*
		 *	Extract the fibctx from the input parameters
		 */
		if (fibctx->unique == (u32)(unsigned long)arg) {   
			/* We found a winner */
Alan Cox's avatar
Alan Cox committed
359 360 361
			break;
		}
		entry = entry->next;
362
		fibctx = NULL;
Alan Cox's avatar
Alan Cox committed
363 364
	}

365
	if (!fibctx)
Alan Cox's avatar
Alan Cox committed
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381
		return 0; /* Already gone */

	if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) ||
		 (fibctx->size != sizeof(struct aac_fib_context)))
		return -EINVAL;
	spin_lock_irqsave(&dev->fib_lock, flags);
	status = aac_close_fib_context(dev, fibctx);
	spin_unlock_irqrestore(&dev->fib_lock, flags);
	return status;
}

/**
 *	check_revision	-	close down user fib context
 *	@dev: adapter
 *	@arg: ioctl arguments
 *
382 383 384
 *	This routine returns the driver version.
 *      Under Linux, there have been no version incompatibilities, so this is 
 *      simple!
Alan Cox's avatar
Alan Cox committed
385 386
 */

387
static int check_revision(struct aac_dev *dev, void __user *arg)
Alan Cox's avatar
Alan Cox committed
388 389 390 391 392 393 394 395 396 397 398 399
{
	struct revision response;

	response.compat = 1;
	response.version = dev->adapter_info.kernelrev;
	response.build = dev->adapter_info.kernelbuild;

	if (copy_to_user(arg, &response, sizeof(response)))
		return -EFAULT;
	return 0;
}

400 401 402 403 404 405
/**
 *
 * aac_send_raw_scb
 *
 */

406
int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
407 408 409 410
{
	struct fib* srbfib;
	int status;
	struct aac_srb *srbcmd;
411 412
	struct aac_srb __user *user_srb = arg;
	struct aac_srb_reply __user *user_reply;
413 414 415 416 417
	struct aac_srb_reply* reply;
	u32 fibsize = 0;
	u32 flags = 0;
	s32 rcode = 0;
	u32 data_dir;
418 419
	void __user *sg_user[32];
	void *sg_list[32];
420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
	u32   sg_indx = 0;
	u32 byte_count = 0;
	u32 actual_fibsize = 0;
	int i;


	if (!capable(CAP_SYS_ADMIN)){
		printk(KERN_DEBUG"aacraid: No permission to send raw srb\n"); 
		return -EPERM;
	}
	/*
	 *	Allocate and initialize a Fib then setup a BlockWrite command
	 */
	if (!(srbfib = fib_alloc(dev))) {
		return -1;
	}
	fib_init(srbfib);

	srbcmd = (struct aac_srb*) fib_data(srbfib);

440
	if(copy_from_user(&fibsize, &user_srb->count,sizeof(u32))){
441 442 443 444 445
		printk(KERN_DEBUG"aacraid: Could not copy data size from user\n"); 
		rcode = -EFAULT;
		goto cleanup;
	}

446 447 448 449 450
	if (fibsize > FIB_DATA_SIZE_IN_BYTES) {
		rcode = -EINVAL;
		goto cleanup;
	}

451 452 453 454 455 456 457 458 459 460 461 462
	if(copy_from_user(srbcmd, user_srb,fibsize)){
		printk(KERN_DEBUG"aacraid: Could not copy srb from user\n"); 
		rcode = -EFAULT;
		goto cleanup;
	}

	user_reply = arg+fibsize;

	flags = srbcmd->flags;
	// Fix up srb for endian and force some values
	srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);	// Force this
	srbcmd->channel  = cpu_to_le32(srbcmd->channel);
463
	srbcmd->id	 = cpu_to_le32(srbcmd->id);
464 465 466 467 468 469
	srbcmd->lun      = cpu_to_le32(srbcmd->lun);
	srbcmd->flags    = cpu_to_le32(srbcmd->flags);
	srbcmd->timeout  = cpu_to_le32(srbcmd->timeout);
	srbcmd->retry_limit =cpu_to_le32(0); // Obsolete parameter
	srbcmd->cdb_size = cpu_to_le32(srbcmd->cdb_size);
	
470
	switch (srbcmd->flags & (SRB_DataIn | SRB_DataOut)) {
471
	case SRB_DataOut:
472
		data_dir = DMA_TO_DEVICE;
473 474
		break;
	case (SRB_DataIn | SRB_DataOut):
475
		data_dir = DMA_BIDIRECTIONAL;
476 477
		break;
	case SRB_DataIn:
478
		data_dir = DMA_FROM_DEVICE;
479 480
		break;
	default:
481
		data_dir = DMA_NONE;
482
	}
483
	if (dev->dac_support == 1) {
484 485 486
		struct sgmap64* psg = (struct sgmap64*)&srbcmd->sg;
		byte_count = 0;

487 488 489 490 491 492
		/*
		 * This should also catch if user used the 32 bit sgmap
		 */
		actual_fibsize = sizeof(struct aac_srb) - 
			sizeof(struct sgentry) + ((srbcmd->sg.count & 0xff) * 
			 	sizeof(struct sgentry64));
493 494 495 496 497
		if(actual_fibsize != fibsize){ // User made a mistake - should not continue
			printk(KERN_DEBUG"aacraid: Bad Size specified in Raw SRB command\n");
			rcode = -EINVAL;
			goto cleanup;
		}
498 499 500 501 502
		if ((data_dir == DMA_NONE) && psg->count) { 
			printk(KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n");
			rcode = -EINVAL;
			goto cleanup;
		}
503 504 505 506 507 508 509 510 511 512 513 514

		for (i = 0; i < psg->count; i++) {
			dma_addr_t addr; 
			u64 le_addr;
			void* p;
			p = kmalloc(psg->sg[i].count,GFP_KERNEL|__GFP_DMA);
			if(p == 0) {
				printk(KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
				psg->sg[i].count,i,psg->count);
				rcode = -ENOMEM;
				goto cleanup;
			}
515 516
			sg_user[i] = (void __user *)psg->sg[i].addr;
			sg_list[i] = p; // save so we can clean up later
517 518 519
			sg_indx = i;

			if( flags & SRB_DataOut ){
520
				if(copy_from_user(p,sg_user[i],psg->sg[i].count)){
521 522 523 524 525
					printk(KERN_DEBUG"aacraid: Could not copy sg data from user\n"); 
					rcode = -EFAULT;
					goto cleanup;
				}
			}
526
			addr = pci_map_single(dev->pdev, p, psg->sg[i].count, data_dir);
527 528 529 530 531 532 533 534 535

			le_addr = cpu_to_le64(addr);
			psg->sg[i].addr[1] = (u32)(le_addr>>32);
			psg->sg[i].addr[0] = (u32)(le_addr & 0xffffffff);
			psg->sg[i].count = cpu_to_le32(psg->sg[i].count);  
			byte_count += psg->sg[i].count;
		}

		srbcmd->count = cpu_to_le32(byte_count);
536
		status = fib_send(ScsiPortCommand64, srbfib, actual_fibsize, FsaNormal, 1, 1,NULL,NULL);
537 538 539 540 541 542 543
	} else {
		struct sgmap* psg = &srbcmd->sg;
		byte_count = 0;

		actual_fibsize = sizeof (struct aac_srb) + (((srbcmd->sg.count & 0xff) - 1) * sizeof (struct sgentry));
		if(actual_fibsize != fibsize){ // User made a mistake - should not continue
			printk(KERN_DEBUG"aacraid: Bad Size specified in Raw SRB command\n");
544 545 546 547 548
			rcode = -EINVAL;
			goto cleanup;
		}
		if ((data_dir == DMA_NONE) && psg->count) {
			printk(KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n");
549 550 551 552 553 554 555 556 557 558 559 560 561
			rcode = -EINVAL;
			goto cleanup;
		}
		for (i = 0; i < psg->count; i++) {
			dma_addr_t addr; 
			void* p;
			p = kmalloc(psg->sg[i].count,GFP_KERNEL);
			if(p == 0) {
				printk(KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
				psg->sg[i].count,i,psg->count);
				rcode = -ENOMEM;
				goto cleanup;
			}
562 563
			sg_user[i] = (void __user *)(psg->sg[i].addr);
			sg_list[i] = p; // save so we can clean up later
564 565 566
			sg_indx = i;

			if( flags & SRB_DataOut ){
567
				if(copy_from_user(p,sg_user[i],psg->sg[i].count)){
568 569 570 571 572
					printk(KERN_DEBUG"aacraid: Could not copy sg data from user\n"); 
					rcode = -EFAULT;
					goto cleanup;
				}
			}
573
			addr = pci_map_single(dev->pdev, p, psg->sg[i].count, data_dir);
574 575 576 577 578 579

			psg->sg[i].addr = cpu_to_le32(addr);
			psg->sg[i].count = cpu_to_le32(psg->sg[i].count);  
			byte_count += psg->sg[i].count;
		}
		srbcmd->count = cpu_to_le32(byte_count);
580
		status = fib_send(ScsiPortCommand, srbfib, actual_fibsize, FsaNormal, 1, 1, NULL, NULL);
581 582 583 584 585 586 587 588 589 590
	}

	if (status != 0){
		printk(KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n"); 
		rcode = -1;
		goto cleanup;
	}

	if( flags & SRB_DataIn ) {
		for(i = 0 ; i <= sg_indx; i++){
591
			if(copy_to_user(sg_user[i],sg_list[i],le32_to_cpu(srbcmd->sg.sg[i].count))){
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608
				printk(KERN_DEBUG"aacraid: Could not copy sg data to user\n"); 
				rcode = -EFAULT;
				goto cleanup;

			}
		}
	}

	reply = (struct aac_srb_reply *) fib_data(srbfib);
	if(copy_to_user(user_reply,reply,sizeof(struct aac_srb_reply))){
		printk(KERN_DEBUG"aacraid: Could not copy reply to user\n"); 
		rcode = -EFAULT;
		goto cleanup;
	}

cleanup:
	for(i=0; i <= sg_indx; i++){
609
		kfree(sg_list[i]);
610 611 612 613 614 615 616
	}
	fib_complete(srbfib);
	fib_free(srbfib);

	return rcode;
}

Alan Cox's avatar
Alan Cox committed
617 618 619 620 621 622 623

struct aac_pci_info {
        u32 bus;
        u32 slot;
};


624
int aac_get_pci_info(struct aac_dev* dev, void __user *arg)
Alan Cox's avatar
Alan Cox committed
625 626 627 628 629 630
{
        struct aac_pci_info pci_info;

	pci_info.bus = dev->pdev->bus->number;
	pci_info.slot = PCI_SLOT(dev->pdev->devfn);

631
       if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) {
632
		printk(KERN_DEBUG "aacraid: Could not copy pci info\n");
Alan Cox's avatar
Alan Cox committed
633
               return -EFAULT;
634
	}
Alan Cox's avatar
Alan Cox committed
635 636 637 638
        return 0;
 }
 

639
int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg)
Alan Cox's avatar
Alan Cox committed
640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666
{
	int status;
	
	/*
	 *	HBA gets first crack
	 */
	 
	status = aac_dev_ioctl(dev, cmd, arg);
	if(status != -ENOTTY)
		return status;

	switch (cmd) {
	case FSACTL_MINIPORT_REV_CHECK:
		status = check_revision(dev, arg);
		break;
	case FSACTL_SENDFIB:
		status = ioctl_send_fib(dev, arg);
		break;
	case FSACTL_OPEN_GET_ADAPTER_FIB:
		status = open_getadapter_fib(dev, arg);
		break;
	case FSACTL_GET_NEXT_ADAPTER_FIB:
		status = next_getadapter_fib(dev, arg);
		break;
	case FSACTL_CLOSE_GET_ADAPTER_FIB:
		status = close_getadapter_fib(dev, arg);
		break;
667 668 669
	case FSACTL_SEND_RAW_SRB:
		status = aac_send_raw_srb(dev,arg);
		break;
Alan Cox's avatar
Alan Cox committed
670 671 672 673 674 675 676 677 678 679
	case FSACTL_GET_PCI_INFO:
		status = aac_get_pci_info(dev,arg);
		break;
	default:
		status = -ENOTTY;
	  	break;	
	}
	return status;
}