* @opcode:    opcode for command to look up
  *
  * Uses the REPORT SUPPORTED OPERATION CODES to look up the given
- * opcode. Returns 0 if RSOC fails or if the command opcode is
- * unsupported. Returns 1 if the device claims to support the command.
+ * opcode. Returns -EINVAL if RSOC fails, 0 if the command opcode is
+ * unsupported and 1 if the device claims to support the command.
  */
 int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer,
                       unsigned int len, unsigned char opcode)
        int result;
 
        if (sdev->no_report_opcodes || sdev->scsi_level < SCSI_SPC_3)
-               return 0;
+               return -EINVAL;
 
        memset(cmd, 0, 16);
        cmd[0] = MAINTENANCE_IN;
        if (result && scsi_sense_valid(&sshdr) &&
            sshdr.sense_key == ILLEGAL_REQUEST &&
            (sshdr.asc == 0x20 || sshdr.asc == 0x24) && sshdr.ascq == 0x00)
-               return 0;
+               return -EINVAL;
 
        if ((buffer[1] & 3) == 3) /* Command supported */
                return 1;
 
 
        if (max == 0)
                sdp->no_write_same = 1;
-       else if (max <= SD_MAX_WS16_BLOCKS)
+       else if (max <= SD_MAX_WS16_BLOCKS) {
+               sdp->no_write_same = 0;
                sdkp->max_ws_blocks = max;
+       }
 
        sd_config_write_same(sdkp);
 
 {
        struct request_queue *q = sdkp->disk->queue;
        unsigned int logical_block_size = sdkp->device->sector_size;
-       unsigned int blocks = 0;
 
        if (sdkp->device->no_write_same) {
                sdkp->max_ws_blocks = 0;
         * blocks per I/O unless the device explicitly advertises a
         * bigger limit.
         */
-       if (sdkp->max_ws_blocks == 0)
-               sdkp->max_ws_blocks = SD_MAX_WS10_BLOCKS;
-
-       if (sdkp->ws16 || sdkp->max_ws_blocks > SD_MAX_WS10_BLOCKS)
-               blocks = min_not_zero(sdkp->max_ws_blocks,
-                                     (u32)SD_MAX_WS16_BLOCKS);
-       else
-               blocks = min_not_zero(sdkp->max_ws_blocks,
-                                     (u32)SD_MAX_WS10_BLOCKS);
+       if (sdkp->max_ws_blocks > SD_MAX_WS10_BLOCKS)
+               sdkp->max_ws_blocks = min_not_zero(sdkp->max_ws_blocks,
+                                                  (u32)SD_MAX_WS16_BLOCKS);
+       else if (sdkp->ws16 || sdkp->ws10 || sdkp->device->no_report_opcodes)
+               sdkp->max_ws_blocks = min_not_zero(sdkp->max_ws_blocks,
+                                                  (u32)SD_MAX_WS10_BLOCKS);
+       else {
+               sdkp->device->no_write_same = 1;
+               sdkp->max_ws_blocks = 0;
+       }
 
 out:
-       blk_queue_max_write_same_sectors(q, blocks * (logical_block_size >> 9));
+       blk_queue_max_write_same_sectors(q, sdkp->max_ws_blocks *
+                                        (logical_block_size >> 9));
 }
 
 /**
 
 static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer)
 {
-       if (scsi_report_opcode(sdkp->device, buffer, SD_BUF_SIZE,
-                              WRITE_SAME_16))
+       struct scsi_device *sdev = sdkp->device;
+
+       if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, INQUIRY) < 0) {
+               sdev->no_report_opcodes = 1;
+
+               /* Disable WRITE SAME if REPORT SUPPORTED OPERATION
+                * CODES is unsupported and the device has an ATA
+                * Information VPD page (SAT).
+                */
+               if (!scsi_get_vpd_page(sdev, 0x89, buffer, SD_BUF_SIZE))
+                       sdev->no_write_same = 1;
+       }
+
+       if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, WRITE_SAME_16) == 1)
                sdkp->ws16 = 1;
+
+       if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, WRITE_SAME) == 1)
+               sdkp->ws10 = 1;
 }
 
 static int sd_try_extended_inquiry(struct scsi_device *sdp)