From: "Adam Kropelin" <[EMAIL PROTECTED]>
Date: Mon, 16 Apr 2007 23:35:56 -0400

> David Miller wrote:
> > From: "Adam Kropelin" <[EMAIL PROTECTED]>
> > Date: Mon, 16 Apr 2007 18:58:39 -0400
> >
> >> Starting smartd: esp: esp0: Aborting command [fffff80030b05280:2a]
> >> esp: esp0: Active command [fffff80030b05280:2a]
> >> esp: esp0: Aborting command [fffff80030b05280:00]
> >> esp: esp0: Queued command [fffff80030b05280:00]
> >> esp: esp0: Aborting command [fffff80030b05280:00]
> >> esp: esp0: Queued command [fffff80030b05280:00]
> >
> > Let's see what the heck smartd is sending to the device.  Please
> > reboot with smartd enabled and post the logs that get output
> > from this patch below applied, thanks.
> 
> Here it is:
> 
> Starting smartd:
 ...

Ok I think I nailed this.

I converted the ESP driver over to using auto-requestsense
when CHECK_CONDITION occurs for a scsi command.

The new ESP driver now passes my dbench+smartd-loop stress
test.

Let me know if you have some trouble with this patch.

Thanks in advance for testing!

diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c
index 2d96fba..fd5548f 100644
--- a/drivers/scsi/esp.c
+++ b/drivers/scsi/esp.c
@@ -47,7 +47,7 @@ static u32 esp_debug;
 #define ESP_DEBUG_DATASTART    0x00000080
 #define ESP_DEBUG_DATADONE     0x00000100
 #define ESP_DEBUG_RECONNECT    0x00000200
-#define ESP_DEBUG_SENSE                0x00000400
+#define ESP_DEBUG_AUTOSENSE    0x00000400
 
 #define esp_log_intr(f, a...) \
 do {   if (esp_debug & ESP_DEBUG_INTR) \
@@ -94,8 +94,8 @@ do {  if (esp_debug & ESP_DEBUG_RECONNECT) \
                printk(f, ## a); \
 } while (0)
 
-#define esp_log_sense(f, a...) \
-do {   if (esp_debug & ESP_DEBUG_SENSE) \
+#define esp_log_autosense(f, a...) \
+do {   if (esp_debug & ESP_DEBUG_AUTOSENSE) \
                printk(f, ## a); \
 } while (0)
 
@@ -537,10 +537,15 @@ static void esp_map_dma(struct esp *esp, struct scsi_cmnd 
*cmd)
        }
 }
 
-static dma_addr_t esp_cur_dma_addr(struct scsi_cmnd *cmd)
+static dma_addr_t esp_cur_dma_addr(struct esp_cmd_entry *ent,
+                                  struct scsi_cmnd *cmd)
 {
        struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd);
 
+       if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+               return ent->sense_dma +
+                       (ent->sense_ptr - cmd->sense_buffer);
+       }
        if (p->mapping_type == MAPPING_TYPE_SINGLE) {
                return p->u.dma_addr +
                        (cmd->request_bufflen -
@@ -553,18 +558,28 @@ static dma_addr_t esp_cur_dma_addr(struct scsi_cmnd *cmd)
        }
 }
 
-static unsigned int esp_cur_dma_len(struct scsi_cmnd *cmd)
+static unsigned int esp_cur_dma_len(struct esp_cmd_entry *ent,
+                                   struct scsi_cmnd *cmd)
 {
        struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd);
 
+       if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+               return SCSI_SENSE_BUFFERSIZE -
+                       (ent->sense_ptr - cmd->sense_buffer);
+       }
        return p->cur_residue;
 }
 
-static void esp_advance_dma(struct esp *esp, struct scsi_cmnd *cmd,
-                           unsigned int len)
+static void esp_advance_dma(struct esp *esp, struct esp_cmd_entry *ent,
+                           struct scsi_cmnd *cmd, unsigned int len)
 {
        struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd);
 
+       if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+               ent->sense_ptr += len;
+               return;
+       }
+
        p->cur_residue -= len;
        p->tot_residue -= len;
        if (p->cur_residue < 0 || p->tot_residue < 0) {
@@ -612,6 +627,10 @@ static void esp_save_pointers(struct esp *esp, struct 
esp_cmd_entry *ent)
        struct scsi_cmnd *cmd = ent->cmd;
        struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd);
 
