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

📄 ultrastor.c

📁 LINUX 1.0 内核c源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	printk("USx4F: queuecommand: aborted\n");
#if ULTRASTOR_MAX_CMDS > 1
	log_ultrastor_abort(&config, mscp_index);
#endif
#endif
	status <<= 16;

      aborted:
	set_bit(mscp_index, &config.mscp_free);
	/* If the driver queues commands, call the done proc here.  Otherwise
	   return an error.  */
#if ULTRASTOR_MAX_CMDS > 1
	SCpnt->result = status;
	done(SCpnt);
	return 0;
#else
	return status;
#endif
    }

    /* Store pointer in OGM address bytes */
    outl((unsigned int)my_mscp, config.ogm_address);

    /* Issue OGM interrupt */
    if (config.slot) {
	/* Write OGM command register on 24F */
	outb(1, config.ogm_address - 1);
	outb(0x2, LCL_DOORBELL_INTR(config.doorbell_address));
    } else {
	outb(0x1, LCL_DOORBELL_INTR(config.doorbell_address));
    }

    restore_flags(flags);

#if (ULTRASTOR_DEBUG & UD_COMMAND)
    printk("USx4F: queuecommand: returning\n");
#endif

    return 0;
}

/* This code must deal with 2 cases:

   1. The command has not been written to the OGM.  In this case, set
   the abort flag and return.

   2. The command has been written to the OGM and is stuck somewhere in
   the adapter.

   2a.  On a 24F, ask the adapter to abort the command.  It will interrupt
   when it does.

   2b.  Call the command's done procedure.

 */

int ultrastor_abort(Scsi_Cmnd *SCpnt, int code)
{
#if ULTRASTOR_DEBUG & UD_ABORT
    char out[108];
    unsigned char icm_status = 0, ogm_status = 0;
    unsigned int icm_addr = 0, ogm_addr = 0;
#endif
    unsigned int mscp_index;
    unsigned char old_aborted;
    void (*done)(Scsi_Cmnd *);

    if(config.slot) return 0;  /* Do not attempt an abort for the 24f */

    mscp_index = ((struct mscp *)SCpnt->host_scribble) - config.mscp;
    if (mscp_index >= ULTRASTOR_MAX_CMDS)
	panic("Ux4F aborting invalid MSCP");

#if ULTRASTOR_DEBUG & UD_ABORT
    if (config.slot)
      {
	int port0 = (config.slot << 12) | 0xc80;
	int i;
	int flags;
	save_flags(flags);
	cli();
	strcpy(out, "OGM %d:%x ICM %d:%x ports:  ");
	for (i = 0; i < 16; i++)
	  {
	    unsigned char p = inb(port0 + i);
	    out[28 + i * 3] = "0123456789abcdef"[p >> 4];
	    out[29 + i * 3] = "0123456789abcdef"[p & 15];
	    out[30 + i * 3] = ' ';
	  }
	out[28 + i * 3] = '\n';
	out[29 + i * 3] = 0;
	ogm_status = inb(port0 + 22);
	ogm_addr = inl(port0 + 23);
	icm_status = inb(port0 + 27);
	icm_addr = inl(port0 + 28);
	restore_flags(flags);
      }

    /* First check to see if an interrupt is pending.  I suspect the SiS
       chipset loses interrupts.  (I also suspect is mangles data, but
       one bug at a time... */
    if (config.slot ? inb(config.icm_address - 1) == 2 :
	(inb(SYS_DOORBELL_INTR(config.doorbell_address)) & 1))
      {
	int flags;
	save_flags(flags);
	printk("Ux4F: abort while completed command pending\n");
	restore_flags(flags);
	cli();
	ultrastor_interrupt(0);
	restore_flags(flags);
	return 0;
      }
#endif

    old_aborted = xchgb(code ? code : DID_ABORT, &config.aborted[mscp_index]);

    /* aborted == 0xff is the signal that queuecommand has not yet sent
       the command.  It will notice the new abort flag and fail.  */
    if (old_aborted == 0xff)
	return 0;

    /* On 24F, send an abort MSCP request.  The adapter will interrupt
       and the interrupt handler will call done.  */
    if (config.slot && inb(config.ogm_address - 1) == 0)
      {
	int flags;

	save_flags(flags);
	cli();
	outl((int)&config.mscp[mscp_index], config.ogm_address);
	inb(0xc80);	/* delay */
	outb(0x80, config.ogm_address - 1);
	outb(0x2, LCL_DOORBELL_INTR(config.doorbell_address));
#if ULTRASTOR_DEBUG & UD_ABORT
	log_ultrastor_abort(&config, mscp_index);
	printk(out, ogm_status, ogm_addr, icm_status, icm_addr);
#endif
	restore_flags(flags);
	return 0;
      }

#if ULTRASTOR_DEBUG & UD_ABORT
    log_ultrastor_abort(&config, mscp_index);
#endif

    /* Can't request a graceful abort.  Either this is not a 24F or
       the OGM is busy.  Don't free the command -- the adapter might
       still be using it.  Setting SCint = 0 causes the interrupt
       handler to ignore the command.  */

#if ULTRASTOR_DEBUG & UD_ABORT
    if (config.mscp[mscp_index].SCint != SCpnt)
	printk("abort: command mismatch, %x != %x\n",
	       config.mscp[mscp_index].SCint, SCpnt);
#endif
    if (config.mscp[mscp_index].SCint == 0)
	return 1;

    if (config.mscp[mscp_index].SCint != SCpnt) panic("Bad abort");
    config.mscp[mscp_index].SCint = 0;
    done = config.mscp[mscp_index].done;
    config.mscp[mscp_index].done = 0;
    SCpnt->result = DID_ABORT << 16;
    /* I worry about reentrancy in scsi.c  */
    done(SCpnt);

    /* Need to set a timeout here in case command never completes.  */
    return 0;

}

