diff options
author | Narsimhulu Musini <nmusini@cisco.com> | 2016-03-17 03:51:12 -0400 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2016-04-11 16:57:09 -0400 |
commit | 6e0ae74b5ca2826fa6c86a157ed5227c766156b9 (patch) | |
tree | 83fc00686403367a3d6d496609e3eadbe70774df | |
parent | f352a0d5bafa62d1f0b044613ea42483a529f9df (diff) |
snic: Handling control path queue issues
Fix handles control path queue issues such as queue full and sudden
removal of hardware.
Signed-off-by: Narsimhulu Musini <nmusini@cisco.com>
Signed-off-by: Sesidhar Baddela <sebaddel@cisco.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-rw-r--r-- | drivers/scsi/snic/vnic_dev.c | 44 |
1 files changed, 30 insertions, 14 deletions
diff --git a/drivers/scsi/snic/vnic_dev.c b/drivers/scsi/snic/vnic_dev.c index e0b5549bc9fb..dad5fc66effb 100644 --- a/drivers/scsi/snic/vnic_dev.c +++ b/drivers/scsi/snic/vnic_dev.c | |||
@@ -263,12 +263,20 @@ static int _svnic_dev_cmd2(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, | |||
263 | int wait) | 263 | int wait) |
264 | { | 264 | { |
265 | struct devcmd2_controller *dc2c = vdev->devcmd2; | 265 | struct devcmd2_controller *dc2c = vdev->devcmd2; |
266 | struct devcmd2_result *result = dc2c->result + dc2c->next_result; | 266 | struct devcmd2_result *result = NULL; |
267 | unsigned int i; | 267 | unsigned int i; |
268 | int delay; | 268 | int delay; |
269 | int err; | 269 | int err; |
270 | u32 posted; | 270 | u32 posted; |
271 | u32 fetch_idx; | ||
271 | u32 new_posted; | 272 | u32 new_posted; |
273 | u8 color; | ||
274 | |||
275 | fetch_idx = ioread32(&dc2c->wq_ctrl->fetch_index); | ||
276 | if (fetch_idx == 0xFFFFFFFF) { /* check for hardware gone */ | ||
277 | /* Hardware surprise removal: return error */ | ||
278 | return -ENODEV; | ||
279 | } | ||
272 | 280 | ||
273 | posted = ioread32(&dc2c->wq_ctrl->posted_index); | 281 | posted = ioread32(&dc2c->wq_ctrl->posted_index); |
274 | 282 | ||
@@ -278,6 +286,13 @@ static int _svnic_dev_cmd2(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, | |||
278 | } | 286 | } |
279 | 287 | ||
280 | new_posted = (posted + 1) % DEVCMD2_RING_SIZE; | 288 | new_posted = (posted + 1) % DEVCMD2_RING_SIZE; |
289 | if (new_posted == fetch_idx) { | ||
290 | pr_err("%s: wq is full while issuing devcmd2 command %d, fetch index: %u, posted index: %u\n", | ||
291 | pci_name(vdev->pdev), _CMD_N(cmd), fetch_idx, posted); | ||
292 | |||
293 | return -EBUSY; | ||
294 | } | ||
295 | |||
281 | dc2c->cmd_ring[posted].cmd = cmd; | 296 | dc2c->cmd_ring[posted].cmd = cmd; |
282 | dc2c->cmd_ring[posted].flags = 0; | 297 | dc2c->cmd_ring[posted].flags = 0; |
283 | 298 | ||
@@ -299,14 +314,22 @@ static int _svnic_dev_cmd2(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, | |||
299 | if (dc2c->cmd_ring[posted].flags & DEVCMD2_FNORESULT) | 314 | if (dc2c->cmd_ring[posted].flags & DEVCMD2_FNORESULT) |
300 | return 0; | 315 | return 0; |
301 | 316 | ||
317 | result = dc2c->result + dc2c->next_result; | ||
318 | color = dc2c->color; | ||
319 | |||
320 | /* | ||
321 | * Increment next_result, after posting the devcmd, irrespective of | ||
322 | * devcmd result, and it should be done only once. | ||
323 | */ | ||
324 | dc2c->next_result++; | ||
325 | if (dc2c->next_result == dc2c->result_size) { | ||
326 | dc2c->next_result = 0; | ||
327 | dc2c->color = dc2c->color ? 0 : 1; | ||
328 | } | ||
329 | |||
302 | for (delay = 0; delay < wait; delay++) { | 330 | for (delay = 0; delay < wait; delay++) { |
303 | udelay(100); | 331 | udelay(100); |
304 | if (result->color == dc2c->color) { | 332 | if (result->color == color) { |
305 | dc2c->next_result++; | ||
306 | if (dc2c->next_result == dc2c->result_size) { | ||
307 | dc2c->next_result = 0; | ||
308 | dc2c->color = dc2c->color ? 0 : 1; | ||
309 | } | ||
310 | if (result->error) { | 333 | if (result->error) { |
311 | err = (int) result->error; | 334 | err = (int) result->error; |
312 | if (err != ERR_ECMDUNKNOWN || | 335 | if (err != ERR_ECMDUNKNOWN || |
@@ -317,13 +340,6 @@ static int _svnic_dev_cmd2(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, | |||
317 | return err; | 340 | return err; |
318 | } | 341 | } |
319 | if (_CMD_DIR(cmd) & _CMD_DIR_READ) { | 342 | if (_CMD_DIR(cmd) & _CMD_DIR_READ) { |
320 | /* | ||
321 | * Adding the rmb() prevents the compiler | ||
322 | * and/or CPU from reordering the reads which | ||
323 | * would potentially result in reading stale | ||
324 | * values. | ||
325 | */ | ||
326 | rmb(); | ||
327 | for (i = 0; i < VNIC_DEVCMD_NARGS; i++) | 343 | for (i = 0; i < VNIC_DEVCMD_NARGS; i++) |
328 | vdev->args[i] = result->results[i]; | 344 | vdev->args[i] = result->results[i]; |
329 | } | 345 | } |