[SCSI] sym53c8xx: Keep transfer negotiations valid
[firefly-linux-kernel-4.4.55.git] / drivers / scsi / sym53c8xx_2 / sym_hipd.c
index 98df1651404faff46e9241e7a776f4e69f45885f..fe6359d4e1ef996ae5c125d2982f3576aacfd169 100644 (file)
@@ -1433,13 +1433,12 @@ static int sym_prepare_nego(struct sym_hcb *np, struct sym_ccb *cp, u_char *msgp
         * Many devices implement PPR in a buggy way, so only use it if we
         * really want to.
         */
-       if (goal->offset &&
-           (goal->iu || goal->dt || goal->qas || (goal->period < 0xa))) {
+       if (goal->renego == NS_PPR || (goal->offset &&
+           (goal->iu || goal->dt || goal->qas || (goal->period < 0xa)))) {
                nego = NS_PPR;
-       } else if (spi_width(starget) != goal->width) {
+       } else if (goal->renego == NS_WIDE || goal->width) {
                nego = NS_WIDE;
-       } else if (spi_period(starget) != goal->period ||
-                  spi_offset(starget) != goal->offset) {
+       } else if (goal->renego == NS_SYNC || goal->offset) {
                nego = NS_SYNC;
        } else {
                goal->check_nego = 0;
@@ -2049,11 +2048,13 @@ static void sym_setwide(struct sym_hcb *np, int target, u_char wide)
        struct sym_tcb *tp = &np->target[target];
        struct scsi_target *starget = tp->starget;
 
-       if (spi_width(starget) == wide)
-               return;
-
        sym_settrans(np, target, 0, 0, 0, wide, 0, 0);
 
+       if (wide)
+               tp->tgoal.renego = NS_WIDE;
+       else
+               tp->tgoal.renego = 0;
+       tp->tgoal.check_nego = 0;
        tp->tgoal.width = wide;
        spi_offset(starget) = 0;
        spi_period(starget) = 0;
@@ -2080,6 +2081,12 @@ sym_setsync(struct sym_hcb *np, int target,
 
        sym_settrans(np, target, 0, ofs, per, wide, div, fak);
 
+       if (wide)
+               tp->tgoal.renego = NS_WIDE;
+       else if (ofs)
+               tp->tgoal.renego = NS_SYNC;
+       else
+               tp->tgoal.renego = 0;
        spi_period(starget) = per;
        spi_offset(starget) = ofs;
        spi_iu(starget) = spi_dt(starget) = spi_qas(starget) = 0;
@@ -2106,6 +2113,10 @@ sym_setpprot(struct sym_hcb *np, int target, u_char opts, u_char ofs,
 
        sym_settrans(np, target, opts, ofs, per, wide, div, fak);
 
+       if (wide || ofs)
+               tp->tgoal.renego = NS_PPR;
+       else
+               tp->tgoal.renego = 0;
        spi_width(starget) = tp->tgoal.width = wide;
        spi_period(starget) = tp->tgoal.period = per;
        spi_offset(starget) = tp->tgoal.offset = ofs;
@@ -3516,6 +3527,7 @@ static void sym_sir_task_recovery(struct sym_hcb *np, int num)
                        spi_dt(starget) = 0;
                        spi_qas(starget) = 0;
                        tp->tgoal.check_nego = 1;
+                       tp->tgoal.renego = 0;
                }
 
                /*
@@ -5135,9 +5147,14 @@ int sym_queue_scsiio(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb *
        /*
         *  Build a negotiation message if needed.
         *  (nego_status is filled by sym_prepare_nego())
+        *
+        *  Always negotiate on INQUIRY and REQUEST SENSE.
+        *
         */
        cp->nego_status = 0;
-       if (tp->tgoal.check_nego && !tp->nego_cp && lp) {
+       if ((tp->tgoal.check_nego ||
+            cmd->cmnd[0] == INQUIRY || cmd->cmnd[0] == REQUEST_SENSE) &&
+           !tp->nego_cp && lp) {
                msglen += sym_prepare_nego(np, cp, msgptr + msglen);
        }