+       if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+               ent->saved_sense_ptr = ent->sense_ptr;
+               return;
+       }
        ent->saved_cur_residue = spriv->cur_residue;
        ent->saved_cur_sg = spriv->cur_sg;
        ent->saved_tot_residue = spriv->tot_residue;
@@ -622,6 +641,10 @@ static void esp_restore_pointers(struct esp *esp, struct 
esp_cmd_entry *ent)
        struct scsi_cmnd *cmd = ent->cmd;
        struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd);
 
+       if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+               ent->sense_ptr = ent->saved_sense_ptr;
+               return;
+       }
        spriv->cur_residue = ent->saved_cur_residue;
        spriv->cur_sg = ent->saved_cur_sg;
        spriv->tot_residue = ent->saved_tot_residue;
@@ -834,8 +857,7 @@ static int esp_alloc_lun_tag(struct esp_cmd_entry *ent,
                         * the queue and run this untagged command.
                         */
                        lp->hold = 0;
-               } else if (lp->num_tagged &&
-                          ent->cmd->cmnd[0] != REQUEST_SENSE) {
+               } else if (lp->num_tagged) {
                        /* Plug the queue until num_tagged decreases
                         * to zero in esp_free_lun_tag.
                         */
@@ -877,28 +899,67 @@ static void esp_free_lun_tag(struct esp_cmd_entry *ent,
        }
 }
 
-static int force_nontagged(struct scsi_cmnd *cmd)
+/* 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
+ * 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.
+ */
+static void esp_autosense(struct esp *esp, struct esp_cmd_entry *ent)
 {
-       /* Why force INQUIRY non-tagged?  The reason is that I've seen
-        * some seagate drives do some weird things when they were
-        * allowed to disconnect an INQUIRY command.  This particular
-        * disk was configured for 16-bit wide transfers, it would
-        * go to DATA phase, transfer 12 bytes of the INQUIRY response,
-        * spit out an IGNORE_WIDE_RESIDUE message, disconnect, then
-        * reconnect and send the whole INQUIRY response.  These INQUIRY
-        * requests were generated by udev's "scsi_id" command.
-        *
-        * This probably accounts for the BLIST_NOTQ seagate entries in
-        * scsi_devinfo.c, one of which states "Chokes on tagged INQUIRY".
-        *
-        * All of this is just silly and asking for trouble, so just do
-        * INQUIRY commands non-tagged.
-        */
-       if (cmd->cmnd[0] == REQUEST_SENSE ||
-           cmd->cmnd[0] == INQUIRY)
-               return 1;
+       struct scsi_cmnd *cmd = ent->cmd;
+       struct scsi_device *dev = cmd->device;
+       int tgt, lun;
+       u8 *p, val;
 
-       return 0;
+       tgt = dev->id;
+       lun = dev->lun;
+
+
+       if (!ent->sense_ptr) {
+               esp_log_autosense("esp%d: Doing auto-sense for "
+                                 "tgt[%d] lun[%d]\n",
+                                 esp->host->unique_id, tgt, lun);
+
+               ent->sense_ptr = cmd->sense_buffer;
+               ent->sense_dma = sbus_map_single(esp->sbus_dev,
+                                                ent->sense_ptr,
+                                                SCSI_SENSE_BUFFERSIZE,
+                                                DMA_FROM_DEVICE);
+       }
+       ent->saved_sense_ptr = ent->sense_ptr;
+
+       esp->active_cmd = ent;
+
+       p = esp->command_block;
+       esp->msg_out_len = 0;
+
+       *p++ = IDENTIFY(0, lun);
+       *p++ = REQUEST_SENSE;
+       *p++ = ((dev->scsi_level <= SCSI_2) ?
+               (lun << 5) : 0);
+       *p++ = 0;
+       *p++ = 0;
+       *p++ = SCSI_SENSE_BUFFERSIZE;
+       *p++ = 0;
+
+       esp->select_state = ESP_SELECT_BASIC;
+
+       val = tgt;
+       if (esp->rev == FASHME)
+               val |= ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT;
+       esp_write8(val, ESP_BUSID);
+
+       esp_write_tgt_sync(esp, tgt);
+       esp_write_tgt_config3(esp, tgt);
+
+       val = (p - esp->command_block);
+
+       if (esp->rev == FASHME)
+               esp_cmd(esp, ESP_CMD_FLUSH);
+       esp_send_dma_command(esp, esp->command_block_dma,
+                            val, 16, 0, ESP_CMD_DMA | ESP_CMD_SELA);
 }
 
 static struct esp_cmd_entry *find_and_prep_issuable_command(struct esp *esp)
