aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorBrian King <brking@linux.vnet.ibm.com>2007-06-13 18:12:26 -0400
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2007-06-17 16:52:53 -0400
commit3d0e91f7ace12499c4b00088e9a6b1361e1bb0ca (patch)
tree273cd6b7b751b371ef5584475456d253d4f97577 /drivers/scsi
parent6c0a60ec52042ece8bf4904c91ac497188e8d70b (diff)
[SCSI] ibmvscsi: Add eh_host_reset_handler
Adds an eh_host_reset_handler to ibmvscsi which resets the connection to the vscsi server. This patch also adds a timer to internally issues commands to prevent client hangs in the case of a misbehaving server. Tested by modifying the VIOS such that it would occasionally drop one or more request in sequence. Signed-off-by: Brian King <brking@linux.vnet.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c136
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.h1
2 files changed, 107 insertions, 30 deletions
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index c63a26e2fbc7..0a16972b2599 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -509,6 +509,70 @@ static int map_data_for_srp_cmd(struct scsi_cmnd *cmd,
509 return map_single_data(cmd, srp_cmd, dev); 509 return map_single_data(cmd, srp_cmd, dev);
510} 510}
511 511
512/**
513 * purge_requests: Our virtual adapter just shut down. purge any sent requests
514 * @hostdata: the adapter
515 */
516static void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code)
517{
518 struct srp_event_struct *tmp_evt, *pos;
519 unsigned long flags;
520
521 spin_lock_irqsave(hostdata->host->host_lock, flags);
522 list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) {
523 list_del(&tmp_evt->list);
524 del_timer(&tmp_evt->timer);
525 if (tmp_evt->cmnd) {
526 tmp_evt->cmnd->result = (error_code << 16);
527 unmap_cmd_data(&tmp_evt->iu.srp.cmd,
528 tmp_evt,
529 tmp_evt->hostdata->dev);
530 if (tmp_evt->cmnd_done)
531 tmp_evt->cmnd_done(tmp_evt->cmnd);
532 } else if (tmp_evt->done)
533 tmp_evt->done(tmp_evt);
534 free_event_struct(&tmp_evt->hostdata->pool, tmp_evt);
535 }
536 spin_unlock_irqrestore(hostdata->host->host_lock, flags);
537}
538
539/**
540 * ibmvscsi_reset_host - Reset the connection to the server
541 * @hostdata: struct ibmvscsi_host_data to reset
542*/
543static void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata)
544{
545 scsi_block_requests(hostdata->host);
546 atomic_set(&hostdata->request_limit, 0);
547
548 purge_requests(hostdata, DID_ERROR);
549 if ((ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata)) ||
550 (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0)) ||
551 (vio_enable_interrupts(to_vio_dev(hostdata->dev)))) {
552 atomic_set(&hostdata->request_limit, -1);
553 dev_err(hostdata->dev, "error after reset\n");
554 }
555
556 scsi_unblock_requests(hostdata->host);
557}
558
559/**
560 * ibmvscsi_timeout - Internal command timeout handler
561 * @evt_struct: struct srp_event_struct that timed out
562 *
563 * Called when an internally generated command times out
564*/
565static void ibmvscsi_timeout(struct srp_event_struct *evt_struct)
566{
567 struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
568
569 dev_err(hostdata->dev, "Command timed out (%x). Resetting connection\n",
570 evt_struct->iu.srp.cmd.opcode);
571
572 ibmvscsi_reset_host(hostdata);
573}
574
575
512/* ------------------------------------------------------------ 576/* ------------------------------------------------------------
513 * Routines for sending and receiving SRPs 577 * Routines for sending and receiving SRPs
514 */ 578 */
@@ -516,12 +580,14 @@ static int map_data_for_srp_cmd(struct scsi_cmnd *cmd,
516 * ibmvscsi_send_srp_event: - Transforms event to u64 array and calls send_crq() 580 * ibmvscsi_send_srp_event: - Transforms event to u64 array and calls send_crq()
517 * @evt_struct: evt_struct to be sent 581 * @evt_struct: evt_struct to be sent
518 * @hostdata: ibmvscsi_host_data of host 582 * @hostdata: ibmvscsi_host_data of host
583 * @timeout: timeout in seconds - 0 means do not time command
519 * 584 *
520 * Returns the value returned from ibmvscsi_send_crq(). (Zero for success) 585 * Returns the value returned from ibmvscsi_send_crq(). (Zero for success)
521 * Note that this routine assumes that host_lock is held for synchronization 586 * Note that this routine assumes that host_lock is held for synchronization
522*/ 587*/
523static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, 588static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
524 struct ibmvscsi_host_data *hostdata) 589 struct ibmvscsi_host_data *hostdata,
590 unsigned long timeout)
525{ 591{
526 u64 *crq_as_u64 = (u64 *) &evt_struct->crq; 592 u64 *crq_as_u64 = (u64 *) &evt_struct->crq;
527 int request_status; 593 int request_status;
@@ -577,9 +643,18 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
577 */ 643 */
578 list_add_tail(&evt_struct->list, &hostdata->sent); 644 list_add_tail(&evt_struct->list, &hostdata->sent);
579 645
646 init_timer(&evt_struct->timer);
647 if (timeout) {
648 evt_struct->timer.data = (unsigned long) evt_struct;
649 evt_struct->timer.expires = jiffies + (timeout * HZ);
650 evt_struct->timer.function = (void (*)(unsigned long))ibmvscsi_timeout;
651 add_timer(&evt_struct->timer);
652 }
653
580 if ((rc = 654 if ((rc =
581 ibmvscsi_send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) { 655 ibmvscsi_send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) {
582 list_del(&evt_struct->list); 656 list_del(&evt_struct->list);
657 del_timer(&evt_struct->timer);
583 658
584 dev_err(hostdata->dev, "send error %d\n", rc); 659 dev_err(hostdata->dev, "send error %d\n", rc);
585 atomic_inc(&hostdata->request_limit); 660 atomic_inc(&hostdata->request_limit);
@@ -709,7 +784,7 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
709 offsetof(struct srp_indirect_buf, desc_list); 784 offsetof(struct srp_indirect_buf, desc_list);
710 } 785 }
711 786
712 return ibmvscsi_send_srp_event(evt_struct, hostdata); 787 return ibmvscsi_send_srp_event(evt_struct, hostdata, 0);
713} 788}
714 789
715/* ------------------------------------------------------------ 790/* ------------------------------------------------------------
@@ -800,7 +875,7 @@ static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata)
800 return; 875 return;
801 } 876 }
802 877
803 if (ibmvscsi_send_srp_event(evt_struct, hostdata)) { 878 if (ibmvscsi_send_srp_event(evt_struct, hostdata, init_timeout * 2)) {
804 dev_err(hostdata->dev, "couldn't send ADAPTER_INFO_REQ!\n"); 879 dev_err(hostdata->dev, "couldn't send ADAPTER_INFO_REQ!\n");
805 dma_unmap_single(hostdata->dev, 880 dma_unmap_single(hostdata->dev,
806 addr, 881 addr,
@@ -889,7 +964,7 @@ static int send_srp_login(struct ibmvscsi_host_data *hostdata)
889 */ 964 */
890 atomic_set(&hostdata->request_limit, 1); 965 atomic_set(&hostdata->request_limit, 1);
891 966
892 rc = ibmvscsi_send_srp_event(evt_struct, hostdata); 967 rc = ibmvscsi_send_srp_event(evt_struct, hostdata, init_timeout * 2);
893 spin_unlock_irqrestore(hostdata->host->host_lock, flags); 968 spin_unlock_irqrestore(hostdata->host->host_lock, flags);
894 dev_info(hostdata->dev, "sent SRP login\n"); 969 dev_info(hostdata->dev, "sent SRP login\n");
895 return rc; 970 return rc;
@@ -969,7 +1044,7 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
969 1044
970 evt->sync_srp = &srp_rsp; 1045 evt->sync_srp = &srp_rsp;
971 init_completion(&evt->comp); 1046 init_completion(&evt->comp);
972 rsp_rc = ibmvscsi_send_srp_event(evt, hostdata); 1047 rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
973 spin_unlock_irqrestore(hostdata->host->host_lock, flags); 1048 spin_unlock_irqrestore(hostdata->host->host_lock, flags);
974 if (rsp_rc != 0) { 1049 if (rsp_rc != 0) {
975 sdev_printk(KERN_ERR, cmd->device, 1050 sdev_printk(KERN_ERR, cmd->device,
@@ -1077,7 +1152,7 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
1077 1152
1078 evt->sync_srp = &srp_rsp; 1153 evt->sync_srp = &srp_rsp;
1079 init_completion(&evt->comp); 1154 init_completion(&evt->comp);
1080 rsp_rc = ibmvscsi_send_srp_event(evt, hostdata); 1155 rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
1081 spin_unlock_irqrestore(hostdata->host->host_lock, flags); 1156 spin_unlock_irqrestore(hostdata->host->host_lock, flags);
1082 if (rsp_rc != 0) { 1157 if (rsp_rc != 0) {
1083 sdev_printk(KERN_ERR, cmd->device, 1158 sdev_printk(KERN_ERR, cmd->device,
@@ -1133,32 +1208,30 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
1133} 1208}
1134 1209
1135/** 1210/**
1136 * purge_requests: Our virtual adapter just shut down. purge any sent requests 1211 * ibmvscsi_eh_host_reset_handler - Reset the connection to the server
1137 * @hostdata: the adapter 1212 * @cmd: struct scsi_cmnd having problems
1138 */ 1213*/
1139static void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code) 1214static int ibmvscsi_eh_host_reset_handler(struct scsi_cmnd *cmd)
1140{ 1215{
1141 struct srp_event_struct *tmp_evt, *pos; 1216 unsigned long wait_switch = 0;
1142 unsigned long flags; 1217 struct ibmvscsi_host_data *hostdata =
1218 (struct ibmvscsi_host_data *)cmd->device->host->hostdata;
1143 1219
1144 spin_lock_irqsave(hostdata->host->host_lock, flags); 1220 dev_err(hostdata->dev, "Resetting connection due to error recovery\n");
1145 list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) { 1221
1146 list_del(&tmp_evt->list); 1222 ibmvscsi_reset_host(hostdata);
1147 if (tmp_evt->cmnd) { 1223
1148 tmp_evt->cmnd->result = (error_code << 16); 1224 for (wait_switch = jiffies + (init_timeout * HZ);
1149 unmap_cmd_data(&tmp_evt->iu.srp.cmd, 1225 time_before(jiffies, wait_switch) &&
1150 tmp_evt, 1226 atomic_read(&hostdata->request_limit) < 2;) {
1151 tmp_evt->hostdata->dev); 1227
1152 if (tmp_evt->cmnd_done) 1228 msleep(10);
1153 tmp_evt->cmnd_done(tmp_evt->cmnd);
1154 } else {
1155 if (tmp_evt->done) {
1156 tmp_evt->done(tmp_evt);
1157 }
1158 }
1159 free_event_struct(&tmp_evt->hostdata->pool, tmp_evt);
1160 } 1229 }
1161 spin_unlock_irqrestore(hostdata->host->host_lock, flags); 1230
1231 if (atomic_read(&hostdata->request_limit) <= 0)
1232 return FAILED;
1233
1234 return SUCCESS;
1162} 1235}
1163 1236
1164/** 1237/**
@@ -1258,6 +1331,8 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
1258 atomic_add(evt_struct->xfer_iu->srp.rsp.req_lim_delta, 1331 atomic_add(evt_struct->xfer_iu->srp.rsp.req_lim_delta,
1259 &hostdata->request_limit); 1332 &hostdata->request_limit);
1260 1333
1334 del_timer(&evt_struct->timer);
1335
1261 if (evt_struct->done) 1336 if (evt_struct->done)
1262 evt_struct->done(evt_struct); 1337 evt_struct->done(evt_struct);
1263 else 1338 else
@@ -1313,7 +1388,7 @@ static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata,
1313 } 1388 }
1314 1389
1315 init_completion(&evt_struct->comp); 1390 init_completion(&evt_struct->comp);
1316 rc = ibmvscsi_send_srp_event(evt_struct, hostdata); 1391 rc = ibmvscsi_send_srp_event(evt_struct, hostdata, init_timeout * 2);
1317 if (rc == 0) 1392 if (rc == 0)
1318 wait_for_completion(&evt_struct->comp); 1393 wait_for_completion(&evt_struct->comp);
1319 dma_unmap_single(hostdata->dev, addr, length, DMA_BIDIRECTIONAL); 1394 dma_unmap_single(hostdata->dev, addr, length, DMA_BIDIRECTIONAL);
@@ -1504,6 +1579,7 @@ static struct scsi_host_template driver_template = {
1504 .queuecommand = ibmvscsi_queuecommand, 1579 .queuecommand = ibmvscsi_queuecommand,
1505 .eh_abort_handler = ibmvscsi_eh_abort_handler, 1580 .eh_abort_handler = ibmvscsi_eh_abort_handler,
1506 .eh_device_reset_handler = ibmvscsi_eh_device_reset_handler, 1581 .eh_device_reset_handler = ibmvscsi_eh_device_reset_handler,
1582 .eh_host_reset_handler = ibmvscsi_eh_host_reset_handler,
1507 .slave_configure = ibmvscsi_slave_configure, 1583 .slave_configure = ibmvscsi_slave_configure,
1508 .change_queue_depth = ibmvscsi_change_queue_depth, 1584 .change_queue_depth = ibmvscsi_change_queue_depth,
1509 .cmd_per_lun = 16, 1585 .cmd_per_lun = 16,
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h
index 727ca7c95926..b19c2e26c2a5 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.h
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.h
@@ -70,6 +70,7 @@ struct srp_event_struct {
70 union viosrp_iu iu; 70 union viosrp_iu iu;
71 void (*cmnd_done) (struct scsi_cmnd *); 71 void (*cmnd_done) (struct scsi_cmnd *);
72 struct completion comp; 72 struct completion comp;
73 struct timer_list timer;
73 union viosrp_iu *sync_srp; 74 union viosrp_iu *sync_srp;
74 struct srp_direct_buf *ext_list; 75 struct srp_direct_buf *ext_list;
75 dma_addr_t ext_list_token; 76 dma_addr_t ext_list_token;