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

📄 scsi.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 5 页
字号:
    channel = hchannel;    if(channel > shpnt->max_channel) goto leave;    dev = hid;    if(dev >= shpnt->max_id) goto leave;    lun = hlun;    if(lun >= shpnt->max_lun) goto leave;    scan_scsis_single (channel, dev, lun, &max_dev_lun, &sparse_lun,		       &SDpnt, SCpnt, shpnt, scsi_result);    if(SDpnt!=oldSDpnt) {	/* it could happen the blockdevice hasn't yet been inited */    for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)        if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();            oldSDpnt->scsi_request_fn = NULL;            for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)                if(sdtpnt->attach) {		  (*sdtpnt->attach)(oldSDpnt);                  if(oldSDpnt->attached) scsi_build_commandblocks(oldSDpnt);}	    resize_dma_pool();          for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) {            if(sdtpnt->finish && sdtpnt->nr_dev)                {(*sdtpnt->finish)();}	}    }  }  else {    for (channel = 0; channel <= shpnt->max_channel; channel++) {      for (dev = 0; dev < shpnt->max_id; ++dev) {        if (shpnt->this_id != dev) {          /*           * We need the for so our continue, etc. work fine. We put this in           * a variable so that we can override it during the scan if we           * detect a device *KNOWN* to have multiple logical units.           */          max_dev_lun = (max_scsi_luns < shpnt->max_lun ?                         max_scsi_luns : shpnt->max_lun);	  sparse_lun = 0;          for (lun = 0; lun < max_dev_lun; ++lun) {            if (!scan_scsis_single (channel, dev, lun, &max_dev_lun,				    &sparse_lun, &SDpnt, SCpnt, shpnt,				    scsi_result)		&& !sparse_lun)              break; /* break means don't probe further for luns!=0 */          }                     /* for lun ends */        }                       /* if this_id != id ends */      }                         /* for dev ends */    }                           /* for channel ends */  } 				/* if/else hardcoded */  leave:  {/* Unchain SCpnt from host_queue */    Scsi_Cmnd *prev, *next, *hqptr;    for(hqptr = shpnt->host_queue; hqptr != SCpnt; hqptr = hqptr->next) ;    if(hqptr) {      prev = hqptr->prev;      next = hqptr->next;      if(prev)      	prev->next = next;      else      	shpnt->host_queue = next;      if(next) next->prev = prev;    }  }      /* Last device block does not exist.  Free memory. */    if (SDpnt != NULL)      scsi_init_free ((char *) SDpnt, sizeof (Scsi_Device));    if (SCpnt != NULL)      scsi_init_free ((char *) SCpnt, sizeof (Scsi_Cmnd));    /* If we allocated a buffer so we could do DMA, free it now */    if (scsi_result != &scsi_result0[0] && scsi_result != NULL)      scsi_init_free (scsi_result, 512);}/* * The worker for scan_scsis. * Returning 0 means Please don't ask further for lun!=0, 1 means OK go on. * Global variables used : scsi_devices(linked list) */int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,    int *sparse_lun, Scsi_Device **SDpnt2, Scsi_Cmnd * SCpnt,    struct Scsi_Host * shpnt, char *scsi_result){  unsigned char scsi_cmd[12];  struct Scsi_Device_Template *sdtpnt;  Scsi_Device * SDtail, *SDpnt=*SDpnt2;  int bflags, type=-1;  SDtail = scsi_devices;  if (scsi_devices)    while (SDtail->next)      SDtail = SDtail->next;  memset (SDpnt, 0, sizeof (Scsi_Device));  SDpnt->host = shpnt;  SDpnt->id = dev;  SDpnt->lun = lun;  SDpnt->channel = channel;  /* Some low level driver could use device->type (DB) */  SDpnt->type = -1;  /*   * Assume that the device will have handshaking problems, and then fix this   * field later if it turns out it doesn't   */  SDpnt->borken = 1;  SDpnt->was_reset = 0;  SDpnt->expecting_cc_ua = 0;  scsi_cmd[0] = TEST_UNIT_READY;  scsi_cmd[1] = lun << 5;  scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0;  SCpnt->host = SDpnt->host;  SCpnt->device = SDpnt;  SCpnt->target = SDpnt->id;  SCpnt->lun = SDpnt->lun;  SCpnt->channel = SDpnt->channel;  {    struct semaphore sem = MUTEX_LOCKED;    SCpnt->request.sem = &sem;    SCpnt->request.rq_status = RQ_SCSI_BUSY;    scsi_do_cmd (SCpnt, (void *) scsi_cmd,                 (void *) scsi_result,                 256, scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5);    down (&sem);  }#if defined(DEBUG) || defined(DEBUG_INIT)  printk ("scsi: scan_scsis_single id %d lun %d. Return code 0x%08x\n",          dev, lun, SCpnt->result);  print_driverbyte(SCpnt->result); print_hostbyte(SCpnt->result);  printk("\n");#endif  if (SCpnt->result) {    if (((driver_byte (SCpnt->result) & DRIVER_SENSE) ||         (status_byte (SCpnt->result) & CHECK_CONDITION)) &&        ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) {      if (((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) &&          ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION) &&          ((SCpnt->sense_buffer[2] & 0xf) != ILLEGAL_REQUEST || lun > 0))        return 1;    }    else      return 0;  }#if defined (DEBUG) || defined(DEBUG_INIT)  printk ("scsi: performing INQUIRY\n");#endif  /*   * Build an INQUIRY command block.   */  scsi_cmd[0] = INQUIRY;  scsi_cmd[1] = (lun << 5) & 0xe0;  scsi_cmd[2] = 0;  scsi_cmd[3] = 0;  scsi_cmd[4] = 255;  scsi_cmd[5] = 0;  SCpnt->cmd_len = 0;  {    struct semaphore sem = MUTEX_LOCKED;    SCpnt->request.sem = &sem;    SCpnt->request.rq_status = RQ_SCSI_BUSY;    scsi_do_cmd (SCpnt, (void *) scsi_cmd,                 (void *) scsi_result,                 256, scan_scsis_done, SCSI_TIMEOUT, 3);    down (&sem);  }#if defined(DEBUG) || defined(DEBUG_INIT)  printk ("scsi: INQUIRY %s with code 0x%x\n",          SCpnt->result ? "failed" : "successful", SCpnt->result);#endif  if (SCpnt->result)    return 0;     /* assume no peripheral if any sort of error */  /*   * Check the peripheral qualifier field - this tells us whether LUNS   * are supported here or not.   */  if( (scsi_result[0] >> 5) == 3 )    {      return 0;     /* assume no peripheral if any sort of error */    }  /*   * It would seem some TOSHIBA CDROM gets things wrong   */  if (!strncmp (scsi_result + 8, "TOSHIBA", 7) &&      !strncmp (scsi_result + 16, "CD-ROM", 6) &&      scsi_result[0] == TYPE_DISK) {    scsi_result[0] = TYPE_ROM;    scsi_result[1] |= 0x80;     /* removable */  }  if (!strncmp (scsi_result + 8, "NEC", 3)) {    if (!strncmp (scsi_result + 16, "CD-ROM DRIVE:84 ", 16) ||        !strncmp (scsi_result + 16, "CD-ROM DRIVE:25", 15))      SDpnt->manufacturer = SCSI_MAN_NEC_OLDCDR;    else      SDpnt->manufacturer = SCSI_MAN_NEC;  }  else if (!strncmp (scsi_result + 8, "TOSHIBA", 7))    SDpnt->manufacturer = SCSI_MAN_TOSHIBA;  else if (!strncmp (scsi_result + 8, "SONY", 4))    SDpnt->manufacturer = SCSI_MAN_SONY;  else if (!strncmp (scsi_result + 8, "PIONEER", 7))    SDpnt->manufacturer = SCSI_MAN_PIONEER;  else    SDpnt->manufacturer = SCSI_MAN_UNKNOWN;  memcpy (SDpnt->vendor, scsi_result + 8, 8);  memcpy (SDpnt->model, scsi_result + 16, 16);  memcpy (SDpnt->rev, scsi_result + 32, 4);  SDpnt->removable = (0x80 & scsi_result[1]) >> 7;  SDpnt->lockable = SDpnt->removable;  SDpnt->changed = 0;  SDpnt->access_count = 0;  SDpnt->busy = 0;  SDpnt->has_cmdblocks = 0;  /*   * Currently, all sequential devices are assumed to be tapes, all random   * devices disk, with the appropriate read only flags set for ROM / WORM   * treated as RO.   */  switch (type = (scsi_result[0] & 0x1f)) {  case TYPE_TAPE:  case TYPE_DISK:  case TYPE_MOD:  case TYPE_PROCESSOR:  case TYPE_SCANNER:  case TYPE_MEDIUM_CHANGER:    SDpnt->writeable = 1;    break;  case TYPE_WORM:  case TYPE_ROM:    SDpnt->writeable = 0;    break;  default:    printk ("scsi: unknown type %d\n", type);  }  SDpnt->single_lun = 0;  SDpnt->soft_reset =    (scsi_result[7] & 1) && ((scsi_result[3] & 7) == 2);  SDpnt->random = (type == TYPE_TAPE) ? 0 : 1;  SDpnt->type = (type & 0x1f);  print_inquiry (scsi_result);  for (sdtpnt = scsi_devicelist; sdtpnt;       sdtpnt = sdtpnt->next)    if (sdtpnt->detect)      SDpnt->attached +=        (*sdtpnt->detect) (SDpnt);  SDpnt->scsi_level = scsi_result[2] & 0x07;  if (SDpnt->scsi_level >= 2 ||      (SDpnt->scsi_level == 1 &&       (scsi_result[3] & 0x0f) == 1))    SDpnt->scsi_level++;  /*   * Accommodate drivers that want to sleep when they should be in a polling   * loop.   */  SDpnt->disconnect = 0;  /*   * Get any flags for this device.   */  bflags = get_device_flags (scsi_result);  /*   * Set the tagged_queue flag for SCSI-II devices that purport to support   * tagged queuing in the INQUIRY data.   */  SDpnt->tagged_queue = 0;  if ((SDpnt->scsi_level >= SCSI_2) &&      (scsi_result[7] & 2) &&      !(bflags & BLIST_NOTQ)) {    SDpnt->tagged_supported = 1;    SDpnt->current_tag = 0;  }  /*   * Some revisions of the Texel CD ROM drives have handshaking problems when   * used with the Seagate controllers.  Before we know what type of device   * we're talking to, we assume it's borken and then change it here if it   * turns out that it isn't a TEXEL drive.   */  if ((bflags & BLIST_BORKEN) == 0)    SDpnt->borken = 0;  /*   * If we want to only allow I/O to one of the luns attached to this device   * at a time, then we set this flag.   */  if (bflags & BLIST_SINGLELUN)    SDpnt->single_lun = 1;  /*   * These devices need this "key" to unlock the devices so we can use it   */  if ((bflags & BLIST_KEY) != 0) {    printk ("Unlocked floptical drive.\n");    SDpnt->lockable = 0;    scsi_cmd[0] = MODE_SENSE;    scsi_cmd[1] = (lun << 5) & 0xe0;    scsi_cmd[2] = 0x2e;    scsi_cmd[3] = 0;    scsi_cmd[4] = 0x2a;    scsi_cmd[5] = 0;    SCpnt->cmd_len = 0;    {      struct semaphore sem = MUTEX_LOCKED;      SCpnt->request.rq_status = RQ_SCSI_BUSY;      SCpnt->request.sem = &sem;      scsi_do_cmd (SCpnt, (void *) scsi_cmd,                   (void *) scsi_result, 0x2a,                   scan_scsis_done, SCSI_TIMEOUT, 3);      down (&sem);    }  }  /* Add this device to the linked list at the end */  if (SDtail)    SDtail->next = SDpnt;  else    scsi_devices = SDpnt;  SDtail = SDpnt;  SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC);  *SDpnt2=SDpnt;  if (!SDpnt)    printk ("scsi: scan_scsis_single: Cannot malloc\n");  /*   * Some scsi devices cannot be polled for lun != 0 due to firmware bugs   */  if (bflags & BLIST_NOLUN)    return 0;                   /* break; */  /*   * If this device is known to support sparse multiple units, override the   * other settings, and scan all of them.   */  if (bflags & BLIST_SPARSELUN) {    *max_dev_lun = 8;    *sparse_lun = 1;    return 1;  }  /*   * If this device is known to support multiple units, override the other   * settings, and scan all of them.   */  if (bflags & BLIST_FORCELUN) {    *max_dev_lun = 8;    return 1;  }  /*   * REGAL CDC-4X: avoid hang after LUN 4   */  if (bflags & BLIST_MAX5LUN) {    *max_dev_lun = 5;    return 1;  }  /*   * We assume the device can't handle lun!=0 if: - it reports scsi-0 (ANSI   * SCSI Revision 0) (old drives like MAXTOR XT-3280) or - it reports scsi-1   * (ANSI SCSI Revision 1) and Response Data Format 0   */  if (((scsi_result[2] & 0x07) == 0)      ||      ((scsi_result[2] & 0x07) == 1 &&       (scsi_result[3] & 0x0f) == 0))    return 0;  return 1;}/* *  Flag bits for the internal_timeout array */#define NORMAL_TIMEOUT 0#define IN_ABORT  1#define IN_RESET  2#define IN_RESET2 4#define IN_RESET3 8/* * This is our time out function, called when the timer expires for a * given host adapter.  It will attempt to abort the currently executing * command, that failing perform a kernel panic. */static void scsi_times_out (Scsi_Cmnd * SCpnt){        switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET | IN_RESET2 | IN_RESET3))    {    case NORMAL_TIMEOUT:	{#ifdef DEBUG_TIMEOUT	    scsi_dump_status();#endif	}		if (!scsi_abort (SCpnt, DID_TIME_OUT))	    return;    case IN_ABORT:	printk("SCSI host %d abort (pid %ld) timed out - resetting\n",	       SCpnt->host->host_no, SCpnt->pid);	if (!scsi_reset (SCpnt, SCSI_RESET_ASYNCHRONOUS))	    return;    case IN_RESET:    case (IN_ABORT | IN_RESET):	/* This might be controversial, but if there is a bus hang,	 * you might conceivably want the machine up and running	 * esp if you have an ide disk. 	 */	printk("SCSI host %d channel %d reset (pid %ld) timed out - "               "trying harder\n",	       SCpnt->host->host_no, SCpnt->channel, SCpnt->pid);	SCpnt->internal_timeout &= ~IN_RESET;	SCpnt->internal_timeout |= IN_RESET2;        scsi_reset (SCpnt,		    SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_BUS_RESET);        return;    case IN_RESET2:    case (IN_ABORT | IN_RESET2):

⌨️ 快捷键说明

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