Date: Thu, 12 Apr 2012 12:58:14 +0000 (UTC) From: Edward Tomasz Napierala <trasz@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r234177 - head/sys/cam/scsi Message-ID: <201204121258.q3CCwEVe029227@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: trasz Date: Thu Apr 12 12:58:14 2012 New Revision: 234177 URL: http://svn.freebsd.org/changeset/base/234177 Log: Refactor da(4) to remove one of two code paths used to query capacity data. Reviewed by: ken, mav (earlier version) Sponsored by: The FreeBSD Foundation Modified: head/sys/cam/scsi/scsi_da.c Modified: head/sys/cam/scsi/scsi_da.c ============================================================================== --- head/sys/cam/scsi/scsi_da.c Thu Apr 12 12:37:53 2012 (r234176) +++ head/sys/cam/scsi/scsi_da.c Thu Apr 12 12:58:14 2012 (r234177) @@ -83,7 +83,8 @@ typedef enum { DA_FLAG_RETRY_UA = 0x080, DA_FLAG_OPEN = 0x100, DA_FLAG_SCTX_INIT = 0x200, - DA_FLAG_CAN_RC16 = 0x400 + DA_FLAG_CAN_RC16 = 0x400, + DA_FLAG_PROBED = 0x800 } da_flags; typedef enum { @@ -829,7 +830,7 @@ static void dadone(struct cam_periph *p static int daerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags); static void daprevent(struct cam_periph *periph, int action); -static int dagetcapacity(struct cam_periph *periph); +static void dareprobe(struct cam_periph *periph); static void dasetgeom(struct cam_periph *periph, uint32_t block_len, uint64_t maxsector, struct scsi_read_capacity_data_long *rcaplong, @@ -929,36 +930,29 @@ daopen(struct disk *dp) softc->flags &= ~DA_FLAG_PACK_INVALID; } - error = dagetcapacity(periph); + dareprobe(periph); - if (error == 0) { - - softc->disk->d_sectorsize = softc->params.secsize; - softc->disk->d_mediasize = softc->params.secsize * (off_t)softc->params.sectors; - softc->disk->d_stripesize = softc->params.stripesize; - softc->disk->d_stripeoffset = softc->params.stripeoffset; - /* XXX: these are not actually "firmware" values, so they may be wrong */ - softc->disk->d_fwsectors = softc->params.secs_per_track; - softc->disk->d_fwheads = softc->params.heads; - softc->disk->d_devstat->block_size = softc->params.secsize; - softc->disk->d_devstat->flags &= ~DEVSTAT_BS_UNAVAILABLE; - if (softc->delete_method > DA_DELETE_DISABLE) - softc->disk->d_flags |= DISKFLAG_CANDELETE; - else - softc->disk->d_flags &= ~DISKFLAG_CANDELETE; - - if ((softc->flags & DA_FLAG_PACK_REMOVABLE) != 0 && - (softc->quirks & DA_Q_NO_PREVENT) == 0) - daprevent(periph, PR_PREVENT); - } else - softc->flags &= ~DA_FLAG_OPEN; + /* Wait for the disk size update. */ + error = msleep(&softc->disk->d_mediasize, periph->sim->mtx, PRIBIO, + "dareprobe", 0); + if (error != 0) + xpt_print(periph->path, "unable to retrieve capacity data"); + + if (periph->flags & CAM_PERIPH_INVALID) + error = ENXIO; + + if (error == 0 && (softc->flags & DA_FLAG_PACK_REMOVABLE) != 0 && + (softc->quirks & DA_Q_NO_PREVENT) == 0) + daprevent(periph, PR_PREVENT); cam_periph_unhold(periph); cam_periph_unlock(periph); if (error != 0) { + softc->flags &= ~DA_FLAG_OPEN; cam_periph_release(periph); } + return (error); } @@ -2364,7 +2358,7 @@ dadone(struct cam_periph *periph, union } } free(csio->data_ptr, M_SCSIDA); - if (announce_buf[0] != '\0') { + if (announce_buf[0] != '\0' && ((softc->flags & DA_FLAG_PROBED) == 0)) { /* * Create our sysctl variables, now that we know * we have successfully attached. @@ -2378,9 +2372,7 @@ dadone(struct cam_periph *periph, union xpt_print(periph->path, "fatal error, " "could not acquire reference count\n"); } - } - softc->state = DA_STATE_NORMAL; /* * Since our peripheral may be invalidated by an error * above or an external event, we must release our CCB @@ -2390,7 +2382,13 @@ dadone(struct cam_periph *periph, union * operation. */ xpt_release_ccb(done_ccb); - cam_periph_unhold(periph); + softc->state = DA_STATE_NORMAL; + wakeup(&softc->disk->d_mediasize); + if ((softc->flags & DA_FLAG_PROBED) == 0) { + softc->flags |= DA_FLAG_PROBED; + cam_periph_unhold(periph); + } else + cam_periph_release_locked(periph); return; } case DA_CCB_WAITING: @@ -2408,6 +2406,30 @@ dadone(struct cam_periph *periph, union xpt_release_ccb(done_ccb); } +static void +dareprobe(struct cam_periph *periph) +{ + struct da_softc *softc; + cam_status status; + + softc = (struct da_softc *)periph->softc; + + /* Probe in progress; don't interfere. */ + if ((softc->flags & DA_FLAG_PROBED) == 0) + return; + + status = cam_periph_acquire(periph); + KASSERT(status == CAM_REQ_CMP, + ("dareprobe: cam_periph_acquire failed")); + + if (softc->flags & DA_FLAG_CAN_RC16) + softc->state = DA_STATE_PROBE2; + else + softc->state = DA_STATE_PROBE; + + xpt_schedule(periph, CAM_PRIORITY_DEV); +} + static int daerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) { @@ -2437,6 +2459,16 @@ daerror(union ccb *ccb, u_int32_t cam_fl &error_code, &sense_key, &asc, &ascq); if (sense_key == SSD_KEY_ILLEGAL_REQUEST) error = cmd6workaround(ccb); + /* + * If the target replied with CAPACITY DATA HAS CHANGED UA, + * query the capacity and notify upper layers. + */ + else if (sense_key == SSD_KEY_UNIT_ATTENTION && + asc == 0x2A && ascq == 0x09) { + xpt_print(periph->path, "capacity data has changed\n"); + dareprobe(periph); + sense_flags |= SF_NO_PRINT; + } } if (error == ERESTART) return (ERESTART); @@ -2490,164 +2522,6 @@ daprevent(struct cam_periph *periph, int xpt_release_ccb(ccb); } -static int -dagetcapacity(struct cam_periph *periph) -{ - struct da_softc *softc; - union ccb *ccb; - struct scsi_read_capacity_data *rcap; - struct scsi_read_capacity_data_long *rcaplong; - uint32_t block_len; - uint64_t maxsector; - int error, rc16failed; - u_int32_t sense_flags; - u_int lbppbe; /* Logical blocks per physical block exponent. */ - u_int lalba; /* Lowest aligned LBA. */ - - softc = (struct da_softc *)periph->softc; - block_len = 0; - maxsector = 0; - lbppbe = 0; - lalba = 0; - error = 0; - rc16failed = 0; - rcaplong = NULL; - sense_flags = SF_RETRY_UA; - if (softc->flags & DA_FLAG_PACK_REMOVABLE) - sense_flags |= SF_NO_PRINT; - - /* Do a read capacity */ - rcap = (struct scsi_read_capacity_data *)malloc(sizeof(*rcaplong), - M_SCSIDA, - M_NOWAIT | M_ZERO); - if (rcap == NULL) - return (ENOMEM); - rcaplong = (struct scsi_read_capacity_data_long *)rcap; - - ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); - - /* Try READ CAPACITY(16) first if we think it should work. */ - if (softc->flags & DA_FLAG_CAN_RC16) { - scsi_read_capacity_16(&ccb->csio, - /*retries*/ 4, - /*cbfcnp*/ dadone, - /*tag_action*/ MSG_SIMPLE_Q_TAG, - /*lba*/ 0, - /*reladr*/ 0, - /*pmi*/ 0, - /*rcap_buf*/ (uint8_t *)rcaplong, - /*rcap_buf_len*/ sizeof(*rcaplong), - /*sense_len*/ SSD_FULL_SIZE, - /*timeout*/ 60000); - ccb->ccb_h.ccb_bp = NULL; - - error = cam_periph_runccb(ccb, daerror, - /*cam_flags*/CAM_RETRY_SELTO, - sense_flags, softc->disk->d_devstat); - if (error == 0) - goto rc16ok; - - /* If we got ILLEGAL REQUEST, do not prefer RC16 any more. */ - if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INVALID) { - softc->flags &= ~DA_FLAG_CAN_RC16; - } else if (((ccb->ccb_h.status & CAM_STATUS_MASK) == - CAM_SCSI_STATUS_ERROR) - && (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND) - && (ccb->ccb_h.status & CAM_AUTOSNS_VALID) - && ((ccb->ccb_h.flags & CAM_SENSE_PHYS) == 0) - && ((ccb->ccb_h.flags & CAM_SENSE_PTR) == 0)) { - int sense_key, error_code, asc, ascq; - - scsi_extract_sense_len(&ccb->csio.sense_data, - ccb->csio.sense_len - - ccb->csio.sense_resid, - &error_code, &sense_key, - &asc, &ascq, /*show_errors*/1); - /* - * If we don't have enough sense to get the sense - * key, or if it's illegal request, turn off - * READ CAPACITY (16). - */ - if ((sense_key == -1) - || (sense_key == SSD_KEY_ILLEGAL_REQUEST)) - softc->flags &= ~DA_FLAG_CAN_RC16; - } - rc16failed = 1; - } - - /* Do READ CAPACITY(10). */ - scsi_read_capacity(&ccb->csio, - /*retries*/4, - /*cbfncp*/dadone, - MSG_SIMPLE_Q_TAG, - rcap, - SSD_FULL_SIZE, - /*timeout*/60000); - ccb->ccb_h.ccb_bp = NULL; - - error = cam_periph_runccb(ccb, daerror, - /*cam_flags*/CAM_RETRY_SELTO, - sense_flags, - softc->disk->d_devstat); - if (error == 0) { - block_len = scsi_4btoul(rcap->length); - maxsector = scsi_4btoul(rcap->addr); - - if (maxsector != 0xffffffff || rc16failed) - goto done; - } else - goto done; - - /* If READ CAPACITY(10) returned overflow, use READ CAPACITY(16) */ - scsi_read_capacity_16(&ccb->csio, - /*retries*/ 4, - /*cbfcnp*/ dadone, - /*tag_action*/ MSG_SIMPLE_Q_TAG, - /*lba*/ 0, - /*reladr*/ 0, - /*pmi*/ 0, - /*rcap_buf*/ (uint8_t *)rcaplong, - /*rcap_buf_len*/ sizeof(*rcaplong), - /*sense_len*/ SSD_FULL_SIZE, - /*timeout*/ 60000); - ccb->ccb_h.ccb_bp = NULL; - - error = cam_periph_runccb(ccb, daerror, - /*cam_flags*/CAM_RETRY_SELTO, - sense_flags, - softc->disk->d_devstat); - if (error == 0) { -rc16ok: - block_len = scsi_4btoul(rcaplong->length); - maxsector = scsi_8btou64(rcaplong->addr); - lbppbe = rcaplong->prot_lbppbe & SRC16_LBPPBE; - lalba = scsi_2btoul(rcaplong->lalba_lbp); - } - -done: - - if (error == 0) { - if (block_len >= MAXPHYS || block_len == 0) { - xpt_print(periph->path, - "unsupportable block size %ju\n", - (uintmax_t) block_len); - error = EINVAL; - } else { - dasetgeom(periph, block_len, maxsector, - rcaplong, sizeof(*rcaplong)); - if ((lalba & SRC16_LBPME) - && softc->delete_method == DA_DELETE_NONE) - softc->delete_method = DA_DELETE_UNMAP; - } - } - - xpt_release_ccb(ccb); - - free(rcap, M_SCSIDA); - - return (error); -} - static void dasetgeom(struct cam_periph *periph, uint32_t block_len, uint64_t maxsector, struct scsi_read_capacity_data_long *rcaplong, size_t rcap_len) @@ -2747,6 +2621,20 @@ dasetgeom(struct cam_periph *periph, uin min(sizeof(softc->rcaplong), rcap_len)); } } + + softc->disk->d_sectorsize = softc->params.secsize; + softc->disk->d_mediasize = softc->params.secsize * (off_t)softc->params.sectors; + softc->disk->d_stripesize = softc->params.stripesize; + softc->disk->d_stripeoffset = softc->params.stripeoffset; + /* XXX: these are not actually "firmware" values, so they may be wrong */ + softc->disk->d_fwsectors = softc->params.secs_per_track; + softc->disk->d_fwheads = softc->params.heads; + softc->disk->d_devstat->block_size = softc->params.secsize; + softc->disk->d_devstat->flags &= ~DEVSTAT_BS_UNAVAILABLE; + if (softc->delete_method > DA_DELETE_DISABLE) + softc->disk->d_flags |= DISKFLAG_CANDELETE; + else + softc->disk->d_flags &= ~DISKFLAG_CANDELETE; } static void
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201204121258.q3CCwEVe029227>