static int  sd_probe(struct device *);
 static int  sd_remove(struct device *);
 static void sd_shutdown(struct device *);
-static int sd_suspend(struct device *);
+static int sd_suspend_system(struct device *);
+static int sd_suspend_runtime(struct device *);
 static int sd_resume(struct device *);
 static void sd_rescan(struct device *);
 static int sd_done(struct scsi_cmnd *);
 };
 
 static const struct dev_pm_ops sd_pm_ops = {
-       .suspend                = sd_suspend,
+       .suspend                = sd_suspend_system,
        .resume                 = sd_resume,
-       .poweroff               = sd_suspend,
+       .poweroff               = sd_suspend_system,
        .restore                = sd_resume,
-       .runtime_suspend        = sd_suspend,
+       .runtime_suspend        = sd_suspend_runtime,
        .runtime_resume         = sd_resume,
 };
 
        if (!scsi_device_online(sdp))
                return -ENODEV;
 
-
        for (retries = 3; retries > 0; --retries) {
                unsigned char cmd[10] = { 0 };
 
 
        if (res) {
                sd_print_result(sdkp, res);
+
                if (driver_byte(res) & DRIVER_SENSE)
                        sd_print_sense_hdr(sdkp, &sshdr);
+               /* we need to evaluate the error return  */
+               if (scsi_sense_valid(&sshdr) &&
+                       /* 0x3a is medium not present */
+                       sshdr.asc == 0x3a)
+                               /* this is no error here */
+                               return 0;
+
+               switch (host_byte(res)) {
+               /* ignore errors due to racing a disconnection */
+               case DID_BAD_TARGET:
+               case DID_NO_CONNECT:
+                       return 0;
+               /* signal the upper layer it might try again */
+               case DID_BUS_BUSY:
+               case DID_IMM_RETRY:
+               case DID_REQUEUE:
+               case DID_SOFT_ERROR:
+                       return -EBUSY;
+               default:
+                       return -EIO;
+               }
        }
-
-       if (res)
-               return -EIO;
        return 0;
 }
 
                sd_print_result(sdkp, res);
                if (driver_byte(res) & DRIVER_SENSE)
                        sd_print_sense_hdr(sdkp, &sshdr);
+               if (scsi_sense_valid(&sshdr) &&
+                       /* 0x3a is medium not present */
+                       sshdr.asc == 0x3a)
+                       res = 0;
        }
 
-       return res;
+       /* SCSI error codes must not go to the generic layer */
+       if (res)
+               return -EIO;
+
+       return 0;
 }
 
 /*
        if (pm_runtime_suspended(dev))
                goto exit;
 
-       if (sdkp->WCE) {
+       if (sdkp->WCE && sdkp->media_present) {
                sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n");
                sd_sync_cache(sdkp);
        }
        scsi_disk_put(sdkp);
 }
 
-static int sd_suspend(struct device *dev)
+static int sd_suspend_common(struct device *dev, bool ignore_stop_errors)
 {
        struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
        int ret = 0;
        if (!sdkp)
                return 0;       /* this can happen */
 
-       if (sdkp->WCE) {
+       if (sdkp->WCE && sdkp->media_present) {
                sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n");
                ret = sd_sync_cache(sdkp);
-               if (ret)
+               if (ret) {
+                       /* ignore OFFLINE device */
+                       if (ret == -ENODEV)
+                               ret = 0;
                        goto done;
+               }
        }
 
        if (sdkp->device->manage_start_stop) {
                sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n");
+               /* an error is not worth aborting a system sleep */
                ret = sd_start_stop_device(sdkp, 0);
+               if (ignore_stop_errors)
+                       ret = 0;
        }
 
 done:
        return ret;
 }
 
+static int sd_suspend_system(struct device *dev)
+{
+       return sd_suspend_common(dev, true);
+}
+
+static int sd_suspend_runtime(struct device *dev)
+{
+       return sd_suspend_common(dev, false);
+}
+
 static int sd_resume(struct device *dev)
 {
        struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);