svn commit: r249152 - in stable/9/sys: cam cam/ata cam/scsi geom geom/part

Alexander Motin mav at FreeBSD.org
Thu Apr 25 04:26:26 UTC 2013


On 25.04.2013 02:39, Scott Long wrote:
> I've already responded to Alexander in private, but in case he doesn't respond, I'm stating publicly that I object to this commit (and the corresponding one in HEAD) and I'd like to have it reviewed and reverted.

The commit was announced on scsi@ and geom@ lists before reaching head, 
and it waited for more then half a year before being merged to 9-STABLE. 
If you still have objections, I would like to discuss them. Could you 
not start each email from request of reverting others work?

> On Apr 5, 2013, at 4:41 AM, Alexander Motin <mav at FreeBSD.org> wrote:
>
>> Author: mav
>> Date: Fri Apr  5 11:41:56 2013
>> New Revision: 249152
>> URL: http://svnweb.freebsd.org/changeset/base/249152
>>
>> Log:
>>   MFC r238886, r238892:
>>   Implement media change notification for DA and CD removable media devices.
>>   It includes three parts:
>>    1) Modifications to CAM to detect media media changes and report them to
>>   disk(9) layer. For modern SATA (and potentially UAS) devices it utilizes
>>   Asynchronous Notification mechanism to receive events from hardware.
>>   Active polling with TEST UNIT READY commands with 3 seconds period is used
>>   for incapable hardware. After that both CD and DA drivers work the same way,
>>   detecting two conditions: "NOT READY: Medium not present" after medium was
>>   detected previously, and "UNIT ATTENTION: Not ready to ready change, medium
>>   may have changed". First one reported to disk(9) as media removal, second
>>   as media insert/change. To reliably receive second event new
>>   AC_UNIT_ATTENTION async added to make UAs broadcasted to all periphs by
>>   generic error handling code in cam_periph_error().
>>    2) Modifications to GEOM core to handle media remove and change events.
>>   Media removal handled by spoiling all consumers attached to the provider.
>>   Media change event also schedules provider retaste after spoiling to probe
>>   new media. New flag G_CF_ORPHAN was added to consumers to reflect that
>>   consumer is in process of destruction. It allows retaste to create new
>>   geom instance of the same class, while previous one is still dying.
>>    3) Modifications to some GEOM classes: DEV -- to report media change
>>   events to devd; PART class already handles spoiling alike to orphan.
>>
>> Modified:
>>   stable/9/sys/cam/ata/ata_all.h
>>   stable/9/sys/cam/ata/ata_xpt.c
>>   stable/9/sys/cam/cam_ccb.h
>>   stable/9/sys/cam/cam_periph.c
>>   stable/9/sys/cam/cam_xpt.c
>>   stable/9/sys/cam/scsi/scsi_cd.c
>>   stable/9/sys/cam/scsi/scsi_da.c
>>   stable/9/sys/geom/geom.h
>>   stable/9/sys/geom/geom_dev.c
>>   stable/9/sys/geom/geom_disk.c
>>   stable/9/sys/geom/geom_disk.h
>>   stable/9/sys/geom/geom_event.c
>>   stable/9/sys/geom/geom_io.c
>>   stable/9/sys/geom/geom_slice.c
>>   stable/9/sys/geom/geom_subr.c
>>   stable/9/sys/geom/part/g_part.c
>> Directory Properties:
>>   stable/9/sys/   (props changed)
>>
>> Modified: stable/9/sys/cam/ata/ata_all.h
>> ==============================================================================
>> --- stable/9/sys/cam/ata/ata_all.h	Fri Apr  5 11:30:31 2013	(r249151)
>> +++ stable/9/sys/cam/ata/ata_all.h	Fri Apr  5 11:41:56 2013	(r249152)
>> @@ -35,6 +35,7 @@ struct ccb_ataio;
>> struct cam_periph;
>> union  ccb;
>>
>> +#define	SID_AEN		0x04	/* Abuse inq_flags bit to track enabled AEN. */
>> #define	SID_DMA		0x10	/* Abuse inq_flags bit to track enabled DMA. */
>>
>> struct ata_cmd {
>>
>> Modified: stable/9/sys/cam/ata/ata_xpt.c
>> ==============================================================================
>> --- stable/9/sys/cam/ata/ata_xpt.c	Fri Apr  5 11:30:31 2013	(r249151)
>> +++ stable/9/sys/cam/ata/ata_xpt.c	Fri Apr  5 11:41:56 2013	(r249152)
>> @@ -463,6 +463,12 @@ negotiate:
>> 		    0, 0x02);
>> 		break;
>> 	case PROBE_SETAN:
>> +		/* Remember what transport thinks about AEN. */
>> +		if (softc->caps & CTS_SATA_CAPS_H_AN)
>> +			path->device->inq_flags |= SID_AEN;
>> +		else
>> +			path->device->inq_flags &= ~SID_AEN;
>> +		xpt_async(AC_GETDEV_CHANGED, path, NULL);
>> 		cam_fill_ataio(ataio,
>> 		    1,
>> 		    probedone,
>> @@ -1157,6 +1163,12 @@ notsata:
>> 		cts.xport_specific.sata.valid = CTS_SATA_VALID_CAPS;
>> 		xpt_action((union ccb *)&cts);
>> 		softc->caps = caps;
>> +		/* Remember what transport thinks about AEN. */
>> +		if (softc->caps & CTS_SATA_CAPS_H_AN)
>> +			path->device->inq_flags |= SID_AEN;
>> +		else
>> +			path->device->inq_flags &= ~SID_AEN;
>> +		xpt_async(AC_GETDEV_CHANGED, path, NULL);
>> 		if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
>> 			path->device->flags &= ~CAM_DEV_UNCONFIGURED;
>> 			xpt_acquire_device(path->device);
>>
>> Modified: stable/9/sys/cam/cam_ccb.h
>> ==============================================================================
>> --- stable/9/sys/cam/cam_ccb.h	Fri Apr  5 11:30:31 2013	(r249151)
>> +++ stable/9/sys/cam/cam_ccb.h	Fri Apr  5 11:41:56 2013	(r249152)
>> @@ -755,6 +755,7 @@ struct ccb_relsim {
>>   * Definitions for the asynchronous callback CCB fields.
>>   */
>> typedef enum {
>> +	AC_UNIT_ATTENTION	= 0x4000,/* Device reported UNIT ATTENTION */
>> 	AC_ADVINFO_CHANGED	= 0x2000,/* Advance info might have changes */
>> 	AC_CONTRACT		= 0x1000,/* A contractual callback */
>> 	AC_GETDEV_CHANGED	= 0x800,/* Getdev info might have changed */
>>
>> Modified: stable/9/sys/cam/cam_periph.c
>> ==============================================================================
>> --- stable/9/sys/cam/cam_periph.c	Fri Apr  5 11:30:31 2013	(r249151)
>> +++ stable/9/sys/cam/cam_periph.c	Fri Apr  5 11:41:56 2013	(r249152)
>> @@ -1604,6 +1604,7 @@ cam_periph_error(union ccb *ccb, cam_fla
>> 	const char *action_string;
>> 	cam_status  status;
>> 	int	    frozen, error, openings, print, lost_device;
>> +	int	    error_code, sense_key, asc, ascq;
>> 	u_int32_t   relsim_flags, timeout;
>>
>> 	print = 1;
>> @@ -1770,6 +1771,12 @@ cam_periph_error(union ccb *ccb, cam_fla
>> 			xpt_async(AC_LOST_DEVICE, newpath, NULL);
>> 			xpt_free_path(newpath);
>> 		}
>> +
>> +	/* Broadcast UNIT ATTENTIONs to all periphs. */
>> +	} else if (scsi_extract_sense_ccb(ccb,
>> +	    &error_code, &sense_key, &asc, &ascq) &&
>> +	    sense_key == SSD_KEY_UNIT_ATTENTION) {
>> +		xpt_async(AC_UNIT_ATTENTION, orig_ccb->ccb_h.path, orig_ccb);
>> 	}
>>
>> 	/* Attempt a retry */
>>
>> Modified: stable/9/sys/cam/cam_xpt.c
>> ==============================================================================
>> --- stable/9/sys/cam/cam_xpt.c	Fri Apr  5 11:30:31 2013	(r249151)
>> +++ stable/9/sys/cam/cam_xpt.c	Fri Apr  5 11:41:56 2013	(r249152)
>> @@ -4053,6 +4053,7 @@ xpt_async_string(u_int32_t async_code)
>> 	case AC_GETDEV_CHANGED: return ("AC_GETDEV_CHANGED");
>> 	case AC_CONTRACT: return ("AC_CONTRACT");
>> 	case AC_ADVINFO_CHANGED: return ("AC_ADVINFO_CHANGED");
>> +	case AC_UNIT_ATTENTION: return ("AC_UNIT_ATTENTION");
>> 	}
>> 	return ("AC_UNKNOWN");
>> }
>>
>> Modified: stable/9/sys/cam/scsi/scsi_cd.c
>> ==============================================================================
>> --- stable/9/sys/cam/scsi/scsi_cd.c	Fri Apr  5 11:30:31 2013	(r249151)
>> +++ stable/9/sys/cam/scsi/scsi_cd.c	Fri Apr  5 11:41:56 2013	(r249152)
>> @@ -97,6 +97,7 @@ typedef enum {
>> 	CD_FLAG_NEW_DISC	= 0x0002,
>> 	CD_FLAG_DISC_LOCKED	= 0x0004,
>> 	CD_FLAG_DISC_REMOVABLE	= 0x0008,
>> +	CD_FLAG_SAW_MEDIA	= 0x0010,
>> 	CD_FLAG_CHANGER		= 0x0040,
>> 	CD_FLAG_ACTIVE		= 0x0080,
>> 	CD_FLAG_SCHED_ON_COMP	= 0x0100,
>> @@ -110,6 +111,7 @@ typedef enum {
>> 	CD_CCB_PROBE		= 0x01,
>> 	CD_CCB_BUFFER_IO	= 0x02,
>> 	CD_CCB_WAITING		= 0x03,
>> +	CD_CCB_TUR		= 0x04,
>> 	CD_CCB_TYPE_MASK	= 0x0F,
>> 	CD_CCB_RETRY_UA		= 0x10
>> } cd_ccb_state;
>> @@ -154,12 +156,14 @@ struct cd_softc {
>> 	struct cam_periph	*periph;
>> 	int			minimum_command_size;
>> 	int			outstanding_cmds;
>> +	int			tur;
>> 	struct task		sysctl_task;
>> 	struct sysctl_ctx_list	sysctl_ctx;
>> 	struct sysctl_oid	*sysctl_tree;
>> 	STAILQ_HEAD(, cd_mode_params)	mode_queue;
>> 	struct cd_tocdata	toc;
>> 	struct disk		*disk;
>> +	struct callout		mediapoll_c;
>> };
>>
>> struct cd_page_sizes {
>> @@ -281,6 +285,7 @@ static	int		cdsendkey(struct cam_periph
>> 				  struct dvd_authinfo *authinfo);
>> static	int		cdreaddvdstructure(struct cam_periph *periph,
>> 					   struct dvd_struct *dvdstruct);
>> +static timeout_t	cdmediapoll;
>>
>> static struct periph_driver cddriver =
>> {
>> @@ -290,6 +295,9 @@ static struct periph_driver cddriver =
>>
>> PERIPHDRIVER_DECLARE(cd, cddriver);
>>
>> +#ifndef	CD_DEFAULT_POLL_PERIOD
>> +#define	CD_DEFAULT_POLL_PERIOD	3
>> +#endif
>> #ifndef	CD_DEFAULT_RETRY
>> #define	CD_DEFAULT_RETRY	4
>> #endif
>> @@ -303,6 +311,7 @@ PERIPHDRIVER_DECLARE(cd, cddriver);
>> #define CHANGER_MAX_BUSY_SECONDS	15
>> #endif
>>
>> +static int cd_poll_period = CD_DEFAULT_POLL_PERIOD;
>> static int cd_retry_count = CD_DEFAULT_RETRY;
>> static int cd_timeout = CD_DEFAULT_TIMEOUT;
>> static int changer_min_busy_seconds = CHANGER_MIN_BUSY_SECONDS;
>> @@ -311,6 +320,9 @@ static int changer_max_busy_seconds = CH
>> static SYSCTL_NODE(_kern_cam, OID_AUTO, cd, CTLFLAG_RD, 0, "CAM CDROM driver");
>> static SYSCTL_NODE(_kern_cam_cd, OID_AUTO, changer, CTLFLAG_RD, 0,
>>      "CD Changer");
>> +SYSCTL_INT(_kern_cam_cd, OID_AUTO, poll_period, CTLFLAG_RW,
>> +           &cd_poll_period, 0, "Media polling period in seconds");
>> +TUNABLE_INT("kern.cam.cd.poll_period", &cd_poll_period);
>> SYSCTL_INT(_kern_cam_cd, OID_AUTO, retry_count, CTLFLAG_RW,
>>             &cd_retry_count, 0, "Normal I/O retry count");
>> TUNABLE_INT("kern.cam.cd.retry_count", &cd_retry_count);
>> @@ -494,6 +506,7 @@ cdcleanup(struct cam_periph *periph)
>> 		xpt_print(periph->path, "can't remove sysctl context\n");
>> 	}
>>
>> +	callout_drain(&softc->mediapoll_c);
>> 	disk_destroy(softc->disk);
>> 	free(softc, M_DEVBUF);
>> 	cam_periph_lock(periph);
>> @@ -504,6 +517,7 @@ cdasync(void *callback_arg, u_int32_t co
>> 	struct cam_path *path, void *arg)
>> {
>> 	struct cam_periph *periph;
>> +	struct cd_softc *softc;
>>
>> 	periph = (struct cam_periph *)callback_arg;
>> 	switch (code) {
>> @@ -541,10 +555,39 @@ cdasync(void *callback_arg, u_int32_t co
>>
>> 		break;
>> 	}
>> +	case AC_UNIT_ATTENTION:
>> +	{
>> +		union ccb *ccb;
>> +		int error_code, sense_key, asc, ascq;
>> +
>> +		softc = (struct cd_softc *)periph->softc;
>> +		ccb = (union ccb *)arg;
>> +
>> +		/*
>> +		 * Handle all media change UNIT ATTENTIONs except
>> +		 * our own, as they will be handled by cderror().
>> +		 */
>> +		if (xpt_path_periph(ccb->ccb_h.path) != periph &&
>> +		    scsi_extract_sense_ccb(ccb,
>> +		     &error_code, &sense_key, &asc, &ascq)) {
>> +			if (asc == 0x28 && ascq == 0x00)
>> +				disk_media_changed(softc->disk, M_NOWAIT);
>> +		}
>> +		cam_periph_async(periph, code, path, arg);
>> +		break;
>> +	}
>> +	case AC_SCSI_AEN:
>> +		softc = (struct cd_softc *)periph->softc;
>> +		if (softc->state == CD_STATE_NORMAL && !softc->tur) {
>> +			if (cam_periph_acquire(periph) == CAM_REQ_CMP) {
>> +				softc->tur = 1;
>> +				xpt_schedule(periph, CAM_PRIORITY_DEV);
>> +			}
>> +		}
>> +		/* FALLTHROUGH */
>> 	case AC_SENT_BDR:
>> 	case AC_BUS_RESET:
>> 	{
>> -		struct cd_softc *softc;
>> 		struct ccb_hdr *ccbh;
>>
>> 		softc = (struct cd_softc *)periph->softc;
>> @@ -784,8 +827,8 @@ cdregister(struct cam_periph *periph, vo
>> 	 * Add an async callback so that we get
>> 	 * notified if this device goes away.
>> 	 */
>> -	xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE,
>> -			   cdasync, periph, periph->path);
>> +	xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE |
>> +	    AC_SCSI_AEN | AC_UNIT_ATTENTION, cdasync, periph, periph->path);
>>
>> 	/*
>> 	 * If the target lun is greater than 0, we most likely have a CD
>> @@ -1001,6 +1044,17 @@ cdregister(struct cam_periph *periph, vo
>> 		}
>> 	}
>>
>> +	/*
>> +	 * Schedule a periodic media polling events.
>> +	 */
>> +	callout_init_mtx(&softc->mediapoll_c, periph->sim->mtx, 0);
>> +	if ((softc->flags & CD_FLAG_DISC_REMOVABLE) &&
>> +	    (softc->flags & CD_FLAG_CHANGER) == 0 &&
>> +	    (cgd->inq_flags & SID_AEN) == 0 &&
>> +	    cd_poll_period != 0)
>> +		callout_reset(&softc->mediapoll_c, cd_poll_period * hz,
>> +		    cdmediapoll, periph);
>> +
>> cdregisterexit:
>>
>> 	if ((softc->flags & CD_FLAG_CHANGER) == 0)
>> @@ -1496,8 +1550,25 @@ cdstart(struct cam_periph *periph, union
>> 			periph->immediate_priority = CAM_PRIORITY_NONE;
>> 			wakeup(&periph->ccb_list);
>> 		} else if (bp == NULL) {
>> -			xpt_release_ccb(start_ccb);
>> +			if (softc->tur) {
>> +				softc->tur = 0;
>> +				csio = &start_ccb->csio;
>> +				scsi_test_unit_ready(csio,
>> +				     /*retries*/ cd_retry_count,
>> +				     cddone,
>> +				     MSG_SIMPLE_Q_TAG,
>> +				     SSD_FULL_SIZE,
>> +				     cd_timeout);
>> +				start_ccb->ccb_h.ccb_bp = NULL;
>> +				start_ccb->ccb_h.ccb_state = CD_CCB_TUR;
>> +				xpt_action(start_ccb);
>> +			} else
>> +				xpt_release_ccb(start_ccb);
>> 		} else {
>> +			if (softc->tur) {
>> +				softc->tur = 0;
>> +				cam_periph_release_locked(periph);
>> +			}
>> 			bioq_remove(&softc->bio_queue, bp);
>>
>> 			scsi_read_write(&start_ccb->csio,
>> @@ -1541,7 +1612,7 @@ cdstart(struct cam_periph *periph, union
>>
>> 			xpt_action(start_ccb);
>> 		}
>> -		if (bp != NULL) {
>> +		if (bp != NULL || softc->tur) {
>> 			/* Have more work to do, so ensure we stay scheduled */
>> 			xpt_schedule(periph, CAM_PRIORITY_NORMAL);
>> 		}
>> @@ -1835,6 +1906,25 @@ cddone(struct cam_periph *periph, union
>> 		wakeup(&done_ccb->ccb_h.cbfcnp);
>> 		return;
>> 	}
>> +	case CD_CCB_TUR:
>> +	{
>> +		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
>> +
>> +			if (cderror(done_ccb, CAM_RETRY_SELTO,
>> +			    SF_RETRY_UA | SF_NO_RECOVERY | SF_NO_PRINT) ==
>> +			    ERESTART)
>> +				return;
>> +			if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
>> +				cam_release_devq(done_ccb->ccb_h.path,
>> +						 /*relsim_flags*/0,
>> +						 /*reduction*/0,
>> +						 /*timeout*/0,
>> +						 /*getcount_only*/0);
>> +		}
>> +		xpt_release_ccb(done_ccb);
>> +		cam_periph_release_locked(periph);
>> +		return;
>> +	}
>> 	default:
>> 		break;
>> 	}
>> @@ -2826,7 +2916,7 @@ cdcheckmedia(struct cam_periph *periph)
>> 		cdprevent(periph, PR_ALLOW);
>> 		return (error);
>> 	} else {
>> -		softc->flags |= CD_FLAG_VALID_MEDIA;
>> +		softc->flags |= CD_FLAG_SAW_MEDIA | CD_FLAG_VALID_MEDIA;
>> 		softc->disk->d_sectorsize = softc->params.blksize;
>> 		softc->disk->d_mediasize =
>> 		    (off_t)softc->params.blksize * softc->params.disksize;
>> @@ -3171,6 +3261,14 @@ cderror(union ccb *ccb, u_int32_t cam_fl
>> 	    &error_code, &sense_key, &asc, &ascq)) {
>> 		if (sense_key == SSD_KEY_ILLEGAL_REQUEST)
>> 			error = cd6byteworkaround(ccb);
>> +		else if (sense_key == SSD_KEY_UNIT_ATTENTION &&
>> +		    asc == 0x28 && ascq == 0x00)
>> +			disk_media_changed(softc->disk, M_NOWAIT);
>> +		else if (sense_key == SSD_KEY_NOT_READY &&
>> +		    asc == 0x3a && (softc->flags & CD_FLAG_SAW_MEDIA)) {
>> +			softc->flags &= ~CD_FLAG_SAW_MEDIA;
>> +			disk_media_gone(softc->disk, M_NOWAIT);
>> +		}
>> 	}
>>
>> 	if (error == ERESTART)
>> @@ -3186,6 +3284,26 @@ cderror(union ccb *ccb, u_int32_t cam_fl
>> 				 &softc->saved_ccb));
>> }
>>
>> +static void
>> +cdmediapoll(void *arg)
>> +{
>> +	struct cam_periph *periph = arg;
>> +	struct cd_softc *softc = periph->softc;
>> +
>> +	if (softc->flags & CD_FLAG_CHANGER)
>> +		return;
>> +
>> +	if (softc->state == CD_STATE_NORMAL && !softc->tur) {
>> +		if (cam_periph_acquire(periph) == CAM_REQ_CMP) {
>> +			softc->tur = 1;
>> +			xpt_schedule(periph, CAM_PRIORITY_DEV);
>> +		}
>> +	}
>> +	/* Queue us up again */
>> +	if (cd_poll_period != 0)
>> +		callout_schedule(&softc->mediapoll_c, cd_poll_period * hz);
>> +}
>> +
>> /*
>>   * Read table of contents
>>   */
>>
>> Modified: stable/9/sys/cam/scsi/scsi_da.c
>> ==============================================================================
>> --- stable/9/sys/cam/scsi/scsi_da.c	Fri Apr  5 11:30:31 2013	(r249151)
>> +++ stable/9/sys/cam/scsi/scsi_da.c	Fri Apr  5 11:41:56 2013	(r249152)
>> @@ -77,6 +77,7 @@ typedef enum {
>> 	DA_FLAG_NEW_PACK	= 0x002,
>> 	DA_FLAG_PACK_LOCKED	= 0x004,
>> 	DA_FLAG_PACK_REMOVABLE	= 0x008,
>> +	DA_FLAG_SAW_MEDIA	= 0x010,
>> 	DA_FLAG_NEED_OTAG	= 0x020,
>> 	DA_FLAG_WENT_IDLE	= 0x040,
>> 	DA_FLAG_RETRY_UA	= 0x080,
>> @@ -101,6 +102,7 @@ typedef enum {
>> 	DA_CCB_WAITING		= 0x04,
>> 	DA_CCB_DUMP		= 0x05,
>> 	DA_CCB_DELETE		= 0x06,
>> +	DA_CCB_TUR		= 0x07,
>> 	DA_CCB_TYPE_MASK	= 0x0F,
>> 	DA_CCB_RETRY_UA		= 0x10
>> } da_ccb_state;
>> @@ -150,6 +152,7 @@ struct da_softc {
>> 	int	 unmap_max_ranges;
>> 	int	 unmap_max_lba;
>> 	int	 delete_running;
>> +	int	 tur;
>> 	da_delete_methods	 delete_method;
>> 	struct	 disk_params params;
>> 	struct	 disk *disk;
>> @@ -161,6 +164,7 @@ struct da_softc {
>> 	uint64_t wwpn;
>> 	uint8_t	 unmap_buf[UNMAP_MAX_RANGES * 16 + 8];
>> 	struct scsi_read_capacity_data_long rcaplong;
>> +	struct callout		mediapoll_c;
>> };
>>
>> struct da_quirk_entry {
>> @@ -875,6 +879,11 @@ static void		dasetgeom(struct cam_periph
>> 				  size_t rcap_size);
>> static timeout_t	dasendorderedtag;
>> static void		dashutdown(void *arg, int howto);
>> +static timeout_t	damediapoll;
>> +
>> +#ifndef	DA_DEFAULT_POLL_PERIOD
>> +#define	DA_DEFAULT_POLL_PERIOD	3
>> +#endif
>>
>> #ifndef DA_DEFAULT_TIMEOUT
>> #define DA_DEFAULT_TIMEOUT 60	/* Timeout in seconds */
>> @@ -889,12 +898,16 @@ static void		dashutdown(void *arg, int h
>> #endif
>>
>>
>> +static int da_poll_period = DA_DEFAULT_POLL_PERIOD;
>> static int da_retry_count = DA_DEFAULT_RETRY;
>> static int da_default_timeout = DA_DEFAULT_TIMEOUT;
>> static int da_send_ordered = DA_DEFAULT_SEND_ORDERED;
>>
>> static SYSCTL_NODE(_kern_cam, OID_AUTO, da, CTLFLAG_RD, 0,
>>              "CAM Direct Access Disk driver");
>> +SYSCTL_INT(_kern_cam_da, OID_AUTO, poll_period, CTLFLAG_RW,
>> +           &da_poll_period, 0, "Media polling period in seconds");
>> +TUNABLE_INT("kern.cam.da.poll_period", &da_poll_period);
>> SYSCTL_INT(_kern_cam_da, OID_AUTO, retry_count, CTLFLAG_RW,
>>             &da_retry_count, 0, "Normal I/O retry count");
>> TUNABLE_INT("kern.cam.da.retry_count", &da_retry_count);
>> @@ -984,6 +997,9 @@ daopen(struct disk *dp)
>> 	    (softc->quirks & DA_Q_NO_PREVENT) == 0)
>> 		daprevent(periph, PR_PREVENT);
>>
>> +	if (error == 0)
>> +		softc->flags |= DA_FLAG_SAW_MEDIA;
>> +
>> 	cam_periph_unhold(periph);
>> 	cam_periph_unlock(periph);
>>
>> @@ -1068,7 +1084,8 @@ daschedule(struct cam_periph *periph)
>>
>> 	/* Check if we have more work to do. */
>> 	if (bioq_first(&softc->bio_queue) ||
>> -	    (!softc->delete_running && bioq_first(&softc->delete_queue))) {
>> +	    (!softc->delete_running && bioq_first(&softc->delete_queue)) ||
>> +	    softc->tur) {
>> 		prio = CAM_PRIORITY_NORMAL;
>> 	}
>>
>> @@ -1315,6 +1332,7 @@ dacleanup(struct cam_periph *periph)
>> 		xpt_print(periph->path, "can't remove sysctl context\n");
>> 	}
>>
>> +	callout_drain(&softc->mediapoll_c);
>> 	disk_destroy(softc->disk);
>> 	callout_drain(&softc->sendordered_c);
>> 	free(softc, M_DEVBUF);
>> @@ -1326,6 +1344,7 @@ daasync(void *callback_arg, u_int32_t co
>> 	struct cam_path *path, void *arg)
>> {
>> 	struct cam_periph *periph;
>> +	struct da_softc *softc;
>>
>> 	periph = (struct cam_periph *)callback_arg;
>> 	switch (code) {
>> @@ -1377,10 +1396,43 @@ daasync(void *callback_arg, u_int32_t co
>> 		}
>> 		break;
>> 	}
>> +	case AC_UNIT_ATTENTION:
>> +	{
>> +		union ccb *ccb;
>> +		int error_code, sense_key, asc, ascq;
>> +
>> +		softc = (struct da_softc *)periph->softc;
>> +		ccb = (union ccb *)arg;
>> +
>> +		/*
>> +		 * Handle all UNIT ATTENTIONs except our own,
>> +		 * as they will be handled by daerror().
>> +		 */
>> +		if (xpt_path_periph(ccb->ccb_h.path) != periph &&
>> +		    scsi_extract_sense_ccb(ccb,
>> +		     &error_code, &sense_key, &asc, &ascq)) {
>> +			if (asc == 0x2A && ascq == 0x09) {
>> +				xpt_print(ccb->ccb_h.path,
>> +				    "capacity data has changed\n");
>> +				dareprobe(periph);
>> +			} else if (asc == 0x28 && ascq == 0x00)
>> +				disk_media_changed(softc->disk, M_NOWAIT);
>> +		}
>> +		cam_periph_async(periph, code, path, arg);
>> +		break;
>> +	}
>> +	case AC_SCSI_AEN:
>> +		softc = (struct da_softc *)periph->softc;
>> +		if (softc->state == DA_STATE_NORMAL && !softc->tur) {
>> +			if (cam_periph_acquire(periph) == CAM_REQ_CMP) {
>> +				softc->tur = 1;
>> +				xpt_schedule(periph, CAM_PRIORITY_DEV);
>> +			}
>> +		}
>> +		/* FALLTHROUGH */
>> 	case AC_SENT_BDR:
>> 	case AC_BUS_RESET:
>> 	{
>> -		struct da_softc *softc;
>> 		struct ccb_hdr *ccbh;
>>
>> 		softc = (struct da_softc *)periph->softc;
>> @@ -1711,9 +1763,9 @@ daregister(struct cam_periph *periph, vo
>> 	 * fine without them and the only alternative
>> 	 * would be to not attach the device on failure.
>> 	 */
>> -	xpt_register_async(AC_SENT_BDR | AC_BUS_RESET
>> -			 | AC_LOST_DEVICE | AC_ADVINFO_CHANGED,
>> -			   daasync, periph, periph->path);
>> +	xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE |
>> +	    AC_ADVINFO_CHANGED | AC_SCSI_AEN | AC_UNIT_ATTENTION,
>> +	    daasync, periph, periph->path);
>>
>> 	/*
>> 	 * Emit an attribute changed notification just in case
>> @@ -1723,6 +1775,16 @@ daregister(struct cam_periph *periph, vo
>> 	 */
>> 	disk_attr_changed(softc->disk, "GEOM::physpath", M_NOWAIT);
>>
>> +	/*
>> +	 * Schedule a periodic media polling events.
>> +	 */
>> +	callout_init_mtx(&softc->mediapoll_c, periph->sim->mtx, 0);
>> +	if ((softc->flags & DA_FLAG_PACK_REMOVABLE) &&
>> +	    (cgd->inq_flags & SID_AEN) == 0 &&
>> +	    da_poll_period != 0)
>> +		callout_reset(&softc->mediapoll_c, da_poll_period * hz,
>> +		    damediapoll, periph);
>> +
>> 	xpt_schedule(periph, CAM_PRIORITY_DEV);
>>
>> 	return(CAM_REQ_CMP);
>> @@ -1860,9 +1922,25 @@ dastart(struct cam_periph *periph, union
>> 		/* Run regular command. */
>> 		bp = bioq_takefirst(&softc->bio_queue);
>> 		if (bp == NULL) {
>> -			xpt_release_ccb(start_ccb);
>> +			if (softc->tur) {
>> +				softc->tur = 0;
>> +				scsi_test_unit_ready(&start_ccb->csio,
>> +				     /*retries*/ da_retry_count,
>> +				     dadone,
>> +				     MSG_SIMPLE_Q_TAG,
>> +				     SSD_FULL_SIZE,
>> +				     da_default_timeout * 1000);
>> +				start_ccb->ccb_h.ccb_bp = NULL;
>> +				start_ccb->ccb_h.ccb_state = DA_CCB_TUR;
>> +				xpt_action(start_ccb);
>> +			} else
>> +				xpt_release_ccb(start_ccb);
>> 			break;
>> 		}
>> +		if (softc->tur) {
>> +			softc->tur = 0;
>> +			cam_periph_release_locked(periph);
>> +		}
>>
>> 		if ((bp->bio_flags & BIO_ORDERED) != 0 ||
>> 		    (softc->flags & DA_FLAG_NEED_OTAG) != 0) {
>> @@ -2429,6 +2507,25 @@ dadone(struct cam_periph *periph, union
>> 	case DA_CCB_DUMP:
>> 		/* No-op.  We're polling */
>> 		return;
>> +	case DA_CCB_TUR:
>> +	{
>> +		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
>> +
>> +			if (daerror(done_ccb, CAM_RETRY_SELTO,
>> +			    SF_RETRY_UA | SF_NO_RECOVERY | SF_NO_PRINT) ==
>> +			    ERESTART)
>> +				return;
>> +			if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
>> +				cam_release_devq(done_ccb->ccb_h.path,
>> +						 /*relsim_flags*/0,
>> +						 /*reduction*/0,
>> +						 /*timeout*/0,
>> +						 /*getcount_only*/0);
>> +		}
>> +		xpt_release_ccb(done_ccb);
>> +		cam_periph_release_locked(periph);
>> +		return;
>> +	}
>> 	default:
>> 		break;
>> 	}
>> @@ -2489,6 +2586,13 @@ daerror(union ccb *ccb, u_int32_t cam_fl
>> 			xpt_print(periph->path, "capacity data has changed\n");
>> 			dareprobe(periph);
>> 			sense_flags |= SF_NO_PRINT;
>> +		} else if (sense_key == SSD_KEY_UNIT_ATTENTION &&
>> +		    asc == 0x28 && ascq == 0x00)
>> +			disk_media_changed(softc->disk, M_NOWAIT);
>> +		else if (sense_key == SSD_KEY_NOT_READY &&
>> +		    asc == 0x3a && (softc->flags & DA_FLAG_SAW_MEDIA)) {
>> +			softc->flags &= ~DA_FLAG_SAW_MEDIA;
>> +			disk_media_gone(softc->disk, M_NOWAIT);
>> 		}
>> 	}
>> 	if (error == ERESTART)
>> @@ -2505,6 +2609,23 @@ daerror(union ccb *ccb, u_int32_t cam_fl
>> }
>>
>> static void
>> +damediapoll(void *arg)
>> +{
>> +	struct cam_periph *periph = arg;
>> +	struct da_softc *softc = periph->softc;
>> +
>> +	if (softc->state == DA_STATE_NORMAL && !softc->tur) {
>> +		if (cam_periph_acquire(periph) == CAM_REQ_CMP) {
>> +			softc->tur = 1;
>> +			daschedule(periph);
>> +		}
>> +	}
>> +	/* Queue us up again */
>> +	if (da_poll_period != 0)
>> +		callout_schedule(&softc->mediapoll_c, da_poll_period * hz);
>> +}
>> +
>> +static void
>> daprevent(struct cam_periph *periph, int action)
>> {
>> 	struct	da_softc *softc;
>>
>> Modified: stable/9/sys/geom/geom.h
>> ==============================================================================
>> --- stable/9/sys/geom/geom.h	Fri Apr  5 11:30:31 2013	(r249151)
>> +++ stable/9/sys/geom/geom.h	Fri Apr  5 11:41:56 2013	(r249152)
>> @@ -169,7 +169,9 @@ struct g_consumer {
>> 	struct g_provider	*provider;
>> 	LIST_ENTRY(g_consumer)	consumers;	/* XXX: better name */
>> 	int			acr, acw, ace;
>> -	int			spoiled;
>> +	int			flags;
>> +#define G_CF_SPOILED		0x1
>> +#define G_CF_ORPHAN		0x4
>> 	struct devstat		*stat;
>> 	u_int			nstart, nend;
>>
>> @@ -242,6 +244,8 @@ int g_post_event(g_event_t *func, void *
>> int g_waitfor_event(g_event_t *func, void *arg, int flag, ...);
>> void g_cancel_event(void *ref);
>> int g_attr_changed(struct g_provider *pp, const char *attr, int flag);
>> +int g_media_changed(struct g_provider *pp, int flag);
>> +int g_media_gone(struct g_provider *pp, int flag);
>> void g_orphan_provider(struct g_provider *pp, int error);
>> void g_waitidlelock(void);
>>
>>
>> Modified: stable/9/sys/geom/geom_dev.c
>> ==============================================================================
>> --- stable/9/sys/geom/geom_dev.c	Fri Apr  5 11:30:31 2013	(r249151)
>> +++ stable/9/sys/geom/geom_dev.c	Fri Apr  5 11:41:56 2013	(r249152)
>> @@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
>> #include <sys/conf.h>
>> #include <sys/ctype.h>
>> #include <sys/bio.h>
>> +#include <sys/bus.h>
>> #include <sys/lock.h>
>> #include <sys/mutex.h>
>> #include <sys/proc.h>
>> @@ -105,6 +106,21 @@ g_dev_print(void)
>> static void
>> g_dev_attrchanged(struct g_consumer *cp, const char *attr)
>> {
>> +	struct cdev *dev;
>> +	char buf[SPECNAMELEN + 6];
>> +
>> +	if (strcmp(attr, "GEOM::media") == 0) {
>> +		dev = cp->geom->softc;
>> +		snprintf(buf, sizeof(buf), "cdev=%s", dev->si_name);
>> +		devctl_notify_f("DEVFS", "CDEV", "MEDIACHANGE", buf, M_WAITOK);
>> +		dev = cp->cp_alias_dev;
>> +		if (dev != NULL) {
>> +			snprintf(buf, sizeof(buf), "cdev=%s", dev->si_name);
>> +			devctl_notify_f("DEVFS", "CDEV", "MEDIACHANGE", buf,
>> +			    M_WAITOK);
>> +		}
>> +		return;
>> +	}
>>
>> 	if (strcmp(attr, "GEOM::physpath") != 0)
>> 		return;
>> @@ -119,7 +135,6 @@ g_dev_attrchanged(struct g_consumer *cp,
>> 		    g_io_getattr("GEOM::physpath", cp, &physpath_len, physpath);
>> 		g_access(cp, -1, 0, 0);
>> 		if (error == 0 && strlen(physpath) != 0) {
>> -			struct cdev *dev;
>> 			struct cdev *old_alias_dev;
>> 			struct cdev **alias_devp;
>>
>> @@ -161,9 +176,6 @@ g_dev_taste(struct g_class *mp, struct g
>>
>> 	g_trace(G_T_TOPOLOGY, "dev_taste(%s,%s)", mp->name, pp->name);
>> 	g_topology_assert();
>> -	LIST_FOREACH(cp, &pp->consumers, consumers)
>> -		if (cp->geom->class == mp)
>> -			return (NULL);
>> 	gp = g_new_geomf(mp, "%s", pp->name);
>> 	cp = g_new_consumer(gp);
>> 	error = g_attach(cp, pp);
>>
>> Modified: stable/9/sys/geom/geom_disk.c
>> ==============================================================================
>> --- stable/9/sys/geom/geom_disk.c	Fri Apr  5 11:30:31 2013	(r249151)
>> +++ stable/9/sys/geom/geom_disk.c	Fri Apr  5 11:41:56 2013	(r249152)
>> @@ -649,6 +649,32 @@ disk_attr_changed(struct disk *dp, const
>> 			(void)g_attr_changed(pp, attr, flag);
>> }
>>
>> +void
>> +disk_media_changed(struct disk *dp, int flag)
>> +{
>> +	struct g_geom *gp;
>> +	struct g_provider *pp;
>> +
>> +	gp = dp->d_geom;
>> +	if (gp != NULL) {
>> +		LIST_FOREACH(pp, &gp->provider, provider)
>> +			g_media_changed(pp, flag);
>> +	}
>> +}
>> +
>> +void
>> +disk_media_gone(struct disk *dp, int flag)
>> +{
>> +	struct g_geom *gp;
>> +	struct g_provider *pp;
>> +
>> +	gp = dp->d_geom;
>> +	if (gp != NULL) {
>> +		LIST_FOREACH(pp, &gp->provider, provider)
>> +			g_media_gone(pp, flag);
>> +	}
>> +}
>> +
>> static void
>> g_kern_disks(void *p, int flag __unused)
>> {
>>
>> Modified: stable/9/sys/geom/geom_disk.h
>> ==============================================================================
>> --- stable/9/sys/geom/geom_disk.h	Fri Apr  5 11:30:31 2013	(r249151)
>> +++ stable/9/sys/geom/geom_disk.h	Fri Apr  5 11:41:56 2013	(r249152)
>> @@ -112,6 +112,8 @@ void disk_create(struct disk *disk, int
>> void disk_destroy(struct disk *disk);
>> void disk_gone(struct disk *disk);
>> void disk_attr_changed(struct disk *dp, const char *attr, int flag);
>> +void disk_media_changed(struct disk *dp, int flag);
>> +void disk_media_gone(struct disk *dp, int flag);
>>
>> #define DISK_VERSION_00		0x58561059
>> #define DISK_VERSION_01		0x5856105a
>>
>> Modified: stable/9/sys/geom/geom_event.c
>> ==============================================================================
>> --- stable/9/sys/geom/geom_event.c	Fri Apr  5 11:30:31 2013	(r249151)
>> +++ stable/9/sys/geom/geom_event.c	Fri Apr  5 11:41:56 2013	(r249152)
>> @@ -202,14 +202,12 @@ g_orphan_register(struct g_provider *pp)
>> 	 * Tell all consumers the bad news.
>> 	 * Don't be surprised if they self-destruct.
>> 	 */
>> -	cp = LIST_FIRST(&pp->consumers);
>> -	while (cp != NULL) {
>> -		cp2 = LIST_NEXT(cp, consumers);
>> +	LIST_FOREACH_SAFE(cp, &pp->consumers, consumers, cp2) {
>> 		KASSERT(cp->geom->orphan != NULL,
>> 		    ("geom %s has no orphan, class %s",
>> 		    cp->geom->name, cp->geom->class->name));
>> +		cp->flags |= G_CF_ORPHAN;
>> 		cp->geom->orphan(cp);
>> -		cp = cp2;
>> 	}
>> 	if (LIST_EMPTY(&pp->consumers) && wf)
>> 		g_destroy_provider(pp);
>>
>> Modified: stable/9/sys/geom/geom_io.c
>> ==============================================================================
>> --- stable/9/sys/geom/geom_io.c	Fri Apr  5 11:30:31 2013	(r249151)
>> +++ stable/9/sys/geom/geom_io.c	Fri Apr  5 11:41:56 2013	(r249152)
>> @@ -311,6 +311,8 @@ g_io_check(struct bio *bp)
>> 	/* if provider is marked for error, don't disturb. */
>> 	if (pp->error)
>> 		return (pp->error);
>> +	if (cp->flags & G_CF_ORPHAN)
>> +		return (ENXIO);
>>
>> 	switch(bp->bio_cmd) {
>> 	case BIO_READ:
>>
>> Modified: stable/9/sys/geom/geom_slice.c
>> ==============================================================================
>> --- stable/9/sys/geom/geom_slice.c	Fri Apr  5 11:30:31 2013	(r249151)
>> +++ stable/9/sys/geom/geom_slice.c	Fri Apr  5 11:41:56 2013	(r249152)
>> @@ -465,6 +465,7 @@ g_slice_spoiled(struct g_consumer *cp)
>> 	g_topology_assert();
>> 	gp = cp->geom;
>> 	g_trace(G_T_TOPOLOGY, "g_slice_spoiled(%p/%s)", cp, gp->name);
>> +	cp->flags |= G_CF_ORPHAN;
>> 	gsp = gp->softc;
>> 	gp->softc = NULL;
>> 	g_slice_free(gsp);
>>
>> Modified: stable/9/sys/geom/geom_subr.c
>> ==============================================================================
>> --- stable/9/sys/geom/geom_subr.c	Fri Apr  5 11:30:31 2013	(r249151)
>> +++ stable/9/sys/geom/geom_subr.c	Fri Apr  5 11:41:56 2013	(r249152)
>> @@ -260,10 +260,11 @@ g_modevent(module_t mod, int type, void
>> static void
>> g_retaste_event(void *arg, int flag)
>> {
>> -	struct g_class *cp, *mp;
>> -	struct g_geom *gp, *gp2;
>> +	struct g_class *mp, *mp2;
>> +	struct g_geom *gp;
>> 	struct g_hh00 *hh;
>> 	struct g_provider *pp;
>> +	struct g_consumer *cp;
>>
>> 	g_topology_assert();
>> 	if (flag == EV_CANCEL)  /* XXX: can't happen ? */
>> @@ -280,17 +281,20 @@ g_retaste_event(void *arg, int flag)
>> 	}
>> 	g_trace(G_T_TOPOLOGY, "g_retaste(%s)", mp->name);
>>
>> -	LIST_FOREACH(cp, &g_classes, class) {
>> -		LIST_FOREACH(gp, &cp->geom, geom) {
>> +	LIST_FOREACH(mp2, &g_classes, class) {
>> +		LIST_FOREACH(gp, &mp2->geom, geom) {
>> 			LIST_FOREACH(pp, &gp->provider, provider) {
>> 				if (pp->acr || pp->acw || pp->ace)
>> 					continue;
>> -				LIST_FOREACH(gp2, &mp->geom, geom) {
>> -					if (!strcmp(pp->name, gp2->name))
>> +				LIST_FOREACH(cp, &pp->consumers, consumers) {
>> +					if (cp->geom->class == mp &&
>> +					    (cp->flags & G_CF_ORPHAN) == 0)
>> 						break;
>> 				}
>> -				if (gp2 != NULL)
>> -					g_wither_geom(gp2, ENXIO);
>> +				if (cp != NULL) {
>> +					cp->flags |= G_CF_ORPHAN;
>> +					g_wither_geom(cp->geom, ENXIO);
>> +				}
>> 				mp->taste(mp, pp, 0);
>> 				g_topology_assert();
>> 			}
>> @@ -531,7 +535,7 @@ g_new_provider_event(void *arg, int flag
>> {
>> 	struct g_class *mp;
>> 	struct g_provider *pp;
>> -	struct g_consumer *cp;
>> +	struct g_consumer *cp, *next_cp;
>>
>> 	g_topology_assert();
>> 	if (flag == EV_CANCEL)
>> @@ -542,11 +546,17 @@ g_new_provider_event(void *arg, int flag
>> 	G_VALID_PROVIDER(pp);
>> 	KASSERT(!(pp->flags & G_PF_WITHER),
>> 	    ("g_new_provider_event but withered"));
>> +	LIST_FOREACH_SAFE(cp, &pp->consumers, consumers, next_cp) {
>> +		if ((cp->flags & G_CF_ORPHAN) == 0 &&
>> +		    cp->geom->attrchanged != NULL)
>> +			cp->geom->attrchanged(cp, "GEOM::media");
>> +	}
>> 	LIST_FOREACH(mp, &g_classes, class) {
>> 		if (mp->taste == NULL)
>> 			continue;
>> 		LIST_FOREACH(cp, &pp->consumers, consumers)
>> -			if (cp->geom->class == mp)
>> +			if (cp->geom->class == mp &&
>> +			    (cp->flags & G_CF_ORPHAN) == 0)
>> 				break;
>> 		if (cp != NULL)
>> 			continue;
>> @@ -803,7 +813,7 @@ g_access(struct g_consumer *cp, int dcr,
>> 	 * are probably just ahead of the event telling us that.  Fail
>> 	 * now rather than having to unravel this later.
>> 	 */
>> -	if (cp->geom->spoiled != NULL && cp->spoiled &&
>> +	if (cp->geom->spoiled != NULL && (cp->flags & G_CF_SPOILED) &&
>> 	    (dcr > 0 || dcw > 0 || dce > 0))
>> 		return (ENXIO);
>>
>> @@ -953,6 +963,7 @@ g_std_spoiled(struct g_consumer *cp)
>> 	g_topology_assert();
>> 	G_VALID_CONSUMER(cp);
>> 	g_trace(G_T_TOPOLOGY, "g_std_spoiled(%p)", cp);
>> +	cp->flags |= G_CF_ORPHAN;
>> 	g_detach(cp);
>> 	gp = cp->geom;
>> 	LIST_FOREACH(pp, &gp->provider, provider)
>> @@ -988,9 +999,9 @@ g_spoil_event(void *arg, int flag)
>> 	G_VALID_PROVIDER(pp);
>> 	for (cp = LIST_FIRST(&pp->consumers); cp != NULL; cp = cp2) {
>> 		cp2 = LIST_NEXT(cp, consumers);
>> -		if (!cp->spoiled)
>> +		if ((cp->flags & G_CF_SPOILED) == 0)
>> 			continue;
>> -		cp->spoiled = 0;
>> +		cp->flags &= ~G_CF_SPOILED;
>> 		if (cp->geom->spoiled == NULL)
>> 			continue;
>> 		cp->geom->spoiled(cp);
>> @@ -1015,11 +1026,54 @@ g_spoil(struct g_provider *pp, struct g_
>> 		KASSERT(cp2->acw == 0, ("spoiling cp->acw = %d", cp2->acw));
>> */
>> 		KASSERT(cp2->ace == 0, ("spoiling cp->ace = %d", cp2->ace));
>> -		cp2->spoiled++;
>> +		cp2->flags |= G_CF_SPOILED;
>> 	}
>> 	g_post_event(g_spoil_event, pp, M_WAITOK, pp, NULL);
>> }
>>
>> +static void
>> +g_media_changed_event(void *arg, int flag)
>> +{
>> +	struct g_provider *pp;
>> +	int retaste;
>> +
>> +	g_topology_assert();
>> +	if (flag == EV_CANCEL)
>> +		return;
>> +	pp = arg;
>> +	G_VALID_PROVIDER(pp);
>> +
>> +	/*
>> +	 * If provider was not open for writing, queue retaste after spoiling.
>> +	 * If it was, retaste will happen automatically on close.
>> +	 */
>> +	retaste = (pp->acw == 0 && pp->error == 0 &&
>> +	    !(pp->geom->flags & G_GEOM_WITHER));
>> +	g_spoil_event(arg, flag);
>> +	if (retaste)
>> +		g_post_event(g_new_provider_event, pp, M_WAITOK, pp, NULL);
>> +}
>> +
>> +int
>> +g_media_changed(struct g_provider *pp, int flag)
>> +{
>> +	struct g_consumer *cp;
>> +
>> +	LIST_FOREACH(cp, &pp->consumers, consumers)
>> +		cp->flags |= G_CF_SPOILED;
>> +	return (g_post_event(g_media_changed_event, pp, flag, pp, NULL));
>> +}
>> +
>> +int
>> +g_media_gone(struct g_provider *pp, int flag)
>> +{
>> +	struct g_consumer *cp;
>> +
>> +	LIST_FOREACH(cp, &pp->consumers, consumers)
>> +		cp->flags |= G_CF_SPOILED;
>> +	return (g_post_event(g_spoil_event, pp, flag, pp, NULL));
>> +}
>> +
>> int
>> g_getattr__(const char *attr, struct g_consumer *cp, void *var, int len)
>> {
>> @@ -1175,15 +1229,15 @@ db_show_geom_consumer(int indent, struct
>> 			    cp->provider);
>> 		}
>> 		gprintln("  access:   r%dw%de%d", cp->acr, cp->acw, cp->ace);
>> -		gprintln("  spoiled:  %d", cp->spoiled);
>> +		gprintln("  flags:    0x%04x", cp->flags);
>> 		gprintln("  nstart:   %u", cp->nstart);
>> 		gprintln("  nend:     %u", cp->nend);
>> 	} else {
>> 		gprintf("consumer: %p (%s), access=r%dw%de%d", cp,
>> 		    cp->provider != NULL ? cp->provider->name : "none",
>> 		    cp->acr, cp->acw, cp->ace);
>> -		if (cp->spoiled)
>> -			db_printf(", spoiled=%d", cp->spoiled);
>> +		if (cp->flags)
>> +			db_printf(", flags=0x%04x", cp->flags);
>> 		db_printf("\n");
>> 	}
>> }
>>
>> Modified: stable/9/sys/geom/part/g_part.c
>> ==============================================================================
>> --- stable/9/sys/geom/part/g_part.c	Fri Apr  5 11:30:31 2013	(r249151)
>> +++ stable/9/sys/geom/part/g_part.c	Fri Apr  5 11:41:56 2013	(r249152)
>> @@ -2055,6 +2055,7 @@ g_part_spoiled(struct g_consumer *cp)
>> 	G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, cp->provider->name));
>> 	g_topology_assert();
>>
>> +	cp
>


-- 
Alexander Motin


More information about the svn-src-stable mailing list