Don't confuse SCSI command status and transfer error code.
authormikeb <mikeb@openbsd.org>
Wed, 21 Jun 2017 18:18:08 +0000 (18:18 +0000)
committermikeb <mikeb@openbsd.org>
Wed, 21 Jun 2017 18:18:08 +0000 (18:18 +0000)
While here, make SCSI command completion routine more robust.

sys/dev/pv/hvs.c

index a0f08c8..5acac16 100644 (file)
@@ -614,31 +614,41 @@ hvs_scsi_cmd_done(struct hvs_ccb *ccb)
        xs = ccb->ccb_xfer;
        srb = &cmd->io.cmd_srb;
 
-       if (srb->srb_datalen > xs->datalen)
-               printf("%s: transfer length %u too large: %u\n",
-                   sc->sc_dev.dv_xname, srb->srb_datalen, xs->datalen);
-       else if (srb->srb_datalen)
-               xs->resid = xs->datalen - srb->srb_datalen;
-
-       if ((srb->srb_scsistatus & 0xff) == SCSI_CHECK &&
-           srb->srb_iostatus & SRB_STATUS_AUTOSENSE_VALID)
-               memcpy(&xs->sense, srb->srb_data, MIN(sizeof(xs->sense),
-                   srb->srb_senselen));
-
-       error = srb->srb_scsistatus & 0xff;
-
-       if (srb->srb_scsistatus != SCSI_OK) {
-               KERNEL_LOCK();
-               hvs_scsi_done(xs, error);
-               KERNEL_UNLOCK();
-               return;
+       xs->status = srb->srb_scsistatus & 0xff;
+
+       switch (xs->status) {
+       case SCSI_OK:
+               if ((srb->srb_iostatus & ~(SRB_STATUS_AUTOSENSE_VALID |
+                   SRB_STATUS_QUEUE_FROZEN)) != SRB_STATUS_SUCCESS)
+                       error = XS_SELTIMEOUT;
+               else
+                       error = XS_NOERROR;
+               break;
+       case SCSI_BUSY:
+       case SCSI_QUEUE_FULL:
+               printf("%s: status %#x iostatus %#x (busy)\n",
+                   sc->sc_dev.dv_xname, srb->srb_scsistatus,
+                   srb->srb_iostatus);
+               xs->error = XS_BUSY;
+               break;
+       case SCSI_CHECK:
+               if (srb->srb_iostatus & SRB_STATUS_AUTOSENSE_VALID) {
+                       memcpy(&xs->sense, srb->srb_data,
+                           MIN(sizeof(xs->sense), srb->srb_senselen));
+                       error = XS_SENSE;
+                       break;
+               }
+               /* FALLTHROUGH */
+       default:
+               error = XS_DRIVER_STUFFUP;
        }
 
-       if ((srb->srb_iostatus & ~(SRB_STATUS_AUTOSENSE_VALID |
-           SRB_STATUS_QUEUE_FROZEN)) != SRB_STATUS_SUCCESS)
-               error = XS_SELTIMEOUT;
-       else if (xs->cmd->opcode == INQUIRY)
-               fixup_inquiry(xs, srb);
+       if (error == XS_NOERROR) {
+               if (xs->cmd->opcode == INQUIRY)
+                       fixup_inquiry(xs, srb);
+               else if (srb->srb_direction != SRB_DATA_NONE)
+                       xs->resid = xs->datalen - srb->srb_datalen;
+       }
 
        KERNEL_LOCK();
        hvs_scsi_done(xs, error);