int ultrastor_reset(Scsi_Cmnd * SCpnt)
{
    int flags;
    register int i;
#if (ULTRASTOR_DEBUG & UD_RESET)
    printk("US14F: reset: called\n");
#endif

    if(config.slot) {
      if (SCpnt) SCpnt->flags |= NEEDS_JUMPSTART;
      return 0;  /* Do not attempt a reset for the 24f */
    };

    save_flags(flags);
    cli();

    /* Reset the adapter and SCSI bus.  The SCSI bus reset can be
       inhibited by clearing ultrastor_bus_reset before probe.  */
    outb(0xc0, LCL_DOORBELL_INTR(config.doorbell_address));
    if (config.slot)
      {
	outb(0, config.ogm_address - 1);
	outb(0, config.icm_address - 1);
      }

#if ULTRASTOR_MAX_CMDS == 1
    if (config.mscp_busy && config.mscp->done && config.mscp->SCint)
      {
	config.mscp->SCint->result = DID_RESET << 16;
	config.mscp->done(config.mscp->SCint);
      }
    config.mscp->SCint = 0;
#else
    for (i = 0; i < ULTRASTOR_MAX_CMDS; i++)
      {
	if (! (config.mscp_free & (1 << i)) &&
	    config.mscp[i].done && config.mscp[i].SCint)
	  {
	    config.mscp[i].SCint->result = DID_RESET << 16;
	    config.mscp[i].done(config.mscp[i].SCint);
	    config.mscp[i].done = 0;
	  }
	config.mscp[i].SCint = 0;
      }
#endif

    memset((unsigned char *)config.aborted, 0, sizeof config.aborted);
#if ULTRASTOR_MAX_CMDS == 1
    config.mscp_busy = 0;
#else
    config.mscp_free = ~0;
#endif

    restore_flags(flags);
    return 0;

}

int ultrastor_biosparam(int size, int dev, int * dkinfo)
{
    unsigned int s = config.heads * config.sectors;

    dkinfo[0] = config.heads;
    dkinfo[1] = config.sectors;
    dkinfo[2] = size / s;	/* Ignore partial cylinders */
#if 0
    if (dkinfo[2] > 1024)
	dkinfo[2] = 1024;
#endif
    return 0;
}