@@ -913,8 +974,13 @@ static struct esp_cmd_entry 
*find_and_prep_issuable_command(struct esp *esp)
                int tgt = dev->id;
                int lun = dev->lun;
 
-               if (force_nontagged(cmd) ||
-                   !scsi_populate_tag_msg(cmd, &ent->tag[0])) {
+               if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+                       ent->tag[0] = 0;
+                       ent->tag[1] = 0;
+                       return ent;
+               }
+
+               if (!scsi_populate_tag_msg(cmd, &ent->tag[0])) {
                        ent->tag[0] = 0;
                        ent->tag[1] = 0;
                }
@@ -949,6 +1015,11 @@ static void esp_maybe_execute_command(struct esp *esp)
        if (!ent)
                return;
 
+       if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+               esp_autosense(esp, ent);
+               return;
+       }
+
        cmd = ent->cmd;
        dev = cmd->device;
        tgt = dev->id;
@@ -1112,23 +1183,32 @@ static void esp_cmd_is_done(struct esp *esp, struct 
esp_cmd_entry *ent,
                ent->eh_done = NULL;
        }
 
-       if (cmd->cmnd[0] == REQUEST_SENSE) {
-               unsigned char *buf;
-               int i;
+       if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+               sbus_unmap_single(esp->sbus_dev, ent->sense_dma,
+                                 SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
+               ent->sense_ptr = NULL;
 
-               if (cmd->use_sg == 0)
-                       buf = cmd->request_buffer;
-               else {
-                       struct scatterlist *sg = cmd->request_buffer;
+               /* Restore the message/status bytes to what we actually
+                * saw originally.  Also, report that we are providing
+                * the sense data.
+                */
+               cmd->result = ((DRIVER_SENSE << 24) |
+                              (DID_OK << 16) |
+                              (COMMAND_COMPLETE << 8) |
+                              (SAM_STAT_CHECK_CONDITION << 0));
 
-                       buf = page_address(sg[0].page) + sg[0].offset;
-               }
+               ent->flags &= ~ESP_CMD_FLAG_AUTOSENSE;
+               if (esp_debug & ESP_DEBUG_AUTOSENSE) {
+                       int i;
 
-               esp_log_sense("ESP: SENSE [ ");
-               for (i = 0; i < 18; i++)
-                       esp_log_sense("%02x ", buf[i]);
-               esp_log_sense("]\n");
+                       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");
+               }
        }
+
        cmd->scsi_done(cmd);
 
        list_del(&ent->list);
@@ -1490,12 +1570,19 @@ static int esp_finish_select(struct esp *esp)
                 * resources (such as DMA mapping & TAG) and reset state (such
                 * as message out and command delivery variables).
                 */
-               esp_unmap_dma(esp, cmd);
-               esp_free_lun_tag(ent, tp->lun[cmd->device->lun]);
-               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;
+               if (!(ent->flags & ESP_CMD_FLAG_AUTOSENSE)) {
+                       esp_unmap_dma(esp, cmd);
+                       esp_free_lun_tag(ent, tp->lun[cmd->device->lun]);
+                       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 {
+                       sbus_unmap_single(esp->sbus_dev, ent->sense_dma,
+                                         SCSI_SENSE_BUFFERSIZE,
+                                         DMA_FROM_DEVICE);
+                       ent->sense_ptr = NULL;
+               }
 
                /* Now that the state is unwound properly, put back onto
                 * the issue queue.  This command is no longer active.
@@ -1947,8 +2034,8 @@ again:
        case ESP_EVENT_DATA_OUT: {
                struct esp_cmd_entry *ent = esp->active_cmd;
                struct scsi_cmnd *cmd = ent->cmd;
-               dma_addr_t dma_addr = esp_cur_dma_addr(cmd);
-               unsigned int dma_len = esp_cur_dma_len(cmd);
+               dma_addr_t dma_addr = esp_cur_dma_addr(ent, cmd);
+               unsigned int dma_len = esp_cur_dma_len(ent, cmd);
 
                if (esp->rev == ESP100)
                        esp_cmd(esp, ESP_CMD_NULL);
@@ -1966,7 +2053,8 @@ again:
                               esp->host->unique_id);
                        printk(KERN_ERR PFX "esp%d: cur adr[%08x] len[%08x]\n",
                               esp->host->unique_id,
-                              esp_cur_dma_addr(cmd), esp_cur_dma_len(cmd));
+                              esp_cur_dma_addr(ent, cmd),
+                              esp_cur_dma_len(ent, cmd));
                        esp_schedule_reset(esp);
                        return 0;
                }
@@ -2020,7 +2108,7 @@ again:
                        return 0;
                }
 
-               esp_advance_dma(esp, cmd, bytes_sent);
+               esp_advance_dma(esp, ent, cmd, bytes_sent);
                esp_event(esp, ESP_EVENT_CHECK_PHASE);
                goto again;
                break;
@@ -2065,10 +2153,17 @@ again:
                                        ent->status, ent->message);
                        if (ent->status == SAM_STAT_TASK_SET_FULL)
                                esp_event_queue_full(esp, ent);
-                       esp_cmd_is_done(esp, ent, cmd,
-                                       compose_result(ent->status,
-                                                      ent->message,
-                                                      DID_OK));
+
+                       if (ent->status == SAM_STAT_CHECK_CONDITION &&
+                           !(ent->flags & ESP_CMD_FLAG_AUTOSENSE)) {
+                               ent->flags |= ESP_CMD_FLAG_AUTOSENSE;
+                               esp_autosense(esp, ent);
+                       } else {
+                               esp_cmd_is_done(esp, ent, cmd,
+                                               compose_result(ent->status,
+                                                              ent->message,
+                                                              DID_OK));
+                       }
                } else if (ent->message == DISCONNECT) {
                        esp_log_disconnect("ESP: Disconnecting tgt[%d] "
                                           "tag[%x:%x]\n",
@@ -2236,6 +2331,13 @@ static void esp_reset_cleanup_one(struct esp *esp, 
struct esp_cmd_entry *ent)
        esp_unmap_dma(esp, cmd);
        esp_free_lun_tag(ent, esp->target[tgt].lun[lun]);
        cmd->result = DID_RESET << 16;
+
+       if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+               sbus_unmap_single(esp->sbus_dev, ent->sense_dma,
+                                 SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
+               ent->sense_ptr = NULL;
+       }
+
        cmd->scsi_done(cmd);
        list_del(&ent->list);
        esp_put_ent(esp, ent);
@@ -3273,7 +3375,7 @@ MODULE_PARM_DESC(esp_debug,
 "      0x00000080      Log data start\n"
 "      0x00000100      Log data done\n"
 "      0x00000200      Log reconnects\n"
-"      0x00000400      Log sense data\n"
+"      0x00000400      Log auto-sense data\n"
 );
 
 module_init(esp_init);
diff --git a/drivers/scsi/esp.h b/drivers/scsi/esp.h
index bd3237d..3d18dfa 100644
--- a/drivers/scsi/esp.h
+++ b/drivers/scsi/esp.h
@@ -275,12 +275,17 @@ struct esp_cmd_entry {
        u8                      flags;
 #define ESP_CMD_FLAG_WRITE     0x01 /* DMA is a write */
 #define ESP_CMD_FLAG_ABORT     0x02 /* being aborted */
+#define ESP_CMD_FLAG_AUTOSENSE 0x04 /* Doing automatic REQUEST_SENSE */
 
        u8                      tag[2];
 
        u8                      status;
        u8                      message;
 
+       unsigned char           *sense_ptr;
+       unsigned char           *saved_sense_ptr;
+       dma_addr_t              sense_dma;
+
        struct completion       *eh_done;
 };
 

-
To unsubscribe from this list: send the line "unsubscribe sparclinux" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to