scsi: establish precedence levels for unit attention
When a device is resized, we will report a unit attention condition for CAPACITY DATA HAS CHANGED. However, we should ensure that this condition does not override a more important unit attention condition. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
		
							parent
							
								
									350e6e4199
								
							
						
					
					
						commit
						e48e84ea80
					
				| @ -1531,6 +1531,55 @@ void scsi_req_abort(SCSIRequest *req, int status) | ||||
|     scsi_req_unref(req); | ||||
| } | ||||
| 
 | ||||
| static int scsi_ua_precedence(SCSISense sense) | ||||
| { | ||||
|     if (sense.key != UNIT_ATTENTION) { | ||||
|         return INT_MAX; | ||||
|     } | ||||
|     if (sense.asc == 0x29 && sense.ascq == 0x04) { | ||||
|         /* DEVICE INTERNAL RESET goes with POWER ON OCCURRED */ | ||||
|         return 1; | ||||
|     } else if (sense.asc == 0x3F && sense.ascq == 0x01) { | ||||
|         /* MICROCODE HAS BEEN CHANGED goes with SCSI BUS RESET OCCURRED */ | ||||
|         return 2; | ||||
|     } else if (sense.asc == 0x29 && (sense.ascq == 0x05 || sense.ascq == 0x06)) { | ||||
|         /* These two go with "all others". */ | ||||
|         ; | ||||
|     } else if (sense.asc == 0x29 && sense.ascq <= 0x07) { | ||||
|         /* POWER ON, RESET OR BUS DEVICE RESET OCCURRED = 0
 | ||||
|          * POWER ON OCCURRED = 1 | ||||
|          * SCSI BUS RESET OCCURRED = 2 | ||||
|          * BUS DEVICE RESET FUNCTION OCCURRED = 3 | ||||
|          * I_T NEXUS LOSS OCCURRED = 7 | ||||
|          */ | ||||
|         return sense.ascq; | ||||
|     } else if (sense.asc == 0x2F && sense.ascq == 0x01) { | ||||
|         /* COMMANDS CLEARED BY POWER LOSS NOTIFICATION  */ | ||||
|         return 8; | ||||
|     } | ||||
|     return (sense.asc << 8) | sense.ascq; | ||||
| } | ||||
| 
 | ||||
| void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense) | ||||
| { | ||||
|     int prec1, prec2; | ||||
|     if (sense.key != UNIT_ATTENTION) { | ||||
|         return; | ||||
|     } | ||||
|     trace_scsi_device_set_ua(sdev->id, sdev->lun, sense.key, | ||||
|                              sense.asc, sense.ascq); | ||||
| 
 | ||||
|     /*
 | ||||
|      * Override a pre-existing unit attention condition, except for a more | ||||
|      * important reset condition. | ||||
|     */ | ||||
|     prec1 = scsi_ua_precedence(sdev->unit_attention); | ||||
|     prec2 = scsi_ua_precedence(sense); | ||||
|     if (prec2 < prec1) { | ||||
|         sdev->unit_attention = sense; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense) | ||||
| { | ||||
|     SCSIRequest *req; | ||||
| @ -1539,7 +1588,8 @@ void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense) | ||||
|         req = QTAILQ_FIRST(&sdev->requests); | ||||
|         scsi_req_cancel(req); | ||||
|     } | ||||
|     sdev->unit_attention = sense; | ||||
| 
 | ||||
|     scsi_device_set_ua(sdev, sense); | ||||
| } | ||||
| 
 | ||||
| static char *scsibus_get_dev_path(DeviceState *dev) | ||||
|  | ||||
| @ -1876,7 +1876,7 @@ static void scsi_cd_change_media_cb(void *opaque, bool load) | ||||
|      */ | ||||
|     s->media_changed = load; | ||||
|     s->tray_open = !load; | ||||
|     s->qdev.unit_attention = SENSE_CODE(UNIT_ATTENTION_NO_MEDIUM); | ||||
|     scsi_device_set_ua(&s->qdev, SENSE_CODE(UNIT_ATTENTION_NO_MEDIUM)); | ||||
|     s->media_event = true; | ||||
|     s->eject_request = false; | ||||
| } | ||||
| @ -1913,7 +1913,7 @@ static void scsi_disk_unit_attention_reported(SCSIDevice *dev) | ||||
|     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); | ||||
|     if (s->media_changed) { | ||||
|         s->media_changed = false; | ||||
|         s->qdev.unit_attention = SENSE_CODE(MEDIUM_CHANGED); | ||||
|         scsi_device_set_ua(&s->qdev, SENSE_CODE(MEDIUM_CHANGED)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -239,6 +239,7 @@ void scsi_req_abort(SCSIRequest *req, int status); | ||||
| void scsi_req_cancel(SCSIRequest *req); | ||||
| void scsi_req_retry(SCSIRequest *req); | ||||
| void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense); | ||||
| void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense); | ||||
| int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed); | ||||
| SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lun); | ||||
| 
 | ||||
|  | ||||
| @ -412,6 +412,7 @@ scsi_req_parsed(int target, int lun, int tag, int cmd, int mode, int xfer) "targ | ||||
| scsi_req_parsed_lba(int target, int lun, int tag, int cmd, uint64_t lba) "target %d lun %d tag %d command %d lba %"PRIu64 | ||||
| scsi_req_parse_bad(int target, int lun, int tag, int cmd) "target %d lun %d tag %d command %d" | ||||
| scsi_req_build_sense(int target, int lun, int tag, int key, int asc, int ascq) "target %d lun %d tag %d key %#02x asc %#02x ascq %#02x" | ||||
| scsi_device_set_ua(int target, int lun, int key, int asc, int ascq) "target %d lun %d key %#02x asc %#02x ascq %#02x" | ||||
| scsi_report_luns(int target, int lun, int tag) "target %d lun %d tag %d" | ||||
| scsi_inquiry(int target, int lun, int tag, int cdb1, int cdb2) "target %d lun %d tag %d page %#02x/%#02x" | ||||
| scsi_test_unit_ready(int target, int lun, int tag) "target %d lun %d tag %d" | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Paolo Bonzini
						Paolo Bonzini