if( buf) kfree( buf); 
kfree(buf); 
int cpqfcTS_ioctl( struct scsi_device *ScsiDev, int Cmnd, void *arg){  int result = 0;  struct Scsi_Host *HostAdapter = ScsiDev->host;  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;  PTACHYON fcChip = &cpqfcHBAdata->fcChip;  PFC_LOGGEDIN_PORT pLoggedInPort = NULL;  struct scsi_cmnd *DumCmnd;  int i, j;  VENDOR_IOCTL_REQ ioc;  cpqfc_passthru_t *vendor_cmd;  Scsi_Device *SDpnt;  Scsi_Request *ScsiPassThruReq;  cpqfc_passthru_private_t *privatedata;  ENTER("cpqfcTS_ioctl ");    // printk("ioctl CMND %d", Cmnd);    switch (Cmnd) {      // Passthrough provides a mechanism to bypass the RAID      // or other controller and talk directly to the devices      // (e.g. physical disk drive)      // Passthrough commands, unfortunately, tend to be vendor      // specific; this is tailored to COMPAQ's RAID (RA4x00)      case CPQFCTS_SCSI_PASSTHRU:      {	void *buf = NULL; // for kernel space buffer for user data	/* Check that our pool got allocated ok. */	if (cpqfcHBAdata->private_data_pool == NULL)		return -ENOMEM;		if( !arg)	  return -EINVAL;	// must be super user to send stuff directly to the	// controller and/or physical drives...	if( !capable(CAP_SYS_RAWIO) )	  return -EPERM;	// copy the caller's struct to our space.        if( copy_from_user( &ioc, arg, sizeof( VENDOR_IOCTL_REQ)))		return( -EFAULT);	vendor_cmd = ioc.argp;  // i.e., CPQ specific command struct	// If necessary, grab a kernel/DMA buffer	if( vendor_cmd->len)	{  	  buf = kmalloc( vendor_cmd->len, GFP_KERNEL);	  if( !buf)	    return -ENOMEM;	}        // Now build a Scsi_Request to pass down...        ScsiPassThruReq = scsi_allocate_request(ScsiDev, GFP_KERNEL);	if (ScsiPassThruReq == NULL) {		kfree(buf);		return -ENOMEM;	}	ScsiPassThruReq->upper_private_data = 			cpqfc_alloc_private_data(cpqfcHBAdata);	if (ScsiPassThruReq->upper_private_data == NULL) {		kfree(buf);		scsi_release_request(ScsiPassThruReq); // "de-allocate"		return -ENOMEM;	}	if (vendor_cmd->rw_flag == VENDOR_WRITE_OPCODE) {		if (vendor_cmd->len) { // Need data from user?        		if (copy_from_user(buf, vendor_cmd->bufp, 						vendor_cmd->len)) {				kfree(buf);				cpqfc_free_private_data(cpqfcHBAdata, 					ScsiPassThruReq->upper_private_data);				scsi_release_request(ScsiPassThruReq);				return( -EFAULT);			}		}		ScsiPassThruReq->sr_data_direction = DMA_TO_DEVICE; 	} else if (vendor_cmd->rw_flag == VENDOR_READ_OPCODE) {		ScsiPassThruReq->sr_data_direction = DMA_FROM_DEVICE;	} else		// maybe this means a bug in the user app		ScsiPassThruReq->sr_data_direction = DMA_BIDIRECTIONAL;	    	ScsiPassThruReq->sr_cmd_len = 0; // set correctly by scsi_do_req()	ScsiPassThruReq->sr_sense_buffer[0] = 0;	ScsiPassThruReq->sr_sense_buffer[2] = 0;        // We copy the scheme used by sd.c:spinup_disk() to submit commands	// to our own HBA.  We do this in order to stall the	// thread calling the IOCTL until it completes, and use	// the same "_quecommand" function for synchronizing	// FC Link events with our "worker thread".	privatedata = ScsiPassThruReq->upper_private_data;	privatedata->bus = vendor_cmd->bus;	privatedata->pdrive = vendor_cmd->pdrive;	        // eventually gets us to our own _quecommand routine	scsi_wait_req(ScsiPassThruReq, 		&vendor_cmd->cdb[0], buf, vendor_cmd->len, 		10*HZ,  // timeout		1);	// retries        result = ScsiPassThruReq->sr_result;        // copy any sense data back to caller        if( result != 0 )	{	  memcpy( vendor_cmd->sense_data, // see struct def - size=40		  ScsiPassThruReq->sr_sense_buffer, 		  sizeof(ScsiPassThruReq->sr_sense_buffer) <                  sizeof(vendor_cmd->sense_data)           ?                  sizeof(ScsiPassThruReq->sr_sense_buffer) :                  sizeof(vendor_cmd->sense_data)                ); 	}        SDpnt = ScsiPassThruReq->sr_device;	/* upper_private_data is already freed in call_scsi_done() */        scsi_release_request(ScsiPassThruReq); // "de-allocate"        ScsiPassThruReq = NULL;	// need to pass data back to user (space)?	if( (vendor_cmd->rw_flag == VENDOR_READ_OPCODE) &&	     vendor_cmd->len )        if(  copy_to_user( vendor_cmd->bufp, buf, vendor_cmd->len))		result = -EFAULT;        if( buf) 	  kfree( buf);        return result;      }            case CPQFCTS_GETPCIINFO:      {	cpqfc_pci_info_struct pciinfo;		if( !arg)	  return -EINVAL;         		        pciinfo.bus = cpqfcHBAdata->PciDev->bus->number;        pciinfo.dev_fn = cpqfcHBAdata->PciDev->devfn;  	pciinfo.board_id = cpqfcHBAdata->PciDev->device |			  (cpqfcHBAdata->PciDev->vendor <<16); 	              if(copy_to_user( arg, &pciinfo, sizeof(cpqfc_pci_info_struct)))		return( -EFAULT);        return 0;      }      case CPQFCTS_GETDRIVVER:      {	DriverVer_type DriverVer = 		CPQFCTS_DRIVER_VER( VER_MAJOR,VER_MINOR,VER_SUBMINOR);		if( !arg)	  return -EINVAL;        if(copy_to_user( arg, &DriverVer, sizeof(DriverVer)))		return( -EFAULT);        return 0;      }      case CPQFC_IOCTL_FC_TARGET_ADDRESS:	// can we find an FC device mapping to this SCSI target?/* 	DumCmnd.channel = ScsiDev->channel; */		// For searching/* 	DumCmnd.target  = ScsiDev->id; *//* 	DumCmnd.lun     = ScsiDev->lun; */	DumCmnd = scsi_get_command (ScsiDev, GFP_KERNEL);	if (!DumCmnd)		return -ENOMEM;		pLoggedInPort = fcFindLoggedInPort( fcChip,		DumCmnd, // search Scsi Nexus		0,        // DON'T search linked list for FC port id		NULL,     // DON'T search linked list for FC WWN		NULL);    // DON'T care about end of list	scsi_put_command (DumCmnd);	if (pLoggedInPort == NULL) {		result = -ENXIO;		break;	}	result = access_ok(VERIFY_WRITE, arg, sizeof(Scsi_FCTargAddress)) ? 0 : -EFAULT;	if (result) break;       put_user(pLoggedInPort->port_id,		&((Scsi_FCTargAddress *) arg)->host_port_id);       for( i=3,j=0; i>=0; i--)   	// copy the LOGIN port's WWN        put_user(pLoggedInPort->u.ucWWN[i], 		&((Scsi_FCTargAddress *) arg)->host_wwn[j++]);      for( i=7; i>3; i--)		// copy the LOGIN port's WWN        put_user(pLoggedInPort->u.ucWWN[i], 		&((Scsi_FCTargAddress *) arg)->host_wwn[j++]);        break;      case CPQFC_IOCTL_FC_TDR:                  result = cpqfcTS_TargetDeviceReset( ScsiDev, 0);        break;    default:      result = -EINVAL;      break;    }  LEAVE("cpqfcTS_ioctl");  return result;}
10457	/local/tlutelli/issta_data/temp/c/2005_temp/2005/10457/f9101210e7aa72daf92722d451a2f7e3af5f781f/cpqfcTSinit.c/clean/drivers/scsi/cpqfcTSinit.c