⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cpqfctsinit.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
  Scsi_Device *SDpnt;  Scsi_Cmnd *ScsiPassThruCmnd;  unsigned long flags;  ENTER("cpqfcTS_ioctl");    // can we find an FC device mapping to this SCSI target?  DumCmnd.channel = ScsiDev->channel;		// For searching  DumCmnd.target  = ScsiDev->id;  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   if( pLoggedInPort == NULL )      // not found!  {    result = -ENXIO;  }   else  // we know what FC device to operate on...  {    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		if( !arg)	  return -EINVAL;	// must be super user to send stuff directly to the	// controller and/or physical drives...	if( !suser() )	  return -EPERM;	// copy the caller's struct to our space.        copy_from_user_ret( &ioc, arg, 			  sizeof( VENDOR_IOCTL_REQ), -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_CMND to pass down...	// This function allocates and sets Scsi_Cmnd ptrs such as	//  ->channel, ->target, ->host        ScsiPassThruCmnd = scsi_allocate_device(NULL, ScsiDev, 1);        // Need data from user?	// make sure caller's buffer is in kernel space.	if( (vendor_cmd->rw_flag == VENDOR_WRITE_OPCODE) &&	    vendor_cmd->len)          copy_from_user_ret( buf, vendor_cmd->bufp, vendor_cmd->len, -EFAULT);	    	// copy the CDB (if/when MAX_COMMAND_SIZE is 16, remove copy below)        memcpy( &ScsiPassThruCmnd->cmnd[0], 		&vendor_cmd->cdb[0], 		MAX_COMMAND_SIZE);          // we want to copy all 16 bytes into the FCP-SCSI CDB,	// although the actual passthru only uses up to the	// first 12.		ScsiPassThruCmnd->cmd_len = 16; // sizeof FCP-SCSI CDB	// Unfortunately, the SCSI command cmnd[] field has only	// 12 bytes.  Ideally the MAX_COMMAND_SIZE should be increased	// to 16 for newer Fibre Channel and SCSI-3 larger CDBs.	// However, to avoid a mandatory kernel rebuild, we use the SCp	// spare field to store the extra 4 bytes ( ugly :-(	if( MAX_COMMAND_SIZE < 16)	{          memcpy( &ScsiPassThruCmnd->SCp.buffers_residual,		  &vendor_cmd->cdb[12], 4);	}	                    	        ScsiPassThruCmnd->SCp.sent_command = 1; // PASSTHRU!	                                        // suppress LUN masking	                                        // and VSA logic	// Use spare fields to copy FCP-SCSI LUN address info...        ScsiPassThruCmnd->SCp.phase = vendor_cmd->bus;	ScsiPassThruCmnd->SCp.have_data_in = vendor_cmd->pdrive;        // We copy the scheme used by scsi.c 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".	        spin_lock_irqsave(&io_request_lock, flags);        {          DECLARE_MUTEX_LOCKED(sem);          ScsiPassThruCmnd->request.sem = &sem;          // eventually gets us to our own _quecommand routine          scsi_do_cmd( ScsiPassThruCmnd, &vendor_cmd->cdb[0], 	       buf, 	       vendor_cmd->len, 	       my_ioctl_done, 	       10*HZ, 1);// timeout,retries          spin_unlock_irqrestore(&io_request_lock, flags);          // Other I/Os can now resume; we wait for our ioctl	  // command to complete	  down(&sem);          spin_lock_irqsave(&io_request_lock, flags);          ScsiPassThruCmnd->request.sem = NULL;        }	        result = ScsiPassThruCmnd->result;        // copy any sense data back to caller        if( result != 0 )	{	  memcpy( vendor_cmd->sense_data, // see struct def - size=40		  ScsiPassThruCmnd->sense_buffer, 		  sizeof(ScsiPassThruCmnd->sense_buffer)); 	}        SDpnt = ScsiPassThruCmnd->device;        scsi_release_command(ScsiPassThruCmnd); // "de-allocate"        ScsiPassThruCmnd = NULL;        if (!SDpnt->was_reset && SDpnt->scsi_request_fn)          (*SDpnt->scsi_request_fn)();        wake_up(&SDpnt->device_wait);        spin_unlock_irqrestore(&io_request_lock, flags);	// need to pass data back to user (space)?	if( (vendor_cmd->rw_flag == VENDOR_READ_OPCODE) &&	     vendor_cmd->len )          copy_to_user_ret( vendor_cmd->bufp, buf, vendor_cmd->len, -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); 	              copy_to_user_ret( arg, &pciinfo, 			  sizeof(cpqfc_pci_info_struct), -EFAULT);        return 0;      }      case CPQFCTS_GETDRIVVER:      {	DriverVer_type DriverVer = 		CPQFCTS_DRIVER_VER( VER_MAJOR,VER_MINOR,VER_SUBMINOR);		if( !arg)	  return -EINVAL;        copy_to_user_ret( arg, &DriverVer, 			  sizeof(DriverVer), -EFAULT);        return 0;      }      case SCSI_IOCTL_FC_TARGET_ADDRESS:      result =         verify_area(VERIFY_WRITE, arg, sizeof(Scsi_FCTargAddress));      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;    default:      result = -EINVAL;      break;    }  }  LEAVE("cpqfcTS_ioctl");  return result;}/* "Release" the Host Bus Adapter...   disable interrupts, stop the HBA, release the interrupt,   and free all resources */int cpqfcTS_release(struct Scsi_Host *HostAdapter){  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;   ENTER("cpqfcTS_release");	  DEBUG_PCI( printk(" cpqfcTS: delete timer...\n"));  del_timer( &cpqfcHBAdata->cpqfcTStimer);        // disable the hardware...  DEBUG_PCI( printk(" disable hardware, destroy queues, free mem\n"));  cpqfcHBAdata->fcChip.ResetTachyon( cpqfcHBAdata, CLEAR_FCPORTS);  // kill kernel thread  if( cpqfcHBAdata->worker_thread ) // (only if exists)  {    DECLARE_MUTEX_LOCKED(sem);  // synchronize thread kill    cpqfcHBAdata->notify_wt = &sem;    DEBUG_PCI( printk(" killing kernel thread\n"));    send_sig( SIGKILL, cpqfcHBAdata->worker_thread, 1);    down( &sem);    cpqfcHBAdata->notify_wt = NULL;      }  // free Linux resources  DEBUG_PCI( printk(" cpqfcTS: freeing resources...\n"));  free_irq( HostAdapter->irq, HostAdapter);  scsi_unregister( HostAdapter);  release_region( cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff);  release_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff); /* we get "vfree: bad address" executing this - need to investigate...   if( (void*)((unsigned long)cpqfcHBAdata->fcChip.Registers.MemBase) !=      cpqfcHBAdata->fcChip.Registers.ReMapMemBase)    vfree( cpqfcHBAdata->fcChip.Registers.ReMapMemBase);*/  LEAVE("cpqfcTS_release");  return 0;}const char * cpqfcTS_info(struct Scsi_Host *HostAdapter){  static char buf[300];  CPQFCHBA *cpqfcHBA;  int BusSpeed, BusWidth;    // get the pointer to our Scsi layer HBA buffer    cpqfcHBA = (CPQFCHBA *)HostAdapter->hostdata;  BusWidth = (cpqfcHBA->fcChip.Registers.PCIMCTR &0x4) > 0 ?               64 : 32;  if( cpqfcHBA->fcChip.Registers.TYconfig.value & 0x80000000)    BusSpeed = 66;  else    BusSpeed = 33;  sprintf(buf, "%s: WWN %08X%08X\n on PCI bus %d device 0x%02x irq %d IObaseL 0x%x, MEMBASE 0x%x\nPCI bus width %d bits, bus speed %d MHz\nFCP-SCSI Driver v%d.%d.%d",      cpqfcHBA->fcChip.Name,       cpqfcHBA->fcChip.Registers.wwn_hi,      cpqfcHBA->fcChip.Registers.wwn_lo,      cpqfcHBA->PciDev->bus->number,      cpqfcHBA->PciDev->device,        HostAdapter->irq,      cpqfcHBA->fcChip.Registers.IOBaseL,      cpqfcHBA->fcChip.Registers.MemBase,      BusWidth,      BusSpeed,      VER_MAJOR, VER_MINOR, VER_SUBMINOR);    cpqfcTSDecodeGBICtype( &cpqfcHBA->fcChip, &buf[ strlen(buf)]);  cpqfcTSGetLPSM( &cpqfcHBA->fcChip, &buf[ strlen(buf)]);  return buf;}//// /proc/scsi support. The following routines allow us to do 'normal'// sprintf like calls to return the currently requested piece (buflenght// chars, starting at bufoffset) of the file. Although procfs allows for// a 1 Kb bytes overflow after te supplied buffer, I consider it bad // programming to use it to make programming a little simpler. This piece// of coding is borrowed from ncr53c8xx.c with some modifications //struct info_str{        char *buffer;			// Pointer to output buffer        int buflength;			// It's length        int bufoffset;			// File offset corresponding with buf[0]	int buffillen;			// Current filled length         int filpos;			// Current file offset};static void copy_mem_info(struct info_str *info, char *data, int datalen){  if (info->filpos < info->bufoffset) {	// Current offset before buffer offset    if (info->filpos + datalen <= info->bufoffset) {      info->filpos += datalen; 		// Discard if completely before buffer      return;    } else {				// Partial copy, set to begin      data += (info->bufoffset - info->filpos);      datalen  -= (info->bufoffset - info->filpos);      info->filpos = info->bufoffset;    }  }  info->filpos += datalen;		// Update current offset  if (info->buffillen == info->buflength) // Buffer full, discard    return;  if (info->buflength - info->buffillen < datalen)  // Overflows buffer ?    datalen = info->buflength - info->buffillen;  memcpy(info->buffer + info->buffillen, data, datalen);  info->buffillen += datalen;}static int copy_info(struct info_str *info, char *fmt, ...){        va_list args;        char buf[400];        int len;        va_start(args, fmt);        len = vsprintf(buf, fmt, args);        va_end(args);        copy_mem_info(info, buf, len);        return len;}// Routine to get data for /proc RAM filesystem//int cpqfcTS_proc_info (char *buffer, char **start, off_t offset, int length, 		       int hostno, int inout){  struct Scsi_Host *host;  Scsi_Cmnd DumCmnd;  int Chan, Targ, i;  struct info_str info;  CPQFCHBA *cpqfcHBA;  PTACHYON fcChip;  PFC_LOGGEDIN_PORT pLoggedInPort;  char buf[81];  // Search the Scsi host list for our controller  for (host=scsi_hostlist; host; host=host->next)    if (host->host_no == hostno)      break;  if (!host) return -ESRCH;  if (inout) return -EINVAL;  // get the pointer to our Scsi layer HBA buffer    cpqfcHBA = (CPQFCHBA *)host->hostdata;  fcChip = &cpqfcHBA->fcChip;    *start 	  = buffer;  info.buffer     = buffer;  info.buflength  = length;  info.bufoffset  = offset;  info.filpos     = 0;  info.buffillen  = 0;  copy_info(&info, "Driver version = %d.%d.%d", VER_MAJOR, VER_MINOR, VER_SUBMINOR);   cpqfcTSDecodeGBICtype( &cpqfcHBA->fcChip, &buf[0]);  cpqfcTSGetLPSM( &cpqfcHBA->fcChip, &buf[ strlen(buf)]);  copy_info(&info, "%s\n", buf); 		  #define DISPLAY_WWN_INFO#ifdef DISPLAY_WWN_INFO  copy_info(&info, "WWN database: (\"port_id: 000000\" means disconnected)\n");  for ( Chan=0; Chan <= host->max_channel; Chan++) {    DumCmnd.channel = Chan;    for (Targ=0; Targ <= host->max_id; Targ++) {      DumCmnd.target = Targ;      if ((pLoggedInPort = fcFindLoggedInPort( fcChip,	    			&DumCmnd, // search Scsi Nexus    				0,        // DON'T search list for FC port id    				NULL,     // DON'T search list for FC WWN    				NULL))){   // DON'T care about end of list	copy_info(&info, "Host: scsi%d Channel: %02d TargetId: %02d -> WWN: ",			   hostno, Chan, Targ);        for( i=3; i>=0; i--)        // copy the LOGIN port's WWN          copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]);        for( i=7; i>3; i--)             // copy the LOGIN port's WWN          copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]);	copy_info(&info, " port_id: %06X\n", pLoggedInPort->port_id);       }    }  }#endif    // Unfortunately, the proc_info buffer isn't big enough// for everything we would like...// For FC stats, compile this and turn off WWN stuff above  //#define DISPLAY_FC_STATS#ifdef DISPLAY_FC_STATS// get the Fibre Channel statistics  {    int DeltaSecs = (jiffies - cpqfcHBA->fcStatsTime) / HZ;    int days,hours,minutes,secs;        days = DeltaSecs / (3600*24); // days    hours = (DeltaSecs% (3600*24)) / 3600; // hours    minutes = (DeltaSecs%3600 /60); // minutes    secs =  DeltaSecs%60;  // secscopy_info( &info, "Fibre Channel Stats (time dd:hh:mm:ss %02u:%02u:%02u:%02u\n",      days, hours, minutes, secs);  }      cpqfcHBA->fcStatsTime = jiffies;  // (for next delta)  copy_info( &info, "  LinkUp           %9u     LinkDown      %u\n",        fcChip->fcStats.linkUp, fcChip->fcStats.linkDown);          copy_info( &info, "  Loss of Signal   %9u     Loss of Sync  %u\n",    fcChip->fcStats.LossofSignal, fcChip->fcStats.LossofSync);		    copy_info( &info, "  Discarded Frames %9u     Bad CRC Frame %u\n",    fcChip->fcStats.Dis_Frm, fcChip->fcStats.Bad_CRC);  copy_info( &info, "  TACH LinkFailTX  %9u     TACH LinkFailRX     %u\n",    fcChip->fcStats.linkFailTX, fcChip->fcStats.linkFailRX);  

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -