staticvoid esp_set_all_config3(struct esp *esp, u8 val)
{ int i;
for (i = 0; i < ESP_MAX_TARGET; i++)
esp->target[i].esp_config3 = val;
}
/* Reset the ESP chip, _not_ the SCSI bus. */ staticvoid esp_reset_esp(struct esp *esp)
{ /* Now reset the ESP chip */
scsi_esp_cmd(esp, ESP_CMD_RC);
scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA); if (esp->rev == FAST)
esp_write8(ESP_CONFIG2_FENAB, ESP_CFG2);
scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA);
/* This is the only point at which it is reliable to read * the ID-code for a fast ESP chip variants.
*/
esp->max_period = ((35 * esp->ccycle) / 1000); if (esp->rev == FAST) {
u8 family_code = ESP_FAMILY(esp_read8(ESP_UID));
if (family_code == ESP_UID_F236) {
esp->rev = FAS236;
} elseif (family_code == ESP_UID_HME) {
esp->rev = FASHME; /* Version is usually '5'. */
} elseif (family_code == ESP_UID_FSC) {
esp->rev = FSC; /* Enable Active Negation */
esp_write8(ESP_CONFIG4_RADE, ESP_CFG4);
} else {
esp->rev = FAS100A;
}
esp->min_period = ((4 * esp->ccycle) / 1000);
} else {
esp->min_period = ((5 * esp->ccycle) / 1000);
} if (esp->rev == FAS236) { /* * The AM53c974 chip returns the same ID as FAS236; * try to configure glitch eater.
*/
u8 config4 = ESP_CONFIG4_GE1;
esp_write8(config4, ESP_CFG4);
config4 = esp_read8(ESP_CFG4); if (config4 & ESP_CONFIG4_GE1) {
esp->rev = PCSCSI;
esp_write8(esp->config4, ESP_CFG4);
}
}
esp->max_period = (esp->max_period + 3)>>2;
esp->min_period = (esp->min_period + 3)>>2;
esp_write8(esp->config1, ESP_CFG1); switch (esp->rev) { case ESP100: /* nothing to do */ break;
case ESP100A:
esp_write8(esp->config2, ESP_CFG2); break;
if (esp->flags & ESP_FLAG_NO_DMA_MAP) { /* * For pseudo DMA and PIO we need the virtual address instead of * a dma address, so perform an identity mapping.
*/
spriv->num_sg = scsi_sg_count(cmd);
/* ESP chip limits other variants by 16-bits of transfer * count. Actually on FAS100A and FAS236 we could get * 24-bits of transfer count by enabling ESP_CONFIG2_FENAB * in the ESP_CFG2 register but that causes other unwanted * changes so we don't use it currently.
*/ if (dma_len > (1U << 16))
dma_len = (1U << 16);
/* All of the DMA variants hooked up to these chips * cannot handle crossing a 24-bit address boundary.
*/
base = dma_addr & ((1U << 24) - 1U);
end = base + dma_len; if (end > (1U << 24))
end = (1U <<24);
dma_len = end - base;
} return dma_len;
}
if (lp->hold) { /* We are being held by active tagged * commands.
*/ if (lp->num_tagged) return -EBUSY;
/* Tagged commands completed, we can unplug * the queue and run this untagged command.
*/
lp->hold = 0;
} elseif (lp->num_tagged) { /* Plug the queue until num_tagged decreases * to zero in esp_free_lun_tag.
*/
lp->hold = 1; return -EBUSY;
}
lp->non_tagged_cmd = ent; return 0;
}
/* Tagged command. Check that it isn't blocked by a non-tagged one. */ if (lp->non_tagged_cmd || lp->hold) return -EBUSY;
/* When a contingent allegiance condition is created, we force feed a * REQUEST_SENSE command to the device to fetch the sense data. I * tried many other schemes, relying on the scsi error handling layer * to send out the REQUEST_SENSE automatically, but this was difficult * to get right especially in the presence of applications like smartd * which use SG_IO to send out their own REQUEST_SENSE commands.
*/ staticvoid esp_autosense(struct esp *esp, struct esp_cmd_entry *ent)
{ struct scsi_cmnd *cmd = ent->cmd; struct scsi_device *dev = cmd->device; int tgt, lun;
u8 *p, val;
tgt = dev->id;
lun = dev->lun;
if (!ent->sense_ptr) {
esp_log_autosense("Doing auto-sense for tgt[%d] lun[%d]\n",
tgt, lun);
esp_map_sense(esp, ent);
}
ent->saved_sense_ptr = ent->sense_ptr;
esp->msg_out_len = 0; if (tp->flags & ESP_TGT_CHECK_NEGO) { /* Need to negotiate. If the target is broken * go for synchronous transfers and non-wide.
*/ if (tp->flags & ESP_TGT_BROKEN) {
tp->flags &= ~ESP_TGT_DISCONNECT;
tp->nego_goal_period = 0;
tp->nego_goal_offset = 0;
tp->nego_goal_width = 0;
tp->nego_goal_tags = 0;
}
/* If the settings are not changing, skip this. */ if (spi_width(tp->starget) == tp->nego_goal_width &&
spi_period(tp->starget) == tp->nego_goal_period &&
spi_offset(tp->starget) == tp->nego_goal_offset) {
tp->flags &= ~ESP_TGT_CHECK_NEGO; goto build_identify;
}
if (ent->eh_done) {
complete(ent->eh_done);
ent->eh_done = NULL;
}
if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
esp_unmap_sense(esp, ent);
/* Restore the message/status bytes to what we actually * saw originally. Also, report that we are providing * the sense data.
*/
cmd->result = SAM_STAT_CHECK_CONDITION;
ent->flags &= ~ESP_CMD_FLAG_AUTOSENSE; if (esp_debug & ESP_DEBUG_AUTOSENSE) { int i;
printk("esp%d: tgt[%d] lun[%d] AUTO SENSE[ ",
esp->host->unique_id, tgt, lun); for (i = 0; i < 18; i++)
printk("%02x ", cmd->sense_buffer[i]);
printk("]\n");
}
}
ent = esp_get_ent(esp); if (!ent) return SCSI_MLQUEUE_HOST_BUSY;
ent->cmd = cmd;
spriv = ESP_CMD_PRIV(cmd);
spriv->num_sg = 0;
list_add_tail(&ent->list, &esp->queued_cmds);
esp_maybe_execute_command(esp);
return 0;
}
static DEF_SCSI_QCMD(esp_queuecommand)
staticint esp_check_gross_error(struct esp *esp)
{ if (esp->sreg & ESP_STAT_SPAM) { /* Gross Error, could be one of: * - top of fifo overwritten * - top of command register overwritten * - DMA programmed with wrong direction * - improper phase change
*/
shost_printk(KERN_ERR, esp->host, "Gross error sreg[%02x]\n", esp->sreg); /* XXX Reset the chip. XXX */ return 1;
} return 0;
}
staticint esp_check_spur_intr(struct esp *esp)
{ switch (esp->rev) { case ESP100: case ESP100A: /* The interrupt pending bit of the status register cannot * be trusted on these revisions.
*/
esp->sreg &= ~ESP_STAT_INTR; break;
default: if (!(esp->sreg & ESP_STAT_INTR)) { if (esp->ireg & ESP_INTR_SR) return 1;
/* If the DMA is indicating interrupt pending and the * ESP is not, the only possibility is a DMA error.
*/ if (!esp->ops->dma_error(esp)) {
shost_printk(KERN_ERR, esp->host, "Spurious irq, sreg=%02x.\n",
esp->sreg); return -1;
}
/* In order to avoid having to add a special half-reconnected state * into the driver we just sit here and poll through the rest of * the reselection process to get the tag message bytes.
*/ staticstruct esp_cmd_entry *esp_reconnect_with_tag(struct esp *esp, struct esp_lun_data *lp)
{ struct esp_cmd_entry *ent; int i;
if (!lp->num_tagged) {
shost_printk(KERN_ERR, esp->host, "Reconnect w/num_tagged==0\n"); return NULL;
}
esp_log_reconnect("reconnect tag, ");
for (i = 0; i < ESP_QUICKIRQ_LIMIT; i++) { if (esp->ops->irq_pending(esp)) break;
} if (i == ESP_QUICKIRQ_LIMIT) {
shost_printk(KERN_ERR, esp->host, "Reconnect IRQ1 timeout\n"); return NULL;
}
if ((esp->sreg & ESP_STAT_PMASK) != ESP_MIP) {
shost_printk(KERN_ERR, esp->host, "Reconnect, not MIP sreg[%02x].\n", esp->sreg); return NULL;
}
/* DMA in the tag bytes... */
esp->command_block[0] = 0xff;
esp->command_block[1] = 0xff;
esp->ops->send_dma_cmd(esp, esp->command_block_dma,
2, 2, 1, ESP_CMD_DMA | ESP_CMD_TI);
/* ACK the message. */
scsi_esp_cmd(esp, ESP_CMD_MOK);
for (i = 0; i < ESP_RESELECT_TAG_LIMIT; i++) { if (esp->ops->irq_pending(esp)) {
esp->sreg = esp_read8(ESP_STATUS);
esp->ireg = esp_read8(ESP_INTRPT); if (esp->ireg & ESP_INTR_FDONE) break;
}
udelay(1);
} if (i == ESP_RESELECT_TAG_LIMIT) {
shost_printk(KERN_ERR, esp->host, "Reconnect IRQ2 timeout\n"); return NULL;
}
esp->ops->dma_drain(esp);
esp->ops->dma_invalidate(esp);
esp_log_reconnect("IRQ2(%d:%x:%x) tag[%x:%x]\n",
i, esp->ireg, esp->sreg,
esp->command_block[0],
esp->command_block[1]);
if (esp->command_block[0] < SIMPLE_QUEUE_TAG ||
esp->command_block[0] > ORDERED_QUEUE_TAG) {
shost_printk(KERN_ERR, esp->host, "Reconnect, bad tag type %02x.\n",
esp->command_block[0]); return NULL;
}
ent = lp->tagged_cmds[esp->command_block[1]]; if (!ent) {
shost_printk(KERN_ERR, esp->host, "Reconnect, no entry for tag %02x.\n",
esp->command_block[1]); return NULL;
}
BUG_ON(esp->active_cmd); if (esp->rev == FASHME) { /* FASHME puts the target and lun numbers directly * into the fifo.
*/
target = esp->fifo[0];
lun = esp->fifo[1] & 0x7;
} else {
u8 bits = esp_read8(ESP_FDATA);
/* Older chips put the lun directly into the fifo, but * the target is given as a sample of the arbitration * lines on the bus at reselection time. So we should * see the ID of the ESP and the one reconnecting target * set in the bitmap.
*/ if (!(bits & esp->scsi_id_mask)) goto do_reset;
bits &= ~esp->scsi_id_mask; if (!bits || (bits & (bits - 1))) goto do_reset;
scsi_esp_cmd(esp, ESP_CMD_FLUSH); if (esp->rev == ESP100) {
u8 ireg = esp_read8(ESP_INTRPT); /* This chip has a bug during reselection that can * cause a spurious illegal-command interrupt, which * we simply ACK here. Another possibility is a bus * reset so we must check for that.
*/ if (ireg & ESP_INTR_SR) goto do_reset;
}
scsi_esp_cmd(esp, ESP_CMD_NULL);
}
if (esp->ops->dma_error(esp)) { /* If we see a DMA error during or as a result of selection, * all bets are off.
*/
esp_schedule_reset(esp);
esp_cmd_is_done(esp, ent, cmd, DID_ERROR); return 0;
}
/* Carefully back out of the selection attempt. Release * resources (such as DMA mapping & TAG) and reset state (such * as message out and command delivery variables).
*/ if (!(ent->flags & ESP_CMD_FLAG_AUTOSENSE)) {
esp_unmap_dma(esp, cmd);
esp_free_lun_tag(ent, cmd->device->hostdata);
tp->flags &= ~(ESP_TGT_NEGO_SYNC | ESP_TGT_NEGO_WIDE);
esp->cmd_bytes_ptr = NULL;
esp->cmd_bytes_left = 0;
} else {
esp_unmap_sense(esp, ent);
}
/* Now that the state is unwound properly, put back onto * the issue queue. This command is no longer active.
*/
list_move(&ent->list, &esp->queued_cmds);
esp->active_cmd = NULL;
/* Return value ignored by caller, it directly invokes * esp_reconnect().
*/ return 0;
}
if (esp->ireg == ESP_INTR_DC) { struct scsi_device *dev = cmd->device;
/* Disconnect. Make sure we re-negotiate sync and * wide parameters if this target starts responding * again in the future.
*/
esp->target[dev->id].flags |= ESP_TGT_CHECK_NEGO;
if (esp->ireg == (ESP_INTR_FDONE | ESP_INTR_BSERV)) { /* Selection successful. On pre-FAST chips we have * to do a NOP and possibly clean out the FIFO.
*/ if (esp->rev <= ESP236) { int fcnt = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES;
/* If we are doing a Select And Stop command, negotiation, etc. * we'll do the right thing as we transition to the next phase.
*/
esp_event(esp, ESP_EVENT_CHECK_PHASE); return 0;
}
/* * The am53c974 has a DMA 'peculiarity'. The doc states: * In some odd byte conditions, one residual byte will * be left in the SCSI FIFO, and the FIFO Flags will * never count to '0 '. When this happens, the residual * byte should be retrieved via PIO following completion * of the BLAST operation.
*/ if (fifo_cnt == 1 && ent->flags & ESP_CMD_FLAG_RESIDUAL) {
size_t count = 1;
size_t offset = bytes_sent;
u8 bval = esp_read8(ESP_FDATA);
flush_fifo = 0; if (!esp->prev_soff) { /* Synchronous data transfer, always flush fifo. */
flush_fifo = 1;
} else { if (esp->rev == ESP100) {
u32 fflags, phase;
/* ESP100 has a chip bug where in the synchronous data * phase it can mistake a final long REQ pulse from the * target as an extra data byte. Fun. * * To detect this case we resample the status register * and fifo flags. If we're still in a data phase and * we see spurious chunks in the fifo, we return error * to the caller which should reset and set things up * such that we only try future transfers to this * target in synchronous mode.
*/
esp->sreg = esp_read8(ESP_STATUS);
phase = esp->sreg & ESP_STAT_PMASK;
fflags = esp_read8(ESP_FFLAGS);
if (esp_soff) {
esp_stp &= 0x1f;
esp_soff |= esp->radelay; if (esp->rev >= FAS236) {
u8 bit = ESP_CONFIG3_FSCSI; if (esp->rev >= FAS100A)
bit = ESP_CONFIG3_FAST;
/* Analyze msgin bytes received from target so far. Return non-zero * if there are more bytes needed to complete the message.
*/ staticint esp_msgin_process(struct esp *esp)
{
u8 msg0 = esp->msg_in[0]; int len = esp->msg_in_len;
if (esp->ireg != ESP_INTR_BSERV) { /* We should always see exactly a bus-service * interrupt at the end of a successful transfer.
*/
shost_printk(KERN_INFO, esp->host, "data done, not BSERV, resetting\n");
esp_schedule_reset(esp); return 0;
}
if (esp_debug & ESP_DEBUG_MSGOUT) { int i;
printk("ESP: Sending message [ "); for (i = 0; i < esp->msg_out_len; i++)
printk("%02x ", esp->msg_out[i]);
printk("]\n");
}
if (esp->rev == FASHME) { int i;
/* Always use the fifo. */ for (i = 0; i < esp->msg_out_len; i++) {
esp_write8(esp->msg_out[i], ESP_FDATA);
esp_write8(0, ESP_FDATA);
}
scsi_esp_cmd(esp, ESP_CMD_TI);
} else { if (esp->msg_out_len == 1) {
esp_write8(esp->msg_out[0], ESP_FDATA);
scsi_esp_cmd(esp, ESP_CMD_TI);
} elseif (esp->flags & ESP_FLAG_USE_FIFO) { for (i = 0; i < esp->msg_out_len; i++)
esp_write8(esp->msg_out[i], ESP_FDATA);
scsi_esp_cmd(esp, ESP_CMD_TI);
} else { /* Use DMA. */
memcpy(esp->command_block,
esp->msg_out,
esp->msg_out_len);
esp->ops->send_dma_cmd(esp,
esp->command_block_dma,
esp->msg_out_len,
esp->msg_out_len,
0,
ESP_CMD_DMA|ESP_CMD_TI);
}
}
esp_event(esp, ESP_EVENT_MSGOUT_DONE); break;
} case ESP_EVENT_MSGOUT_DONE: if (esp->rev == FASHME) {
scsi_esp_cmd(esp, ESP_CMD_FLUSH);
} else { if (esp->msg_out_len > 1)
esp->ops->dma_invalidate(esp);
/* XXX if the chip went into disconnected mode, * we can't run the phase state machine anyway.
*/ if (!(esp->ireg & ESP_INTR_DC))
scsi_esp_cmd(esp, ESP_CMD_NULL);
}
esp->msg_out_len = 0;
esp_event(esp, ESP_EVENT_CHECK_PHASE); goto again; case ESP_EVENT_MSGIN: if (esp->ireg & ESP_INTR_BSERV) { if (esp->rev == FASHME) { if (!(esp_read8(ESP_STATUS2) &
ESP_STAT2_FEMPTY))
scsi_esp_cmd(esp, ESP_CMD_FLUSH);
} else {
scsi_esp_cmd(esp, ESP_CMD_FLUSH); if (esp->rev == ESP100)
scsi_esp_cmd(esp, ESP_CMD_NULL);
}
scsi_esp_cmd(esp, ESP_CMD_TI);
esp->flags |= ESP_FLAG_QUICKIRQ_CHECK; return 1;
} if (esp->ireg & ESP_INTR_FDONE) {
u8 val;
if (esp->rev == FASHME)
val = esp->fifo[0]; else
val = esp_read8(ESP_FDATA);
esp->msg_in[esp->msg_in_len++] = val;
esp_log_msgin("Got msgin byte %x\n", val);
if (!esp_msgin_process(esp))
esp->msg_in_len = 0;
if (esp->rev == FASHME)
scsi_esp_cmd(esp, ESP_CMD_FLUSH);
scsi_esp_cmd(esp, ESP_CMD_MOK);
/* Check whether a bus reset is to be done next */ if (esp->event == ESP_EVENT_RESET) return 0;
if (tp->starget)
__starget_for_each_device(tp->starget, NULL,
esp_clear_hold);
}
esp->flags &= ~ESP_FLAG_RESETTING;
}
/* Runs under host->lock */ staticvoid __esp_interrupt(struct esp *esp)
{ int finish_reset, intr_done;
u8 phase;
/* * Once INTRPT is read STATUS and SSTEP are cleared.
*/
esp->sreg = esp_read8(ESP_STATUS);
esp->seqreg = esp_read8(ESP_SSTEP);
esp->ireg = esp_read8(ESP_INTRPT);
if (esp->flags & ESP_FLAG_RESETTING) {
finish_reset = 1;
} else { if (esp_check_gross_error(esp)) return;
finish_reset = esp_check_spur_intr(esp); if (finish_reset < 0) return;
}
if (esp->ireg & ESP_INTR_SR)
finish_reset = 1;
if (finish_reset) {
esp_reset_cleanup(esp); if (esp->eh_reset) {
complete(esp->eh_reset);
esp->eh_reset = NULL;
} return;
}
spin_lock_irqsave(esp->host->host_lock, flags);
ret = IRQ_NONE; if (esp->ops->irq_pending(esp)) {
ret = IRQ_HANDLED; for (;;) { int i;
__esp_interrupt(esp); if (!(esp->flags & ESP_FLAG_QUICKIRQ_CHECK)) break;
esp->flags &= ~ESP_FLAG_QUICKIRQ_CHECK;
for (i = 0; i < ESP_QUICKIRQ_LIMIT; i++) { if (esp->ops->irq_pending(esp)) break;
} if (i == ESP_QUICKIRQ_LIMIT) break;
}
}
spin_unlock_irqrestore(esp->host->host_lock, flags);
val = esp_read8(ESP_CFG2);
val &= ~ESP_CONFIG2_MAGIC;
esp->config2 = 0; if (val != (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) { /* * If what we write to cfg2 does not come back, * cfg2 is not implemented. * Therefore this must be a plain esp100.
*/
esp->rev = ESP100; return;
}
}
val = esp_read8(ESP_CFG3); if (val != 5) { /* The cfg2 register is implemented, however * cfg3 is not, must be esp100a.
*/
esp->rev = ESP100A;
} else {
esp_set_all_config3(esp, 0);
esp->prev_cfg3 = 0;
esp_write8(esp->prev_cfg3, ESP_CFG3);
/* All of cfg{1,2,3} implemented, must be one of * the fas variants, figure out which one.
*/ if (esp->cfact == 0 || esp->cfact > ESP_CCF_F5) {
esp->rev = FAST;
esp->sync_defp = SYNC_DEFP_FAST;
} else {
esp->rev = ESP236;
}
}
}
staticvoid esp_init_swstate(struct esp *esp)
{ int i;
/* Start with a clear state, domain validation (via ->sdev_configure, * spi_dv_device()) will attempt to enable SYNC, WIDE, and tagged * commands.
*/ for (i = 0 ; i < ESP_MAX_TARGET; i++) {
esp->target[i].flags = 0;
esp->target[i].nego_goal_period = 0;
esp->target[i].nego_goal_offset = 0;
esp->target[i].nego_goal_width = 0;
esp->target[i].nego_goal_tags = 0;
}
}
/* This places the ESP into a known state at boot time. */ staticvoid esp_bootup_reset(struct esp *esp)
{
u8 val;
/* Reset the DMA */
esp->ops->reset_dma(esp);
/* Reset the ESP */
esp_reset_esp(esp);
/* Reset the SCSI bus, but tell ESP not to generate an irq */
val = esp_read8(ESP_CFG1);
val |= ESP_CONFIG1_SRRDISAB;
esp_write8(val, ESP_CFG1);
scsi_esp_cmd(esp, ESP_CMD_RS);
udelay(400);
esp_write8(esp->config1, ESP_CFG1);
/* Eat any bitrot in the chip and we are done... */
esp_read8(ESP_INTRPT);
}
staticvoid esp_set_clock_params(struct esp *esp)
{ int fhz;
u8 ccf;
/* This is getting messy but it has to be done correctly or else * you get weird behavior all over the place. We are trying to * basically figure out three pieces of information. * * a) Clock Conversion Factor * * This is a representation of the input crystal clock frequency * going into the ESP on this machine. Any operation whose timing * is longer than 400ns depends on this value being correct. For * example, you'll get blips for arbitration/selection during high * load or with multiple targets if this is not set correctly. * * b) Selection Time-Out * * The ESP isn't very bright and will arbitrate for the bus and try * to select a target forever if you let it. This value tells the * ESP when it has taken too long to negotiate and that it should * interrupt the CPU so we can see what happened. The value is * computed as follows (from NCR/Symbios chip docs). * * (Time Out Period) * (Input Clock) * STO = ---------------------------------- * (8192) * (Clock Conversion Factor) * * We use a time out period of 250ms (ESP_BUS_TIMEOUT). * * c) Imperical constants for synchronous offset and transfer period * register values * * This entails the smallest and largest sync period we could ever * handle on this ESP.
*/
fhz = esp->cfreq;
/* If we can't find anything reasonable, just assume 20MHZ. * This is the clock frequency of the older sun4c's where I've * been unable to find the clock-frequency PROM property. All * other machines provide useful values it seems.
*/ if (fhz <= 5000000 || ccf < 1 || ccf > 8) {
fhz = 20000000;
ccf = 4;
}
/* XXX This helps a lot with debugging but might be a bit * XXX much for the final driver.
*/
spin_lock_irqsave(esp->host->host_lock, flags);
shost_printk(KERN_ERR, esp->host, "Aborting command [%p:%02x]\n",
cmd, cmd->cmnd[0]);
ent = esp->active_cmd; if (ent)
shost_printk(KERN_ERR, esp->host, "Current command [%p:%02x]\n",
ent->cmd, ent->cmd->cmnd[0]);
list_for_each_entry(ent, &esp->queued_cmds, list) {
shost_printk(KERN_ERR, esp->host, "Queued command [%p:%02x]\n",
ent->cmd, ent->cmd->cmnd[0]);
}
list_for_each_entry(ent, &esp->active_cmds, list) {
shost_printk(KERN_ERR, esp->host, " Active command [%p:%02x]\n",
ent->cmd, ent->cmd->cmnd[0]);
}
esp_dump_cmd_log(esp);
spin_unlock_irqrestore(esp->host->host_lock, flags);
spin_lock_irqsave(esp->host->host_lock, flags);
ent = NULL;
list_for_each_entry(tmp, &esp->queued_cmds, list) { if (tmp->cmd == cmd) {
ent = tmp; break;
}
}
if (ent) { /* Easiest case, we didn't even issue the command * yet so it is trivial to abort.
*/
list_del(&ent->list);
cmd->result = DID_ABORT << 16;
scsi_done(cmd);
esp_put_ent(esp, ent);
goto out_success;
}
init_completion(&eh_done);
ent = esp->active_cmd; if (ent && ent->cmd == cmd) { /* Command is the currently active command on * the bus. If we already have an output message * pending, no dice.
*/ if (esp->msg_out_len) goto out_failure;
/* Send out an abort, encouraging the target to * go to MSGOUT phase by asserting ATN.
*/
esp->msg_out[0] = ABORT_TASK_SET;
esp->msg_out_len = 1;
ent->eh_done = &eh_done;
scsi_esp_cmd(esp, ESP_CMD_SATN);
} else { /* The command is disconnected. This is not easy to * abort. For now we fail and let the scsi error * handling layer go try a scsi bus reset or host * reset. * * What we could do is put together a scsi command * solely for the purpose of sending an abort message * to the target. Coming up with all the code to * cook up scsi commands, special case them everywhere, * etc. is for questionable gain and it would be better * if the generic scsi error handling layer could do at * least some of that for us. * * Anyways this is an area for potential future improvement * in this driver.
*/ goto out_failure;
}
out_failure: /* XXX This might be a good location to set ESP_TGT_BROKEN * XXX since we know which target/lun in particular is * XXX causing trouble.
*/
spin_unlock_irqrestore(esp->host->host_lock, flags); return FAILED;
}
/* XXX This is too simple... We should add lots of * XXX checks here so that if we find that the chip is * XXX very wedged we return failure immediately so * XXX that we can perform a full chip reset.
*/
esp->flags |= ESP_FLAG_RESETTING;
scsi_esp_cmd(esp, ESP_CMD_RS);
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.54Bemerkung:
Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.