mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-24 01:41:39 +00:00
[SCSI] sym53c8xx: Keep transfer negotiations valid
(The patch updated based on testing and comments from Tony Battersby.) Change the sym53c8xx_2 driver negotiation logic so that the driver will tolerate better device removals. Negotiation message(s) will be sent with every INQUIRY and REQUEST SENSE command, and whenever there is a change in goals or when the device reports check condition. The patch was made specifically to address the case where you hotswap the disk using remove-single-device/add-single-device commands through /proc/scsi/scsi. Without the patch the driver keeps using old transfer parameters even though the target is reset and reports check condition, so the data transfer of the very first INQUIRY will fail. Signed-off-by: Aaro Koskinen <Aaro.Koskinen@nokia.com> Tested-by: Tony Battersby <tonyb@cybernetics.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
This commit is contained in:
parent
5ef074161b
commit
49799fee82
2 changed files with 27 additions and 9 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -354,6 +354,7 @@ struct sym_trans {
|
|||
unsigned int dt:1;
|
||||
unsigned int qas:1;
|
||||
unsigned int check_nego:1;
|
||||
unsigned int renego:2;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue