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

📄 seagate.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
#endif/* *    We loop as long as we are in a data in phase, there is room to read, *      and BSY is still active *//* SJT: Start. */#ifdef SEAGATE_USE_ASM/* *      We loop as long as we are in a data in phase, there is room to read,  *      and BSY is still active */            /* Local variables : ecx = len, edi = data                                 esi = st0x_cr_sr, ebx = st0x_dr */            __asm__ (            /* Test for room to read */                "orl %%ecx, %%ecx\n\t"                "jz 2f\n\t"                "cld\n\t"/*                "movl " SYMBOL_NAME_STR(st0x_cr_sr) ", %%esi\n\t"  *//*                "movl " SYMBOL_NAME_STR(st0x_dr) ", %%ebx\n\t"  */            "1:\t"                "movb (%%esi), %%al\n\t"            /* Test for BSY */                "test $1, %%al\n\t"                "jz 2f\n\t"            /* Test for data in phase - STATUS & REQ_MASK should be REQ_DATAIN,                = STAT_IO, which is 4. */                "movb $0xe, %%ah\n\t"                      "andb %%al, %%ah\n\t"                "cmpb $0x04, %%ah\n\t"                "jne 2f\n\t"            /* Test for REQ */                      "test $0x10, %%al\n\t"                "jz 1b\n\t"                "movb (%%ebx), %%al\n\t"                      "stosb\n\t"                   "loop 1b\n\t"            "2:\n"/* output */    : "=D" (data), "=c" (len) /* input */     : "0" (data), "1" (len), "S" (phys_to_virt(st0x_cr_sr)), "b" (phys_to_virt(st0x_dr)) /* clobbered */ : "eax","ebx", "esi"); #else /* SEAGATE_USE_ASM */            while (len)            {              unsigned char stat;              stat = STATUS;              if (!(stat & STAT_BSY) || ((stat & REQ_MASK) != REQ_DATAIN))                break;              if (stat & STAT_REQ)              {                *data++ = DATA;                --len;              }            }#endif /* SEAGATE_USE_ASM *//* SJT: End. */#if (DEBUG & PHASE_DATAIN)            printk ("scsi%d: transfered -= %d\n", hostno, len);            transfered -= len;          /* Since we assumed all of Len got  *                                           transfered, correct our mistake */#endif          }          if (!len && nobuffs)          {            --nobuffs;            ++buffer;            len = buffer->length;            data = (unsigned char *) buffer->address;            DPRINTK (DEBUG_SG, 		     "scsi%d : next scatter-gather buffer len = %d address = %08x\n",                    hostno, len, data);          }          break;        case REQ_CMDOUT:          while (((status_read = STATUS) & STAT_BSY) &&                 ((status_read & REQ_MASK) == REQ_CMDOUT))            if (status_read & STAT_REQ)            {              WRITE_DATA (*(const unsigned char *) cmnd);              cmnd = 1 + (const unsigned char *) cmnd;#ifdef SLOW_RATE              if (borken)                borken_wait ();#endif            }          break;        case REQ_STATIN:          status = DATA;          break;        case REQ_MSGOUT:/* *    We can only have sent a MSG OUT if we requested to do this *      by raising ATTN.  So, we must drop ATTN. */          WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE);/* *    If we are reconnecting, then we must send an IDENTIFY message in *       response  to MSGOUT. */          switch (reselect)          {            case CAN_RECONNECT:              WRITE_DATA (IDENTIFY (1, lun));              DPRINTK (PHASE_RESELECT | PHASE_MSGOUT, "scsi%d : sent IDENTIFY message.\n", hostno);              break;#ifdef LINKED            case LINKED_WRONG:              WRITE_DATA (ABORT);              linked_connected = 0;              reselect = CAN_RECONNECT;              goto connect_loop;              DPRINTK (PHASE_MSGOUT | DEBUG_LINKED, 		       "scsi%d : sent ABORT message to cancel incorrect I_T_L nexus.\n", hostno);#endif /* LINKED */              DPRINTK (DEBUG_LINKED, "correct\n");            default:              WRITE_DATA (NOP);              printk ("scsi%d : target %d requested MSGOUT, sent NOP message.\n", hostno, target);          }          break;        case REQ_MSGIN:          switch (message = DATA)          {            case DISCONNECT:	      DANY ("seagate: deciding to disconnect\n");              should_reconnect = 1;              current_data = data;      /* WDE add */              current_buffer = buffer;              current_bufflen = len;    /* WDE add */              current_nobuffs = nobuffs;#ifdef LINKED              linked_connected = 0;#endif              done = 1;              DPRINTK ((PHASE_RESELECT | PHASE_MSGIN), "scsi%d : disconnected.\n", hostno);              break;#ifdef LINKED            case LINKED_CMD_COMPLETE:            case LINKED_FLG_CMD_COMPLETE:#endif            case COMMAND_COMPLETE:/* * Note : we should check for underflow here. */              DPRINTK (PHASE_MSGIN, "scsi%d : command complete.\n", hostno);              done = 1;              break;            case ABORT:              DPRINTK (PHASE_MSGIN, "scsi%d : abort message.\n", hostno);              done = 1;              break;            case SAVE_POINTERS:              current_buffer = buffer;              current_bufflen = len;    /* WDE add */              current_data = data;      /* WDE mod */              current_nobuffs = nobuffs;              DPRINTK (PHASE_MSGIN, "scsi%d : pointers saved.\n", hostno);              break;            case RESTORE_POINTERS:              buffer = current_buffer;              cmnd = current_cmnd;              data = current_data;      /* WDE mod */              len = current_bufflen;              nobuffs = current_nobuffs;              DPRINTK (PHASE_MSGIN, "scsi%d : pointers restored.\n", hostno);              break;            default:/* *    IDENTIFY distinguishes itself from the other messages by setting the *      high byte. [FIXME: should not this read "the high bit"? - pavel@ucw.cz] * *      Note : we need to handle at least one outstanding command per LUN, *      and need to hash the SCSI command for that I_T_L nexus based on the *      known ID (at this point) and LUN. */              if (message & 0x80)              {                DPRINTK (PHASE_MSGIN, "scsi%d : IDENTIFY message received from id %d, lun %d.\n",                        hostno, target, message & 7);              }              else              {/* *      We should go into a MESSAGE OUT phase, and send  a MESSAGE_REJECT *      if we run into a message that we don't like.  The seagate driver *      needs some serious restructuring first though. */                DPRINTK (PHASE_MSGIN, 			 "scsi%d : unknown message %d from target %d.\n", hostno, message, target);              }          }          break;        default:          printk ("scsi%d : unknown phase.\n", hostno);          st0x_aborted = DID_ERROR;      }                                 /* end of switch (status_read &                                           REQ_MASK) */#ifdef SLOW_RATE/* * I really don't care to deal with borken devices in each single * byte transfer case (ie, message in, message out, status), so * I'll do the wait here if necessary. */      if (borken)        borken_wait ();#endif    }                                   /* if(status_read & STAT_REQ) ends */  }                                     /* while(((status_read = STATUS)...)                                           ends */  DPRINTK (PHASE_DATAIN | PHASE_DATAOUT | PHASE_EXIT, 	   "scsi%d : Transfered %d bytes\n", hostno, transfered);#if (DEBUG & PHASE_EXIT)#if 0                                   /* Doesn't work for scatter/gather */  printk ("Buffer : \n");  for (i = 0; i < 20; ++i)    printk ("%02x  ", ((unsigned char *) data)[i]);     /* WDE mod */  printk ("\n");#endif  printk ("scsi%d : status = ", hostno);  print_status (status);  printk ("message = %02x\n", message);#endif/* We shouldn't reach this until *after* BSY has been deasserted */#ifdef LINKED  else  {/* * Fix the message byte so that unsuspecting high level drivers don't * puke when they see a LINKED COMMAND message in place of the COMMAND * COMPLETE they may be expecting.  Shouldn't be necessary, but it's * better to be on the safe side. * * A non LINKED* message byte will indicate that the command completed, * and we are now disconnected. */    switch (message)    {      case LINKED_CMD_COMPLETE:      case LINKED_FLG_CMD_COMPLETE:        message = COMMAND_COMPLETE;        linked_target = current_target;        linked_lun = current_lun;        linked_connected = 1;	DPRINTK (DEBUG_LINKED, "scsi%d : keeping I_T_L nexus established"		 "for linked command.\n", hostno);    /* We also will need to adjust status to accommodate intermediate       conditions. */        if ((status == INTERMEDIATE_GOOD) ||            (status == INTERMEDIATE_C_GOOD))          status = GOOD;        break;/* * We should also handle what are "normal" termination messages * here (ABORT, BUS_DEVICE_RESET?, and COMMAND_COMPLETE individually, * and flake if things aren't right. */      default:        DPRINTK (DEBUG_LINKED, "scsi%d : closing I_T_L nexus.\n", hostno);        linked_connected = 0;    }  }#endif /* LINKED */  if (should_reconnect)  {    DPRINTK (PHASE_RESELECT, "scsi%d : exiting seagate_st0x_queue_command()"	     "with reconnect enabled.\n", hostno);    WRITE_CONTROL (BASE_CMD | CMD_INTR);  }  else    WRITE_CONTROL (BASE_CMD);  return retcode (st0x_aborted);}                                       /* end of internal_command */int seagate_st0x_abort (Scsi_Cmnd * SCpnt){  st0x_aborted = DID_ABORT;  return SCSI_ABORT_PENDING;}#undef ULOOP#undef TIMEOUT/* * the seagate_st0x_reset function resets the SCSI bus  */int seagate_st0x_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags){/* No timeouts - this command is going to fail because it was reset. */  DANY ("scsi%d: Reseting bus... ", hostno );/* assert  RESET signal on SCSI bus.  */  WRITE_CONTROL (BASE_CMD | CMD_RST);  udelay( 20*1000 );  WRITE_CONTROL (BASE_CMD);  st0x_aborted = DID_RESET;  DANY ("done.\n");  return SCSI_RESET_WAKEUP;}int seagate_st0x_biosparam (Disk * disk, kdev_t dev, int *ip){  unsigned char buf[256 + sizeof (Scsi_Ioctl_Command)],                 cmd[6], *data, *page;  Scsi_Ioctl_Command *sic = (Scsi_Ioctl_Command *) buf;  int result, formatted_sectors, total_sectors;  int cylinders, heads, sectors;  int capacity;/* * Only SCSI-I CCS drives and later implement the necessary mode sense * pages. */  if (disk->device->scsi_level < 2)    return -1;  data = sic->data;  cmd[0] = MODE_SENSE;  cmd[1] = (disk->device->lun << 5) & 0xe5;  cmd[2] = 0x04;                        /* Read page 4, rigid disk geometry                                           page current values */  cmd[3] = 0;  cmd[4] = 255;  cmd[5] = 0;/* * We are transferring 0 bytes in the out direction, and expect to get back * 24 bytes for each mode page. */  sic->inlen = 0;  sic->outlen = 256;  memcpy (data, cmd, 6);  if (!(result = kernel_scsi_ioctl (disk->device, SCSI_IOCTL_SEND_COMMAND,                                    sic)))  {/* * The mode page lies beyond the MODE SENSE header, with length 4, and * the BLOCK DESCRIPTOR, with length header[3]. */    page = data + 4 + data[3];    heads = (int) page[5];    cylinders = (page[2] << 16) | (page[3] << 8) | page[4];    cmd[2] = 0x03;                      /* Read page 3, format page current                                           values */    memcpy (data, cmd, 6);    if (!(result = kernel_scsi_ioctl (disk->device, SCSI_IOCTL_SEND_COMMAND,                                      sic)))    {      page = data + 4 + data[3];      sectors = (page[10] << 8) | page[11];/* * Get the total number of formatted sectors from the block descriptor, * so we can tell how many are being used for alternates. */      formatted_sectors = (data[4 + 1] << 16) | (data[4 + 2] << 8)                           | data[4 + 3];      total_sectors = (heads * cylinders * sectors);/* * Adjust the real geometry by subtracting * (spare sectors / (heads * tracks)) cylinders from the number of cylinders. * * It appears that the CE cylinder CAN be a partial cylinder. */      printk ("scsi%d : heads = %d cylinders = %d sectors = %d total = %d formatted = %d\n",              hostno, heads, cylinders, sectors, total_sectors,              formatted_sectors);      if (!heads || !sectors || !cylinders)        result = -1;      else        cylinders -= ((total_sectors - formatted_sectors) / (heads * sectors));/* * Now, we need to do a sanity check on the geometry to see if it is * BIOS compatible.  The maximum BIOS geometry is 1024 cylinders * * 256 heads * 64 sectors. */      if ((cylinders > 1024) || (sectors > 64))      {        /* The Seagate's seem to have some mapping.  Multiply           heads*sectors*cyl to get capacity.  Then start rounding down.         */        capacity = heads * sectors * cylinders;                       /* Old MFM Drives use this, so does the Seagate */        sectors = 17;        heads = 2;        capacity = capacity / sectors;        while (cylinders > 1024)        {          heads *= 2;                   /* For some reason, they go in                                           multiples */          cylinders = capacity / heads;        }      }      ip[0] = heads;      ip[1] = sectors;      ip[2] = cylinders;/* * There should be an alternate mapping for things the seagate doesn't * understand, but I couldn't say what it is with reasonable certainty. */    }  }  return result;}#ifdef MODULE/* Eventually this will go into an include file, but this will be later */Scsi_Host_Template driver_template = SEAGATE_ST0X;#include "scsi_module.c"#endif

⌨️ 快捷键说明

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