static void ultrastor_interrupt(int cpl)
{
    unsigned int status;
#if ULTRASTOR_MAX_CMDS > 1
    unsigned int mscp_index;
#endif
    register struct mscp *mscp;
    void (*done)(Scsi_Cmnd *);
    Scsi_Cmnd *SCtmp;

#if ULTRASTOR_MAX_CMDS == 1
    mscp = &config.mscp[0];
#else
    mscp = (struct mscp *)inl(config.icm_address);
    mscp_index = mscp - config.mscp;
    if (mscp_index >= ULTRASTOR_MAX_CMDS) {
	printk("Ux4F interrupt: bad MSCP address %x\n", (unsigned int) mscp);
	/* A command has been lost.  Reset and report an error
	   for all commands.  */
	ultrastor_reset(NULL);
	return;
    }
#endif

    /* Clean ICM slot (set ICMINT bit to 0) */
    if (config.slot) {
	unsigned char icm_status = inb(config.icm_address - 1);
#if ULTRASTOR_DEBUG & (UD_INTERRUPT|UD_ERROR|UD_ABORT)
	if (icm_status != 1 && icm_status != 2)
	    printk("US24F: ICM status %x for MSCP %d (%x)\n", icm_status,
		   mscp_index, (unsigned int) mscp);
#endif
	/* The manual says clear interrupt then write 0 to ICM status.
	   This seems backwards, but I'll do it anyway.  --jfc */
	outb(2, SYS_DOORBELL_INTR(config.doorbell_address));
	outb(0, config.icm_address - 1);
	if (icm_status == 4) {
	    printk("UltraStor abort command failed\n");
	    return;
	}
	if (icm_status == 3) {
	    void (*done)(Scsi_Cmnd *) = mscp->done;
	    if (done) {
		mscp->done = 0;
		mscp->SCint->result = DID_ABORT << 16;
		done(mscp->SCint);
	    }
	    return;
	}
    } else {
	outb(1, SYS_DOORBELL_INTR(config.doorbell_address));
    }

    SCtmp = mscp->SCint;
    mscp->SCint = NULL;

    if (SCtmp == 0)
      {
#if ULTRASTOR_DEBUG & (UD_ABORT|UD_INTERRUPT)
	printk("MSCP %d (%x): no command\n", mscp_index, (unsigned int) mscp);
#endif	
#if ULTRASTOR_MAX_CMDS == 1
	config.mscp_busy = FALSE;
#else
	set_bit(mscp_index, &config.mscp_free);
#endif
	config.aborted[mscp_index] = 0;
	return;
      }

    /* Save done locally and zero before calling.  This is needed as
       once we call done, we may get another command queued before this
       interrupt service routine can return. */
    done = mscp->done;
    mscp->done = 0;

    /* Let the higher levels know that we're done */
    switch (mscp->adapter_status)
      {
      case 0:
	status = DID_OK << 16;
	break;
      case 0x01:	/* invalid command */
      case 0x02:	/* invalid parameters */
      case 0x03:	/* invalid data list */
      default:
	status = DID_ERROR << 16;
	break;
      case 0x84:	/* SCSI bus abort */
	status = DID_ABORT << 16;
	break;
      case 0x91:
	status = DID_TIME_OUT << 16;
	break;
      }

    SCtmp->result = status | mscp->target_status;

    SCtmp->host_scribble = 0;

    /* Free up mscp block for next command */
#if ULTRASTOR_MAX_CMDS == 1
    config.mscp_busy = FALSE;
#else
    set_bit(mscp_index, &config.mscp_free);
#endif

#if ULTRASTOR_DEBUG & (UD_ABORT|UD_INTERRUPT)
    if (config.aborted[mscp_index])
	printk("Ux4 interrupt: MSCP %d (%x) aborted = %d\n",
	       mscp_index, (unsigned int) mscp, config.aborted[mscp_index]);
#endif
    config.aborted[mscp_index] = 0;

    if (done)
	done(SCtmp);
    else
	printk("US14F: interrupt: unexpected interrupt\n");

    if (config.slot ? inb(config.icm_address - 1) : (inb(SYS_DOORBELL_INTR(config.doorbell_address)) & 1))
      printk("Ux4F: multiple commands completed\n");

#if (ULTRASTOR_DEBUG & UD_INTERRUPT)
    printk("USx4F: interrupt: returning\n");
#endif
}

⌨️ 快捷键说明

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