diff options
author | Dave C Boutcher <sleddog@us.ibm.com> | 2006-01-19 14:34:44 -0500 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.(none)> | 2006-01-26 08:10:08 -0500 |
commit | 2b541f8f77fd339e4c5c5cbe8549b52445012704 (patch) | |
tree | 2df9275132ac1bdaadf6695e4d50132b8b955efd /drivers/scsi/ibmvscsi | |
parent | 2dbb04c65561122cc53b22dbea9aa59f9609215b (diff) |
[SCSI] ibmvscsi: handle re-enable firmware message
New versions of the Power5 firmware can send a "re-enable" message to
the virtual scsi adapter. This fix makes us handle the message
correctly. Without it, the driver goes catatonic and the system crashes
unpleasantly.
Signed-off-by: Dave Boutcher <sleddog@us.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/ibmvscsi')
-rw-r--r-- | drivers/scsi/ibmvscsi/ibmvscsi.c | 67 | ||||
-rw-r--r-- | drivers/scsi/ibmvscsi/ibmvscsi.h | 3 | ||||
-rw-r--r-- | drivers/scsi/ibmvscsi/iseries_vscsi.c | 13 | ||||
-rw-r--r-- | drivers/scsi/ibmvscsi/rpa_vscsi.c | 22 |
4 files changed, 74 insertions, 31 deletions
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 822b9fa706f3..eaefeddb2b4a 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c | |||
@@ -87,7 +87,7 @@ static int max_channel = 3; | |||
87 | static int init_timeout = 5; | 87 | static int init_timeout = 5; |
88 | static int max_requests = 50; | 88 | static int max_requests = 50; |
89 | 89 | ||
90 | #define IBMVSCSI_VERSION "1.5.7" | 90 | #define IBMVSCSI_VERSION "1.5.8" |
91 | 91 | ||
92 | MODULE_DESCRIPTION("IBM Virtual SCSI"); | 92 | MODULE_DESCRIPTION("IBM Virtual SCSI"); |
93 | MODULE_AUTHOR("Dave Boutcher"); | 93 | MODULE_AUTHOR("Dave Boutcher"); |
@@ -534,7 +534,6 @@ static int map_data_for_srp_cmd(struct scsi_cmnd *cmd, | |||
534 | static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, | 534 | static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, |
535 | struct ibmvscsi_host_data *hostdata) | 535 | struct ibmvscsi_host_data *hostdata) |
536 | { | 536 | { |
537 | struct scsi_cmnd *cmnd; | ||
538 | u64 *crq_as_u64 = (u64 *) &evt_struct->crq; | 537 | u64 *crq_as_u64 = (u64 *) &evt_struct->crq; |
539 | int rc; | 538 | int rc; |
540 | 539 | ||
@@ -544,19 +543,8 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, | |||
544 | * can handle more requests (can_queue) when we actually can't | 543 | * can handle more requests (can_queue) when we actually can't |
545 | */ | 544 | */ |
546 | if ((evt_struct->crq.format == VIOSRP_SRP_FORMAT) && | 545 | if ((evt_struct->crq.format == VIOSRP_SRP_FORMAT) && |
547 | (atomic_dec_if_positive(&hostdata->request_limit) < 0)) { | 546 | (atomic_dec_if_positive(&hostdata->request_limit) < 0)) |
548 | /* See if the adapter is disabled */ | 547 | goto send_error; |
549 | if (atomic_read(&hostdata->request_limit) < 0) | ||
550 | goto send_error; | ||
551 | |||
552 | printk(KERN_WARNING | ||
553 | "ibmvscsi: Warning, request_limit exceeded\n"); | ||
554 | unmap_cmd_data(&evt_struct->iu.srp.cmd, | ||
555 | evt_struct, | ||
556 | hostdata->dev); | ||
557 | free_event_struct(&hostdata->pool, evt_struct); | ||
558 | return SCSI_MLQUEUE_HOST_BUSY; | ||
559 | } | ||
560 | 548 | ||
561 | /* Copy the IU into the transfer area */ | 549 | /* Copy the IU into the transfer area */ |
562 | *evt_struct->xfer_iu = evt_struct->iu; | 550 | *evt_struct->xfer_iu = evt_struct->iu; |
@@ -572,7 +560,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, | |||
572 | ibmvscsi_send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) { | 560 | ibmvscsi_send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) { |
573 | list_del(&evt_struct->list); | 561 | list_del(&evt_struct->list); |
574 | 562 | ||
575 | printk(KERN_ERR "ibmvscsi: failed to send event struct rc %d\n", | 563 | printk(KERN_ERR "ibmvscsi: send error %d\n", |
576 | rc); | 564 | rc); |
577 | goto send_error; | 565 | goto send_error; |
578 | } | 566 | } |
@@ -582,14 +570,8 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, | |||
582 | send_error: | 570 | send_error: |
583 | unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev); | 571 | unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev); |
584 | 572 | ||
585 | if ((cmnd = evt_struct->cmnd) != NULL) { | ||
586 | cmnd->result = DID_ERROR << 16; | ||
587 | evt_struct->cmnd_done(cmnd); | ||
588 | } else if (evt_struct->done) | ||
589 | evt_struct->done(evt_struct); | ||
590 | |||
591 | free_event_struct(&hostdata->pool, evt_struct); | 573 | free_event_struct(&hostdata->pool, evt_struct); |
592 | return 0; | 574 | return SCSI_MLQUEUE_HOST_BUSY; |
593 | } | 575 | } |
594 | 576 | ||
595 | /** | 577 | /** |
@@ -802,7 +784,8 @@ static void login_rsp(struct srp_event_struct *evt_struct) | |||
802 | case SRP_LOGIN_RSP_TYPE: /* it worked! */ | 784 | case SRP_LOGIN_RSP_TYPE: /* it worked! */ |
803 | break; | 785 | break; |
804 | case SRP_LOGIN_REJ_TYPE: /* refused! */ | 786 | case SRP_LOGIN_REJ_TYPE: /* refused! */ |
805 | printk(KERN_INFO "ibmvscsi: SRP_LOGIN_REQ rejected\n"); | 787 | printk(KERN_INFO "ibmvscsi: SRP_LOGIN_REJ reason %u\n", |
788 | evt_struct->xfer_iu->srp.login_rej.reason); | ||
806 | /* Login failed. */ | 789 | /* Login failed. */ |
807 | atomic_set(&hostdata->request_limit, -1); | 790 | atomic_set(&hostdata->request_limit, -1); |
808 | return; | 791 | return; |
@@ -834,6 +817,9 @@ static void login_rsp(struct srp_event_struct *evt_struct) | |||
834 | return; | 817 | return; |
835 | } | 818 | } |
836 | 819 | ||
820 | /* If we had any pending I/Os, kick them */ | ||
821 | scsi_unblock_requests(hostdata->host); | ||
822 | |||
837 | send_mad_adapter_info(hostdata); | 823 | send_mad_adapter_info(hostdata); |
838 | return; | 824 | return; |
839 | } | 825 | } |
@@ -862,6 +848,7 @@ static int send_srp_login(struct ibmvscsi_host_data *hostdata) | |||
862 | init_timeout * HZ); | 848 | init_timeout * HZ); |
863 | 849 | ||
864 | login = &evt_struct->iu.srp.login_req; | 850 | login = &evt_struct->iu.srp.login_req; |
851 | memset(login, 0x00, sizeof(struct srp_login_req)); | ||
865 | login->type = SRP_LOGIN_REQ_TYPE; | 852 | login->type = SRP_LOGIN_REQ_TYPE; |
866 | login->max_requested_initiator_to_target_iulen = sizeof(union srp_iu); | 853 | login->max_requested_initiator_to_target_iulen = sizeof(union srp_iu); |
867 | login->required_buffer_formats = 0x0006; | 854 | login->required_buffer_formats = 0x0006; |
@@ -1122,7 +1109,7 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd) | |||
1122 | * purge_requests: Our virtual adapter just shut down. purge any sent requests | 1109 | * purge_requests: Our virtual adapter just shut down. purge any sent requests |
1123 | * @hostdata: the adapter | 1110 | * @hostdata: the adapter |
1124 | */ | 1111 | */ |
1125 | static void purge_requests(struct ibmvscsi_host_data *hostdata) | 1112 | static void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code) |
1126 | { | 1113 | { |
1127 | struct srp_event_struct *tmp_evt, *pos; | 1114 | struct srp_event_struct *tmp_evt, *pos; |
1128 | unsigned long flags; | 1115 | unsigned long flags; |
@@ -1131,7 +1118,7 @@ static void purge_requests(struct ibmvscsi_host_data *hostdata) | |||
1131 | list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) { | 1118 | list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) { |
1132 | list_del(&tmp_evt->list); | 1119 | list_del(&tmp_evt->list); |
1133 | if (tmp_evt->cmnd) { | 1120 | if (tmp_evt->cmnd) { |
1134 | tmp_evt->cmnd->result = (DID_ERROR << 16); | 1121 | tmp_evt->cmnd->result = (error_code << 16); |
1135 | unmap_cmd_data(&tmp_evt->iu.srp.cmd, | 1122 | unmap_cmd_data(&tmp_evt->iu.srp.cmd, |
1136 | tmp_evt, | 1123 | tmp_evt, |
1137 | tmp_evt->hostdata->dev); | 1124 | tmp_evt->hostdata->dev); |
@@ -1186,12 +1173,30 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq, | |||
1186 | printk(KERN_ERR "ibmvscsi: unknown crq message type\n"); | 1173 | printk(KERN_ERR "ibmvscsi: unknown crq message type\n"); |
1187 | } | 1174 | } |
1188 | return; | 1175 | return; |
1189 | case 0xFF: /* Hypervisor telling us the connection is closed */ | 1176 | case 0xFF: /* Hypervisor telling us the connection is closed */ |
1190 | printk(KERN_INFO "ibmvscsi: Virtual adapter failed!\n"); | 1177 | scsi_block_requests(hostdata->host); |
1178 | if (crq->format == 0x06) { | ||
1179 | /* We need to re-setup the interpartition connection */ | ||
1180 | printk(KERN_INFO | ||
1181 | "ibmvscsi: Re-enabling adapter!\n"); | ||
1182 | purge_requests(hostdata, DID_REQUEUE); | ||
1183 | if (ibmvscsi_reenable_crq_queue(&hostdata->queue, | ||
1184 | hostdata) == 0) | ||
1185 | if (ibmvscsi_send_crq(hostdata, | ||
1186 | 0xC001000000000000LL, 0)) | ||
1187 | printk(KERN_ERR | ||
1188 | "ibmvscsi: transmit error after" | ||
1189 | " enable\n"); | ||
1190 | } else { | ||
1191 | printk(KERN_INFO | ||
1192 | "ibmvscsi: Virtual adapter failed rc %d!\n", | ||
1193 | crq->format); | ||
1191 | 1194 | ||
1192 | atomic_set(&hostdata->request_limit, -1); | 1195 | atomic_set(&hostdata->request_limit, -1); |
1193 | purge_requests(hostdata); | 1196 | purge_requests(hostdata, DID_ERROR); |
1194 | ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata); | 1197 | ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata); |
1198 | } | ||
1199 | scsi_unblock_requests(hostdata->host); | ||
1195 | return; | 1200 | return; |
1196 | case 0x80: /* real payload */ | 1201 | case 0x80: /* real payload */ |
1197 | break; | 1202 | break; |
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h index 5b0edd1f1921..4550d71e4744 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.h +++ b/drivers/scsi/ibmvscsi/ibmvscsi.h | |||
@@ -103,6 +103,9 @@ void ibmvscsi_release_crq_queue(struct crq_queue *queue, | |||
103 | int ibmvscsi_reset_crq_queue(struct crq_queue *queue, | 103 | int ibmvscsi_reset_crq_queue(struct crq_queue *queue, |
104 | struct ibmvscsi_host_data *hostdata); | 104 | struct ibmvscsi_host_data *hostdata); |
105 | 105 | ||
106 | int ibmvscsi_reenable_crq_queue(struct crq_queue *queue, | ||
107 | struct ibmvscsi_host_data *hostdata); | ||
108 | |||
106 | void ibmvscsi_handle_crq(struct viosrp_crq *crq, | 109 | void ibmvscsi_handle_crq(struct viosrp_crq *crq, |
107 | struct ibmvscsi_host_data *hostdata); | 110 | struct ibmvscsi_host_data *hostdata); |
108 | int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, | 111 | int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, |
diff --git a/drivers/scsi/ibmvscsi/iseries_vscsi.c b/drivers/scsi/ibmvscsi/iseries_vscsi.c index ce15d9e39621..7eed0b098171 100644 --- a/drivers/scsi/ibmvscsi/iseries_vscsi.c +++ b/drivers/scsi/ibmvscsi/iseries_vscsi.c | |||
@@ -124,6 +124,19 @@ int ibmvscsi_reset_crq_queue(struct crq_queue *queue, | |||
124 | } | 124 | } |
125 | 125 | ||
126 | /** | 126 | /** |
127 | * reenable_crq_queue: - reenables a crq after a failure | ||
128 | * @queue: crq_queue to initialize and register | ||
129 | * @hostdata: ibmvscsi_host_data of host | ||
130 | * | ||
131 | * no-op for iSeries | ||
132 | */ | ||
133 | int ibmvscsi_reenable_crq_queue(struct crq_queue *queue, | ||
134 | struct ibmvscsi_host_data *hostdata) | ||
135 | { | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | /** | ||
127 | * ibmvscsi_send_crq: - Send a CRQ | 140 | * ibmvscsi_send_crq: - Send a CRQ |
128 | * @hostdata: the adapter | 141 | * @hostdata: the adapter |
129 | * @word1: the first 64 bits of the data | 142 | * @word1: the first 64 bits of the data |
diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c index 75db2f5c545e..f47dd87c05e7 100644 --- a/drivers/scsi/ibmvscsi/rpa_vscsi.c +++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c | |||
@@ -281,6 +281,28 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue, | |||
281 | } | 281 | } |
282 | 282 | ||
283 | /** | 283 | /** |
284 | * reenable_crq_queue: - reenables a crq after | ||
285 | * @queue: crq_queue to initialize and register | ||
286 | * @hostdata: ibmvscsi_host_data of host | ||
287 | * | ||
288 | */ | ||
289 | int ibmvscsi_reenable_crq_queue(struct crq_queue *queue, | ||
290 | struct ibmvscsi_host_data *hostdata) | ||
291 | { | ||
292 | int rc; | ||
293 | struct vio_dev *vdev = to_vio_dev(hostdata->dev); | ||
294 | |||
295 | /* Re-enable the CRQ */ | ||
296 | do { | ||
297 | rc = plpar_hcall_norets(H_ENABLE_CRQ, vdev->unit_address); | ||
298 | } while ((rc == H_InProgress) || (rc == H_Busy) || (H_isLongBusy(rc))); | ||
299 | |||
300 | if (rc) | ||
301 | printk(KERN_ERR "ibmvscsi: Error %d enabling adapter\n", rc); | ||
302 | return rc; | ||
303 | } | ||
304 | |||
305 | /** | ||
284 | * reset_crq_queue: - resets a crq after a failure | 306 | * reset_crq_queue: - resets a crq after a failure |
285 | * @queue: crq_queue to initialize and register | 307 | * @queue: crq_queue to initialize and register |
286 | * @hostdata: ibmvscsi_host_data of host | 308 | * @hostdata: ibmvscsi_host_data of host |