Commit 279afdfe78a020b4b1a68bffd0009b961b12982e
Committed by
James Bottomley
1 parent
f8813d260e
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
[SCSI] Generate uevents on certain unit attention codes
Generate a uevent when the following Unit Attention ASC/ASCQ codes are received: 2A/01 MODE PARAMETERS CHANGED 2A/09 CAPACITY DATA HAS CHANGED 38/07 THIN PROVISIONING SOFT THRESHOLD REACHED 3F/03 INQUIRY DATA HAS CHANGED 3F/0E REPORTED LUNS DATA HAS CHANGED Log kernel messages when the following Unit Attention ASC/ASCQ codes are received that are not as specific as those above: 2A/xx PARAMETERS CHANGED 3F/xx TARGET OPERATING CONDITIONS HAVE CHANGED Added logic to set expecting_lun_change for other LUNs on the target after REPORTED LUNS DATA HAS CHANGED is received, so that duplicate uevents are not generated, and clear expecting_lun_change when a REPORT LUNS command completes, in accordance with the SPC-3 specification regarding reporting of the 3F 0E ASC/ASCQ UA. [jejb: remove SPC3 test in scsi_report_lun_change and some docbook fixes and unused variable fix, both reported by Fengguang Wu] Signed-off-by: Ewan D. Milne <emilne@redhat.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Showing 4 changed files with 127 additions and 22 deletions Side-by-side Diff
drivers/scsi/scsi_error.c
... | ... | @@ -223,7 +223,75 @@ |
223 | 223 | } |
224 | 224 | #endif |
225 | 225 | |
226 | + /** | |
227 | + * scsi_report_lun_change - Set flag on all *other* devices on the same target | |
228 | + * to indicate that a UNIT ATTENTION is expected. | |
229 | + * @sdev: Device reporting the UNIT ATTENTION | |
230 | + */ | |
231 | +static void scsi_report_lun_change(struct scsi_device *sdev) | |
232 | +{ | |
233 | + sdev->sdev_target->expecting_lun_change = 1; | |
234 | +} | |
235 | + | |
226 | 236 | /** |
237 | + * scsi_report_sense - Examine scsi sense information and log messages for | |
238 | + * certain conditions, also issue uevents for some of them. | |
239 | + * @sdev: Device reporting the sense code | |
240 | + * @sshdr: sshdr to be examined | |
241 | + */ | |
242 | +static void scsi_report_sense(struct scsi_device *sdev, | |
243 | + struct scsi_sense_hdr *sshdr) | |
244 | +{ | |
245 | + enum scsi_device_event evt_type = SDEV_EVT_MAXBITS; /* i.e. none */ | |
246 | + | |
247 | + if (sshdr->sense_key == UNIT_ATTENTION) { | |
248 | + if (sshdr->asc == 0x3f && sshdr->ascq == 0x03) { | |
249 | + evt_type = SDEV_EVT_INQUIRY_CHANGE_REPORTED; | |
250 | + sdev_printk(KERN_WARNING, sdev, | |
251 | + "Inquiry data has changed"); | |
252 | + } else if (sshdr->asc == 0x3f && sshdr->ascq == 0x0e) { | |
253 | + evt_type = SDEV_EVT_LUN_CHANGE_REPORTED; | |
254 | + scsi_report_lun_change(sdev); | |
255 | + sdev_printk(KERN_WARNING, sdev, | |
256 | + "Warning! Received an indication that the " | |
257 | + "LUN assignments on this target have " | |
258 | + "changed. The Linux SCSI layer does not " | |
259 | + "automatically remap LUN assignments.\n"); | |
260 | + } else if (sshdr->asc == 0x3f) | |
261 | + sdev_printk(KERN_WARNING, sdev, | |
262 | + "Warning! Received an indication that the " | |
263 | + "operating parameters on this target have " | |
264 | + "changed. The Linux SCSI layer does not " | |
265 | + "automatically adjust these parameters.\n"); | |
266 | + | |
267 | + if (sshdr->asc == 0x38 && sshdr->ascq == 0x07) { | |
268 | + evt_type = SDEV_EVT_SOFT_THRESHOLD_REACHED_REPORTED; | |
269 | + sdev_printk(KERN_WARNING, sdev, | |
270 | + "Warning! Received an indication that the " | |
271 | + "LUN reached a thin provisioning soft " | |
272 | + "threshold.\n"); | |
273 | + } | |
274 | + | |
275 | + if (sshdr->asc == 0x2a && sshdr->ascq == 0x01) { | |
276 | + evt_type = SDEV_EVT_MODE_PARAMETER_CHANGE_REPORTED; | |
277 | + sdev_printk(KERN_WARNING, sdev, | |
278 | + "Mode parameters changed"); | |
279 | + } else if (sshdr->asc == 0x2a && sshdr->ascq == 0x09) { | |
280 | + evt_type = SDEV_EVT_CAPACITY_CHANGE_REPORTED; | |
281 | + sdev_printk(KERN_WARNING, sdev, | |
282 | + "Capacity data has changed"); | |
283 | + } else if (sshdr->asc == 0x2a) | |
284 | + sdev_printk(KERN_WARNING, sdev, | |
285 | + "Parameters changed"); | |
286 | + } | |
287 | + | |
288 | + if (evt_type != SDEV_EVT_MAXBITS) { | |
289 | + set_bit(evt_type, sdev->pending_events); | |
290 | + schedule_work(&sdev->event_work); | |
291 | + } | |
292 | +} | |
293 | + | |
294 | +/** | |
227 | 295 | * scsi_check_sense - Examine scsi cmd sense |
228 | 296 | * @scmd: Cmd to have sense checked. |
229 | 297 | * |
... | ... | @@ -250,6 +318,8 @@ |
250 | 318 | */ |
251 | 319 | return SUCCESS; |
252 | 320 | |
321 | + scsi_report_sense(sdev, &sshdr); | |
322 | + | |
253 | 323 | if (scsi_sense_is_deferred(&sshdr)) |
254 | 324 | return NEEDS_RETRY; |
255 | 325 | |
... | ... | @@ -315,6 +385,14 @@ |
315 | 385 | } |
316 | 386 | } |
317 | 387 | /* |
388 | + * we might also expect a cc/ua if another LUN on the target | |
389 | + * reported a UA with an ASC/ASCQ of 3F 0E - | |
390 | + * REPORTED LUNS DATA HAS CHANGED. | |
391 | + */ | |
392 | + if (scmd->device->sdev_target->expecting_lun_change && | |
393 | + sshdr.asc == 0x3f && sshdr.ascq == 0x0e) | |
394 | + return NEEDS_RETRY; | |
395 | + /* | |
318 | 396 | * if the device is in the process of becoming ready, we |
319 | 397 | * should retry. |
320 | 398 | */ |
... | ... | @@ -327,26 +405,6 @@ |
327 | 405 | if (scmd->device->allow_restart && |
328 | 406 | (sshdr.asc == 0x04) && (sshdr.ascq == 0x02)) |
329 | 407 | return FAILED; |
330 | - | |
331 | - if (sshdr.asc == 0x3f && sshdr.ascq == 0x0e) | |
332 | - scmd_printk(KERN_WARNING, scmd, | |
333 | - "Warning! Received an indication that the " | |
334 | - "LUN assignments on this target have " | |
335 | - "changed. The Linux SCSI layer does not " | |
336 | - "automatically remap LUN assignments.\n"); | |
337 | - else if (sshdr.asc == 0x3f) | |
338 | - scmd_printk(KERN_WARNING, scmd, | |
339 | - "Warning! Received an indication that the " | |
340 | - "operating parameters on this target have " | |
341 | - "changed. The Linux SCSI layer does not " | |
342 | - "automatically adjust these parameters.\n"); | |
343 | - | |
344 | - if (sshdr.asc == 0x38 && sshdr.ascq == 0x07) | |
345 | - scmd_printk(KERN_WARNING, scmd, | |
346 | - "Warning! Received an indication that the " | |
347 | - "LUN reached a thin provisioning soft " | |
348 | - "threshold.\n"); | |
349 | - | |
350 | 408 | /* |
351 | 409 | * Pass the UA upwards for a determination in the completion |
352 | 410 | * functions. |
... | ... | @@ -1574,6 +1632,8 @@ |
1574 | 1632 | */ |
1575 | 1633 | return ADD_TO_MLQUEUE; |
1576 | 1634 | case GOOD: |
1635 | + if (scmd->cmnd[0] == REPORT_LUNS) | |
1636 | + scmd->device->sdev_target->expecting_lun_change = 0; | |
1577 | 1637 | scsi_handle_queue_ramp_up(scmd->device); |
1578 | 1638 | case COMMAND_TERMINATED: |
1579 | 1639 | return SUCCESS; |
drivers/scsi/scsi_lib.c
... | ... | @@ -2253,7 +2253,21 @@ |
2253 | 2253 | case SDEV_EVT_MEDIA_CHANGE: |
2254 | 2254 | envp[idx++] = "SDEV_MEDIA_CHANGE=1"; |
2255 | 2255 | break; |
2256 | - | |
2256 | + case SDEV_EVT_INQUIRY_CHANGE_REPORTED: | |
2257 | + envp[idx++] = "SDEV_UA=INQUIRY_DATA_HAS_CHANGED"; | |
2258 | + break; | |
2259 | + case SDEV_EVT_CAPACITY_CHANGE_REPORTED: | |
2260 | + envp[idx++] = "SDEV_UA=CAPACITY_DATA_HAS_CHANGED"; | |
2261 | + break; | |
2262 | + case SDEV_EVT_SOFT_THRESHOLD_REACHED_REPORTED: | |
2263 | + envp[idx++] = "SDEV_UA=THIN_PROVISIONING_SOFT_THRESHOLD_REACHED"; | |
2264 | + break; | |
2265 | + case SDEV_EVT_MODE_PARAMETER_CHANGE_REPORTED: | |
2266 | + envp[idx++] = "SDEV_UA=MODE_PARAMETERS_CHANGED"; | |
2267 | + break; | |
2268 | + case SDEV_EVT_LUN_CHANGE_REPORTED: | |
2269 | + envp[idx++] = "SDEV_UA=REPORTED_LUNS_DATA_HAS_CHANGED"; | |
2270 | + break; | |
2257 | 2271 | default: |
2258 | 2272 | /* do nothing */ |
2259 | 2273 | break; |
2260 | 2274 | |
... | ... | @@ -2274,10 +2288,15 @@ |
2274 | 2288 | void scsi_evt_thread(struct work_struct *work) |
2275 | 2289 | { |
2276 | 2290 | struct scsi_device *sdev; |
2291 | + enum scsi_device_event evt_type; | |
2277 | 2292 | LIST_HEAD(event_list); |
2278 | 2293 | |
2279 | 2294 | sdev = container_of(work, struct scsi_device, event_work); |
2280 | 2295 | |
2296 | + for (evt_type = SDEV_EVT_FIRST; evt_type <= SDEV_EVT_LAST; evt_type++) | |
2297 | + if (test_and_clear_bit(evt_type, sdev->pending_events)) | |
2298 | + sdev_evt_send_simple(sdev, evt_type, GFP_KERNEL); | |
2299 | + | |
2281 | 2300 | while (1) { |
2282 | 2301 | struct scsi_event *evt; |
2283 | 2302 | struct list_head *this, *tmp; |
... | ... | @@ -2347,6 +2366,11 @@ |
2347 | 2366 | /* evt_type-specific initialization, if any */ |
2348 | 2367 | switch (evt_type) { |
2349 | 2368 | case SDEV_EVT_MEDIA_CHANGE: |
2369 | + case SDEV_EVT_INQUIRY_CHANGE_REPORTED: | |
2370 | + case SDEV_EVT_CAPACITY_CHANGE_REPORTED: | |
2371 | + case SDEV_EVT_SOFT_THRESHOLD_REACHED_REPORTED: | |
2372 | + case SDEV_EVT_MODE_PARAMETER_CHANGE_REPORTED: | |
2373 | + case SDEV_EVT_LUN_CHANGE_REPORTED: | |
2350 | 2374 | default: |
2351 | 2375 | /* do nothing */ |
2352 | 2376 | break; |
drivers/scsi/scsi_sysfs.c
... | ... | @@ -739,6 +739,11 @@ |
739 | 739 | #define REF_EVT(name) &dev_attr_evt_##name.attr |
740 | 740 | |
741 | 741 | DECLARE_EVT(media_change, MEDIA_CHANGE) |
742 | +DECLARE_EVT(inquiry_change_reported, INQUIRY_CHANGE_REPORTED) | |
743 | +DECLARE_EVT(capacity_change_reported, CAPACITY_CHANGE_REPORTED) | |
744 | +DECLARE_EVT(soft_threshold_reached, SOFT_THRESHOLD_REACHED_REPORTED) | |
745 | +DECLARE_EVT(mode_parameter_change_reported, MODE_PARAMETER_CHANGE_REPORTED) | |
746 | +DECLARE_EVT(lun_change_reported, LUN_CHANGE_REPORTED) | |
742 | 747 | |
743 | 748 | /* Default template for device attributes. May NOT be modified */ |
744 | 749 | static struct attribute *scsi_sdev_attrs[] = { |
... | ... | @@ -759,6 +764,11 @@ |
759 | 764 | &dev_attr_ioerr_cnt.attr, |
760 | 765 | &dev_attr_modalias.attr, |
761 | 766 | REF_EVT(media_change), |
767 | + REF_EVT(inquiry_change_reported), | |
768 | + REF_EVT(capacity_change_reported), | |
769 | + REF_EVT(soft_threshold_reached), | |
770 | + REF_EVT(mode_parameter_change_reported), | |
771 | + REF_EVT(lun_change_reported), | |
762 | 772 | NULL |
763 | 773 | }; |
764 | 774 |
include/scsi/scsi_device.h
... | ... | @@ -52,8 +52,15 @@ |
52 | 52 | |
53 | 53 | enum scsi_device_event { |
54 | 54 | SDEV_EVT_MEDIA_CHANGE = 1, /* media has changed */ |
55 | + SDEV_EVT_INQUIRY_CHANGE_REPORTED, /* 3F 03 UA reported */ | |
56 | + SDEV_EVT_CAPACITY_CHANGE_REPORTED, /* 2A 09 UA reported */ | |
57 | + SDEV_EVT_SOFT_THRESHOLD_REACHED_REPORTED, /* 38 07 UA reported */ | |
58 | + SDEV_EVT_MODE_PARAMETER_CHANGE_REPORTED, /* 2A 01 UA reported */ | |
59 | + SDEV_EVT_LUN_CHANGE_REPORTED, /* 3F 0E UA reported */ | |
55 | 60 | |
56 | - SDEV_EVT_LAST = SDEV_EVT_MEDIA_CHANGE, | |
61 | + SDEV_EVT_FIRST = SDEV_EVT_MEDIA_CHANGE, | |
62 | + SDEV_EVT_LAST = SDEV_EVT_LUN_CHANGE_REPORTED, | |
63 | + | |
57 | 64 | SDEV_EVT_MAXBITS = SDEV_EVT_LAST + 1 |
58 | 65 | }; |
59 | 66 | |
... | ... | @@ -164,6 +171,7 @@ |
164 | 171 | atomic_t disk_events_disable_depth; /* disable depth for disk events */ |
165 | 172 | |
166 | 173 | DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */ |
174 | + DECLARE_BITMAP(pending_events, SDEV_EVT_MAXBITS); /* pending events */ | |
167 | 175 | struct list_head event_list; /* asserted events */ |
168 | 176 | struct work_struct event_work; |
169 | 177 | |
... | ... | @@ -261,6 +269,9 @@ |
261 | 269 | * means no lun present. */ |
262 | 270 | unsigned int no_report_luns:1; /* Don't use |
263 | 271 | * REPORT LUNS for scanning. */ |
272 | + unsigned int expecting_lun_change:1; /* A device has reported | |
273 | + * a 3F/0E UA, other devices on | |
274 | + * the same target will also. */ | |
264 | 275 | /* commands actually active on LLD. protected by host lock. */ |
265 | 276 | unsigned int target_busy; |
266 | 277 | /* |