diff options
Diffstat (limited to 'drivers/scsi/esp_scsi.c')
-rw-r--r-- | drivers/scsi/esp_scsi.c | 286 |
1 files changed, 203 insertions, 83 deletions
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index c3fc34b9964d..ac7da9db7317 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -369,19 +369,28 @@ static void esp_map_dma(struct esp *esp, struct scsi_cmnd *cmd) { struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd); struct scatterlist *sg = scsi_sglist(cmd); - int dir = cmd->sc_data_direction; - int total, i; + int total = 0, i; - if (dir == DMA_NONE) + if (cmd->sc_data_direction == DMA_NONE) return; - spriv->u.num_sg = esp->ops->map_sg(esp, sg, scsi_sg_count(cmd), dir); + 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); + for (i = 0; i < spriv->num_sg; i++) { + sg[i].dma_address = (uintptr_t)sg_virt(&sg[i]); + total += sg_dma_len(&sg[i]); + } + } else { + spriv->num_sg = scsi_dma_map(cmd); + for (i = 0; i < spriv->num_sg; i++) + total += sg_dma_len(&sg[i]); + } spriv->cur_residue = sg_dma_len(sg); spriv->cur_sg = sg; - - total = 0; - for (i = 0; i < spriv->u.num_sg; i++) - total += sg_dma_len(&sg[i]); spriv->tot_residue = total; } @@ -441,13 +450,8 @@ static void esp_advance_dma(struct esp *esp, struct esp_cmd_entry *ent, static void esp_unmap_dma(struct esp *esp, struct scsi_cmnd *cmd) { - struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd); - int dir = cmd->sc_data_direction; - - if (dir == DMA_NONE) - return; - - esp->ops->unmap_sg(esp, scsi_sglist(cmd), spriv->u.num_sg, dir); + if (!(esp->flags & ESP_FLAG_NO_DMA_MAP)) + scsi_dma_unmap(cmd); } static void esp_save_pointers(struct esp *esp, struct esp_cmd_entry *ent) @@ -478,17 +482,6 @@ static void esp_restore_pointers(struct esp *esp, struct esp_cmd_entry *ent) spriv->tot_residue = ent->saved_tot_residue; } -static void esp_check_command_len(struct esp *esp, struct scsi_cmnd *cmd) -{ - if (cmd->cmd_len == 6 || - cmd->cmd_len == 10 || - cmd->cmd_len == 12) { - esp->flags &= ~ESP_FLAG_DOING_SLOWCMD; - } else { - esp->flags |= ESP_FLAG_DOING_SLOWCMD; - } -} - static void esp_write_tgt_config3(struct esp *esp, int tgt) { if (esp->rev > ESP100A) { @@ -624,6 +617,26 @@ static void esp_free_lun_tag(struct esp_cmd_entry *ent, } } +static void esp_map_sense(struct esp *esp, struct esp_cmd_entry *ent) +{ + ent->sense_ptr = ent->cmd->sense_buffer; + if (esp->flags & ESP_FLAG_NO_DMA_MAP) { + ent->sense_dma = (uintptr_t)ent->sense_ptr; + return; + } + + ent->sense_dma = dma_map_single(esp->dev, ent->sense_ptr, + SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); +} + +static void esp_unmap_sense(struct esp *esp, struct esp_cmd_entry *ent) +{ + if (!(esp->flags & ESP_FLAG_NO_DMA_MAP)) + dma_unmap_single(esp->dev, ent->sense_dma, + SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); + ent->sense_ptr = NULL; +} + /* When a contingent allegiance conditon 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 @@ -645,12 +658,7 @@ static void esp_autosense(struct esp *esp, struct esp_cmd_entry *ent) if (!ent->sense_ptr) { esp_log_autosense("Doing auto-sense for tgt[%d] lun[%d]\n", tgt, lun); - - ent->sense_ptr = cmd->sense_buffer; - ent->sense_dma = esp->ops->map_single(esp, - ent->sense_ptr, - SCSI_SENSE_BUFFERSIZE, - DMA_FROM_DEVICE); + esp_map_sense(esp, ent); } ent->saved_sense_ptr = ent->sense_ptr; @@ -717,10 +725,10 @@ static struct esp_cmd_entry *find_and_prep_issuable_command(struct esp *esp) static void esp_maybe_execute_command(struct esp *esp) { struct esp_target_data *tp; - struct esp_lun_data *lp; struct scsi_device *dev; struct scsi_cmnd *cmd; struct esp_cmd_entry *ent; + bool select_and_stop = false; int tgt, lun, i; u32 val, start_cmd; u8 *p; @@ -743,7 +751,6 @@ static void esp_maybe_execute_command(struct esp *esp) tgt = dev->id; lun = dev->lun; tp = &esp->target[tgt]; - lp = dev->hostdata; list_move(&ent->list, &esp->active_cmds); @@ -752,7 +759,8 @@ static void esp_maybe_execute_command(struct esp *esp) esp_map_dma(esp, cmd); esp_save_pointers(esp, ent); - esp_check_command_len(esp, cmd); + if (!(cmd->cmd_len == 6 || cmd->cmd_len == 10 || cmd->cmd_len == 12)) + select_and_stop = true; p = esp->command_block; @@ -793,42 +801,22 @@ static void esp_maybe_execute_command(struct esp *esp) tp->flags &= ~ESP_TGT_CHECK_NEGO; } - /* Process it like a slow command. */ - if (tp->flags & (ESP_TGT_NEGO_WIDE | ESP_TGT_NEGO_SYNC)) - esp->flags |= ESP_FLAG_DOING_SLOWCMD; + /* If there are multiple message bytes, use Select and Stop */ + if (esp->msg_out_len) + select_and_stop = true; } build_identify: - /* If we don't have a lun-data struct yet, we're probing - * so do not disconnect. Also, do not disconnect unless - * we have a tag on this command. - */ - if (lp && (tp->flags & ESP_TGT_DISCONNECT) && ent->tag[0]) - *p++ = IDENTIFY(1, lun); - else - *p++ = IDENTIFY(0, lun); + *p++ = IDENTIFY(tp->flags & ESP_TGT_DISCONNECT, lun); if (ent->tag[0] && esp->rev == ESP100) { /* ESP100 lacks select w/atn3 command, use select * and stop instead. */ - esp->flags |= ESP_FLAG_DOING_SLOWCMD; + select_and_stop = true; } - if (!(esp->flags & ESP_FLAG_DOING_SLOWCMD)) { - start_cmd = ESP_CMD_SELA; - if (ent->tag[0]) { - *p++ = ent->tag[0]; - *p++ = ent->tag[1]; - - start_cmd = ESP_CMD_SA3; - } - - for (i = 0; i < cmd->cmd_len; i++) - *p++ = cmd->cmnd[i]; - - esp->select_state = ESP_SELECT_BASIC; - } else { + if (select_and_stop) { esp->cmd_bytes_left = cmd->cmd_len; esp->cmd_bytes_ptr = &cmd->cmnd[0]; @@ -843,6 +831,19 @@ build_identify: start_cmd = ESP_CMD_SELAS; esp->select_state = ESP_SELECT_MSGOUT; + } else { + start_cmd = ESP_CMD_SELA; + if (ent->tag[0]) { + *p++ = ent->tag[0]; + *p++ = ent->tag[1]; + + start_cmd = ESP_CMD_SA3; + } + + for (i = 0; i < cmd->cmd_len; i++) + *p++ = cmd->cmnd[i]; + + esp->select_state = ESP_SELECT_BASIC; } val = tgt; if (esp->rev == FASHME) @@ -902,9 +903,7 @@ static void esp_cmd_is_done(struct esp *esp, struct esp_cmd_entry *ent, } if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { - esp->ops->unmap_single(esp, ent->sense_dma, - SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); - ent->sense_ptr = NULL; + esp_unmap_sense(esp, ent); /* Restore the message/status bytes to what we actually * saw originally. Also, report that we are providing @@ -965,7 +964,7 @@ static int esp_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_ cmd->scsi_done = done; spriv = ESP_CMD_PRIV(cmd); - spriv->u.dma_addr = ~(dma_addr_t)0x0; + spriv->num_sg = 0; list_add_tail(&ent->list, &esp->queued_cmds); @@ -1252,14 +1251,10 @@ static int esp_finish_select(struct esp *esp) esp_unmap_dma(esp, cmd); esp_free_lun_tag(ent, cmd->device->hostdata); tp->flags &= ~(ESP_TGT_NEGO_SYNC | ESP_TGT_NEGO_WIDE); - esp->flags &= ~ESP_FLAG_DOING_SLOWCMD; esp->cmd_bytes_ptr = NULL; esp->cmd_bytes_left = 0; } else { - esp->ops->unmap_single(esp, ent->sense_dma, - SCSI_SENSE_BUFFERSIZE, - DMA_FROM_DEVICE); - ent->sense_ptr = NULL; + esp_unmap_sense(esp, ent); } /* Now that the state is unwound properly, put back onto @@ -1303,9 +1298,8 @@ static int esp_finish_select(struct esp *esp) esp_flush_fifo(esp); } - /* If we are doing a slow command, negotiation, etc. - * we'll do the right thing as we transition to the - * next phase. + /* 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; @@ -1338,6 +1332,7 @@ static int esp_data_bytes_sent(struct esp *esp, struct esp_cmd_entry *ent, bytes_sent = esp->data_dma_len; bytes_sent -= ecount; + bytes_sent -= esp->send_cmd_residual; /* * The am53c974 has a DMA 'pecularity'. The doc states: @@ -1358,7 +1353,7 @@ static int esp_data_bytes_sent(struct esp *esp, struct esp_cmd_entry *ent, struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd); u8 *ptr; - ptr = scsi_kmap_atomic_sg(p->cur_sg, p->u.num_sg, + ptr = scsi_kmap_atomic_sg(p->cur_sg, p->num_sg, &offset, &count); if (likely(ptr)) { *(ptr + offset) = bval; @@ -2039,11 +2034,8 @@ static void esp_reset_cleanup_one(struct esp *esp, struct esp_cmd_entry *ent) esp_free_lun_tag(ent, cmd->device->hostdata); cmd->result = DID_RESET << 16; - if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { - esp->ops->unmap_single(esp, ent->sense_dma, - SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); - ent->sense_ptr = NULL; - } + if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) + esp_unmap_sense(esp, ent); cmd->scsi_done(cmd); list_del(&ent->list); @@ -2382,7 +2374,7 @@ static const char *esp_chip_names[] = { static struct scsi_transport_template *esp_transport_template; -int scsi_esp_register(struct esp *esp, struct device *dev) +int scsi_esp_register(struct esp *esp) { static int instance; int err; @@ -2402,10 +2394,10 @@ int scsi_esp_register(struct esp *esp, struct device *dev) esp_bootup_reset(esp); - dev_printk(KERN_INFO, dev, "esp%u: regs[%1p:%1p] irq[%u]\n", + dev_printk(KERN_INFO, esp->dev, "esp%u: regs[%1p:%1p] irq[%u]\n", esp->host->unique_id, esp->regs, esp->dma_regs, esp->host->irq); - dev_printk(KERN_INFO, dev, + dev_printk(KERN_INFO, esp->dev, "esp%u: is a %s, %u MHz (ccf=%u), SCSI ID %u\n", esp->host->unique_id, esp_chip_names[esp->rev], esp->cfreq / 1000000, esp->cfact, esp->scsi_id); @@ -2413,7 +2405,7 @@ int scsi_esp_register(struct esp *esp, struct device *dev) /* Let the SCSI bus reset settle. */ ssleep(esp_bus_reset_settle); - err = scsi_add_host(esp->host, dev); + err = scsi_add_host(esp->host, esp->dev); if (err) return err; @@ -2790,3 +2782,131 @@ MODULE_PARM_DESC(esp_debug, module_init(esp_init); module_exit(esp_exit); + +#ifdef CONFIG_SCSI_ESP_PIO +static inline unsigned int esp_wait_for_fifo(struct esp *esp) +{ + int i = 500000; + + do { + unsigned int fbytes = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES; + + if (fbytes) + return fbytes; + + udelay(1); + } while (--i); + + shost_printk(KERN_ERR, esp->host, "FIFO is empty. sreg [%02x]\n", + esp_read8(ESP_STATUS)); + return 0; +} + +static inline int esp_wait_for_intr(struct esp *esp) +{ + int i = 500000; + + do { + esp->sreg = esp_read8(ESP_STATUS); + if (esp->sreg & ESP_STAT_INTR) + return 0; + + udelay(1); + } while (--i); + + shost_printk(KERN_ERR, esp->host, "IRQ timeout. sreg [%02x]\n", + esp->sreg); + return 1; +} + +#define ESP_FIFO_SIZE 16 + +void esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count, + u32 dma_count, int write, u8 cmd) +{ + u8 phase = esp->sreg & ESP_STAT_PMASK; + + cmd &= ~ESP_CMD_DMA; + esp->send_cmd_error = 0; + + if (write) { + u8 *dst = (u8 *)addr; + u8 mask = ~(phase == ESP_MIP ? ESP_INTR_FDONE : ESP_INTR_BSERV); + + scsi_esp_cmd(esp, cmd); + + while (1) { + if (!esp_wait_for_fifo(esp)) + break; + + *dst++ = readb(esp->fifo_reg); + --esp_count; + + if (!esp_count) + break; + + if (esp_wait_for_intr(esp)) { + esp->send_cmd_error = 1; + break; + } + + if ((esp->sreg & ESP_STAT_PMASK) != phase) + break; + + esp->ireg = esp_read8(ESP_INTRPT); + if (esp->ireg & mask) { + esp->send_cmd_error = 1; + break; + } + + if (phase == ESP_MIP) + esp_write8(ESP_CMD_MOK, ESP_CMD); + + esp_write8(ESP_CMD_TI, ESP_CMD); + } + } else { + unsigned int n = ESP_FIFO_SIZE; + u8 *src = (u8 *)addr; + + scsi_esp_cmd(esp, ESP_CMD_FLUSH); + + if (n > esp_count) + n = esp_count; + writesb(esp->fifo_reg, src, n); + src += n; + esp_count -= n; + + scsi_esp_cmd(esp, cmd); + + while (esp_count) { + if (esp_wait_for_intr(esp)) { + esp->send_cmd_error = 1; + break; + } + + if ((esp->sreg & ESP_STAT_PMASK) != phase) + break; + + esp->ireg = esp_read8(ESP_INTRPT); + if (esp->ireg & ~ESP_INTR_BSERV) { + esp->send_cmd_error = 1; + break; + } + + n = ESP_FIFO_SIZE - + (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES); + + if (n > esp_count) + n = esp_count; + writesb(esp->fifo_reg, src, n); + src += n; + esp_count -= n; + + esp_write8(ESP_CMD_TI, ESP_CMD); + } + } + + esp->send_cmd_residual = esp_count; +} +EXPORT_SYMBOL(esp_send_pio_cmd); +#endif |