From owner-svn-src-stable@freebsd.org Fri Sep 13 15:17:31 2019 Return-Path: Delivered-To: svn-src-stable@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 2615FF3F8D; Fri, 13 Sep 2019 15:17:31 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 46VK4q0yYNz3Hq4; Fri, 13 Sep 2019 15:17:31 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 0431790A3; Fri, 13 Sep 2019 15:17:31 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x8DFHUOc045461; Fri, 13 Sep 2019 15:17:31 GMT (envelope-from mav@FreeBSD.org) Received: (from mav@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x8DFHUYC045460; Fri, 13 Sep 2019 15:17:30 GMT (envelope-from mav@FreeBSD.org) Message-Id: <201909131517.x8DFHUYC045460@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: mav set sender to mav@FreeBSD.org using -f From: Alexander Motin Date: Fri, 13 Sep 2019 15:17:30 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r352291 - stable/11/sbin/camcontrol X-SVN-Group: stable-11 X-SVN-Commit-Author: mav X-SVN-Commit-Paths: stable/11/sbin/camcontrol X-SVN-Commit-Revision: 352291 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 13 Sep 2019 15:17:31 -0000 Author: mav Date: Fri Sep 13 15:17:30 2019 New Revision: 352291 URL: https://svnweb.freebsd.org/changeset/base/352291 Log: MFC r352082, r352103: Fix number of problems found while testing on SAT devices. - Remove incomplete and dangerous ata_res decoding from ata_do_cmd(). Instead switch all functions that need the result to use get_ata_status(), doing the same, but more careful, also reducing code duplication. - Made get_ata_status() to also decode fixed format sense. In many cases it is still not enough to make it useful, since it can only report results of 28-bit command, but it is slightly better then nothing. - Organize error reporting in ata_do_cmd(), so that if caller specified AP_FLAG_CHK_COND, it is responsible for command errors (non-ioctl ones). - Make HPA/AMA errors not fatal for `identify` subcommand. - Fix reprobe() not being called on HPA/AMA when in quiet mode. - Remove not very useful messages from `format` and `sanitize` commands with -y flag. Once they started, they often can't be stopped any way. Modified: stable/11/sbin/camcontrol/camcontrol.c Directory Properties: stable/11/ (props changed) Modified: stable/11/sbin/camcontrol/camcontrol.c ============================================================================== --- stable/11/sbin/camcontrol/camcontrol.c Fri Sep 13 15:15:58 2019 (r352290) +++ stable/11/sbin/camcontrol/camcontrol.c Fri Sep 13 15:17:30 2019 (r352291) @@ -1603,7 +1603,7 @@ atacapprint(struct ata_params *parm) } static int -scsi_cam_pass_16_send(struct cam_device *device, union ccb *ccb, int quiet) +scsi_cam_pass_16_send(struct cam_device *device, union ccb *ccb) { struct ata_pass_16 *ata_pass_16; struct ata_cmd ata_cmd; @@ -1626,24 +1626,21 @@ scsi_cam_pass_16_send(struct cam_device *device, union ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; if (cam_send_ccb(device, ccb) < 0) { - if (quiet != 1 || arglist & CAM_ARG_VERBOSE) { - warn("error sending ATA %s via pass_16", - ata_op_string(&ata_cmd)); - } + warn("error sending ATA %s via pass_16", ata_op_string(&ata_cmd)); return (1); } + /* + * Consider any non-CAM_REQ_CMP status as error and report it here, + * unless caller set AP_FLAG_CHK_COND, in which case it is reponsible. + */ if (!(ata_pass_16->flags & AP_FLAG_CHK_COND) && (ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { - if (quiet != 1 || arglist & CAM_ARG_VERBOSE) { - warnx("ATA %s via pass_16 failed", - ata_op_string(&ata_cmd)); - } + warnx("ATA %s via pass_16 failed", ata_op_string(&ata_cmd)); if (arglist & CAM_ARG_VERBOSE) { cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); } - return (1); } @@ -1652,7 +1649,7 @@ scsi_cam_pass_16_send(struct cam_device *device, union static int -ata_cam_send(struct cam_device *device, union ccb *ccb, int quiet) +ata_cam_send(struct cam_device *device, union ccb *ccb) { if (arglist & CAM_ARG_VERBOSE) { warnx("sending ATA %s with timeout of %u msecs", @@ -1667,24 +1664,21 @@ ata_cam_send(struct cam_device *device, union ccb *ccb ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; if (cam_send_ccb(device, ccb) < 0) { - if (quiet != 1 || arglist & CAM_ARG_VERBOSE) { - warn("error sending ATA %s", - ata_op_string(&(ccb->ataio.cmd))); - } + warn("error sending ATA %s", ata_op_string(&(ccb->ataio.cmd))); return (1); } - if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { - if (quiet != 1 || arglist & CAM_ARG_VERBOSE) { - warnx("ATA %s failed: %d", - ata_op_string(&(ccb->ataio.cmd)), quiet); - } - + /* + * Consider any non-CAM_REQ_CMP status as error and report it here, + * unless caller set AP_FLAG_CHK_COND, in which case it is reponsible. + */ + if (!(ccb->ataio.cmd.flags & CAM_ATAIO_NEEDRESULT) && + (ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { + warnx("ATA %s failed", ata_op_string(&(ccb->ataio.cmd))); if (arglist & CAM_ARG_VERBOSE) { cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); } - return (1); } @@ -1696,7 +1690,7 @@ ata_do_pass_16(struct cam_device *device, union ccb *c u_int32_t flags, u_int8_t protocol, u_int8_t ata_flags, u_int8_t tag_action, u_int8_t command, u_int16_t features, u_int64_t lba, u_int16_t sector_count, u_int8_t *data_ptr, - u_int16_t dxfer_len, int timeout, int quiet) + u_int16_t dxfer_len, int timeout) { if (data_ptr != NULL) { if (flags & CAM_DIR_OUT) @@ -1726,7 +1720,7 @@ ata_do_pass_16(struct cam_device *device, union ccb *c /*sense_len*/SSD_FULL_SIZE, timeout); - return scsi_cam_pass_16_send(device, ccb, quiet); + return scsi_cam_pass_16_send(device, ccb); } static int @@ -1762,50 +1756,10 @@ ata_do_cmd(struct cam_device *device, union ccb *ccb, return (1); if (retval == 1) { - int error; - - /* Try using SCSI Passthrough */ - error = ata_do_pass_16(device, ccb, retries, flags, protocol, + return (ata_do_pass_16(device, ccb, retries, flags, protocol, ata_flags, tag_action, command, features, lba, sector_count, data_ptr, dxfer_len, - timeout, 0); - - if (ata_flags & AP_FLAG_CHK_COND) { - /* Decode ata_res from sense data */ - struct ata_res_pass16 *res_pass16; - struct ata_res *res; - u_int i; - u_int16_t *ptr; - - /* sense_data is 4 byte aligned */ - ptr = (uint16_t*)(uintptr_t)&ccb->csio.sense_data; - for (i = 0; i < sizeof(*res_pass16) / 2; i++) - ptr[i] = le16toh(ptr[i]); - - /* sense_data is 4 byte aligned */ - res_pass16 = (struct ata_res_pass16 *)(uintptr_t) - &ccb->csio.sense_data; - res = &ccb->ataio.res; - res->flags = res_pass16->flags; - res->status = res_pass16->status; - res->error = res_pass16->error; - res->lba_low = res_pass16->lba_low; - res->lba_mid = res_pass16->lba_mid; - res->lba_high = res_pass16->lba_high; - res->device = res_pass16->device; - res->lba_low_exp = res_pass16->lba_low_exp; - res->lba_mid_exp = res_pass16->lba_mid_exp; - res->lba_high_exp = res_pass16->lba_high_exp; - res->sector_count = res_pass16->sector_count; - res->sector_count_exp = res_pass16->sector_count_exp; - ccb->ccb_h.status &= ~CAM_STATUS_MASK; - if (res->status & ATA_STATUS_ERROR) - ccb->ccb_h.status |= CAM_ATA_STATUS_ERROR; - else - ccb->ccb_h.status |= CAM_REQ_CMP; - } - - return (error); + timeout)); } CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->ataio); @@ -1826,7 +1780,7 @@ ata_do_cmd(struct cam_device *device, union ccb *ccb, if (ata_flags & AP_FLAG_CHK_COND) ccb->ataio.cmd.flags |= CAM_ATAIO_NEEDRESULT; - return ata_cam_send(device, ccb, 0); + return ata_cam_send(device, ccb); } static void @@ -1846,52 +1800,43 @@ dump_data(uint16_t *ptr, uint32_t len) } static int -atahpa_proc_resp(struct cam_device *device, union ccb *ccb, - int is48bit, u_int64_t *hpasize) +atahpa_proc_resp(struct cam_device *device, union ccb *ccb, u_int64_t *hpasize) { - struct ata_res *res; + uint8_t error = 0, ata_device = 0, status = 0; + uint16_t count = 0; + uint64_t lba = 0; + int retval; - res = &ccb->ataio.res; - if (res->status & ATA_STATUS_ERROR) { + retval = get_ata_status(device, ccb, &error, &count, &lba, &ata_device, + &status); + if (retval == 1) { if (arglist & CAM_ARG_VERBOSE) { cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); - printf("error = 0x%02x, sector_count = 0x%04x, " - "device = 0x%02x, status = 0x%02x\n", - res->error, res->sector_count, - res->device, res->status); } + warnx("Can't get ATA command status"); + return (retval); + } - if (res->error & ATA_ERROR_ID_NOT_FOUND) { + if (status & ATA_STATUS_ERROR) { + if (arglist & CAM_ARG_VERBOSE) { + cam_error_print(device, ccb, CAM_ESF_ALL, + CAM_EPF_ALL, stderr); + } + + if (error & ATA_ERROR_ID_NOT_FOUND) { warnx("Max address has already been set since " "last power-on or hardware reset"); - } + } else if (hpasize == NULL) + warnx("Command failed with ATA error"); return (1); } - if (arglist & CAM_ARG_VERBOSE) { - fprintf(stdout, "%s%d: Raw native max data:\n", - device->device_name, device->dev_unit_num); - /* res is 4 byte aligned */ - dump_data((uint16_t*)(uintptr_t)res, sizeof(struct ata_res)); - - printf("error = 0x%02x, sector_count = 0x%04x, device = 0x%02x, " - "status = 0x%02x\n", res->error, res->sector_count, - res->device, res->status); - } - if (hpasize != NULL) { - if (is48bit) { - *hpasize = (((u_int64_t)((res->lba_high_exp << 16) | - (res->lba_mid_exp << 8) | res->lba_low_exp) << 24) | - ((res->lba_high << 16) | (res->lba_mid << 8) | - res->lba_low)) + 1; - } else { - *hpasize = (((res->device & 0x0f) << 24) | - (res->lba_high << 16) | (res->lba_mid << 8) | - res->lba_low) + 1; - } + if (retval == 2 || retval == 6) + return (1); + *hpasize = lba; } return (0); @@ -1935,7 +1880,7 @@ ata_read_native_max(struct cam_device *device, int ret if (error) return (error); - return atahpa_proc_resp(device, ccb, is48bit, hpasize); + return atahpa_proc_resp(device, ccb, hpasize); } static int @@ -1979,7 +1924,7 @@ atahpa_set_max(struct cam_device *device, int retry_co if (error) return (error); - return atahpa_proc_resp(device, ccb, is48bit, NULL); + return atahpa_proc_resp(device, ccb, NULL); } static int @@ -1987,20 +1932,19 @@ atahpa_password(struct cam_device *device, int retry_c u_int32_t timeout, union ccb *ccb, int is48bit, struct ata_set_max_pwd *pwd) { - int error; u_int cmd; u_int8_t protocol; protocol = AP_PROTO_PIO_OUT; cmd = (is48bit) ? ATA_SET_MAX_ADDRESS48 : ATA_SET_MAX_ADDRESS; - error = ata_do_cmd(device, + return (ata_do_cmd(device, ccb, retry_count, /*flags*/CAM_DIR_OUT, /*protocol*/protocol, /*ata_flags*/AP_FLAG_BYT_BLOK_BLOCKS | - AP_FLAG_TLEN_SECT_CNT | AP_FLAG_CHK_COND, + AP_FLAG_TLEN_SECT_CNT, /*tag_action*/MSG_SIMPLE_Q_TAG, /*command*/cmd, /*features*/ATA_HPA_FEAT_SET_PWD, @@ -2009,31 +1953,25 @@ atahpa_password(struct cam_device *device, int retry_c /*data_ptr*/(u_int8_t*)pwd, /*dxfer_len*/sizeof(*pwd), timeout ? timeout : 1000, - is48bit); - - if (error) - return (error); - - return atahpa_proc_resp(device, ccb, is48bit, NULL); + is48bit)); } static int atahpa_lock(struct cam_device *device, int retry_count, u_int32_t timeout, union ccb *ccb, int is48bit) { - int error; u_int cmd; u_int8_t protocol; protocol = AP_PROTO_NON_DATA; cmd = (is48bit) ? ATA_SET_MAX_ADDRESS48 : ATA_SET_MAX_ADDRESS; - error = ata_do_cmd(device, + return (ata_do_cmd(device, ccb, retry_count, /*flags*/CAM_DIR_NONE, /*protocol*/protocol, - /*ata_flags*/AP_FLAG_CHK_COND, + /*ata_flags*/0, /*tag_action*/MSG_SIMPLE_Q_TAG, /*command*/cmd, /*features*/ATA_HPA_FEAT_LOCK, @@ -2042,12 +1980,7 @@ atahpa_lock(struct cam_device *device, int retry_count /*data_ptr*/NULL, /*dxfer_len*/0, timeout ? timeout : 1000, - is48bit); - - if (error) - return (error); - - return atahpa_proc_resp(device, ccb, is48bit, NULL); + is48bit)); } static int @@ -2055,20 +1988,19 @@ atahpa_unlock(struct cam_device *device, int retry_cou u_int32_t timeout, union ccb *ccb, int is48bit, struct ata_set_max_pwd *pwd) { - int error; u_int cmd; u_int8_t protocol; protocol = AP_PROTO_PIO_OUT; cmd = (is48bit) ? ATA_SET_MAX_ADDRESS48 : ATA_SET_MAX_ADDRESS; - error = ata_do_cmd(device, + return (ata_do_cmd(device, ccb, retry_count, /*flags*/CAM_DIR_OUT, /*protocol*/protocol, /*ata_flags*/AP_FLAG_BYT_BLOK_BLOCKS | - AP_FLAG_TLEN_SECT_CNT | AP_FLAG_CHK_COND, + AP_FLAG_TLEN_SECT_CNT, /*tag_action*/MSG_SIMPLE_Q_TAG, /*command*/cmd, /*features*/ATA_HPA_FEAT_UNLOCK, @@ -2077,31 +2009,25 @@ atahpa_unlock(struct cam_device *device, int retry_cou /*data_ptr*/(u_int8_t*)pwd, /*dxfer_len*/sizeof(*pwd), timeout ? timeout : 1000, - is48bit); - - if (error) - return (error); - - return atahpa_proc_resp(device, ccb, is48bit, NULL); + is48bit)); } static int atahpa_freeze_lock(struct cam_device *device, int retry_count, u_int32_t timeout, union ccb *ccb, int is48bit) { - int error; u_int cmd; u_int8_t protocol; protocol = AP_PROTO_NON_DATA; cmd = (is48bit) ? ATA_SET_MAX_ADDRESS48 : ATA_SET_MAX_ADDRESS; - error = ata_do_cmd(device, + return (ata_do_cmd(device, ccb, retry_count, /*flags*/CAM_DIR_NONE, /*protocol*/protocol, - /*ata_flags*/AP_FLAG_CHK_COND, + /*ata_flags*/0, /*tag_action*/MSG_SIMPLE_Q_TAG, /*command*/cmd, /*features*/ATA_HPA_FEAT_FREEZE, @@ -2110,12 +2036,7 @@ atahpa_freeze_lock(struct cam_device *device, int retr /*data_ptr*/NULL, /*dxfer_len*/0, timeout ? timeout : 1000, - is48bit); - - if (error) - return (error); - - return atahpa_proc_resp(device, ccb, is48bit, NULL); + is48bit)); } static int @@ -2144,7 +2065,7 @@ ata_get_native_max(struct cam_device *device, int retr if (error) return (error); - return atahpa_proc_resp(device, ccb, /*is48bit*/1, nativesize); + return atahpa_proc_resp(device, ccb, nativesize); } static int @@ -2176,21 +2097,20 @@ ataama_set(struct cam_device *device, int retry_count, if (error) return (error); - return atahpa_proc_resp(device, ccb, /*is48bit*/1, NULL); + return atahpa_proc_resp(device, ccb, NULL); } static int ataama_freeze(struct cam_device *device, int retry_count, u_int32_t timeout, union ccb *ccb) { - int error; - error = ata_do_cmd(device, + return (ata_do_cmd(device, ccb, retry_count, /*flags*/CAM_DIR_NONE, /*protocol*/AP_PROTO_NON_DATA | AP_EXTEND, - /*ata_flags*/AP_FLAG_CHK_COND, + /*ata_flags*/0, /*tag_action*/MSG_SIMPLE_Q_TAG, /*command*/ATA_AMAX_ADDR, /*features*/ATA_AMAX_ADDR_FREEZE, @@ -2199,12 +2119,7 @@ ataama_freeze(struct cam_device *device, int retry_cou /*data_ptr*/NULL, /*dxfer_len*/0, timeout ? timeout : 30 * 1000, - /*force48bit*/1); - - if (error) - return (error); - - return atahpa_proc_resp(device, ccb, /*is48bit*/1, NULL); + /*force48bit*/1)); } int @@ -2318,7 +2233,7 @@ ataidentify(struct cam_device *device, int retry_count { union ccb *ccb; struct ata_params *ident_buf; - u_int64_t hpasize, nativesize; + u_int64_t hpasize = 0, nativesize = 0; if ((ccb = cam_getccb(device)) == NULL) { warnx("couldn't allocate CCB"); @@ -2337,22 +2252,12 @@ ataidentify(struct cam_device *device, int retry_count } if (ident_buf->support.command1 & ATA_SUPPORT_PROTECTED) { - if (ata_read_native_max(device, retry_count, timeout, ccb, - ident_buf, &hpasize) != 0) { - cam_freeccb(ccb); - return (1); - } - } else { - hpasize = 0; + ata_read_native_max(device, retry_count, timeout, ccb, + ident_buf, &hpasize); } if (ident_buf->support2 & ATA_SUPPORT_AMAX_ADDR) { - if (ata_get_native_max(device, retry_count, timeout, ccb, - &nativesize) != 0) { - cam_freeccb(ccb); - return (1); - } - } else { - nativesize = 0; + ata_get_native_max(device, retry_count, timeout, ccb, + &nativesize); } printf("%s%d: ", device->device_name, device->dev_unit_num); @@ -2843,10 +2748,11 @@ atahpa(struct cam_device *device, int retry_count, int } if (action == ATA_HPA_ACTION_PRINT) { - error = ata_read_native_max(device, retry_count, timeout, ccb, - ident_buf, &hpasize); - if (error == 0) - atahpa_print(ident_buf, hpasize, 1); + hpasize = 0; + if (ident_buf->support.command1 & ATA_SUPPORT_PROTECTED) + ata_read_native_max(device, retry_count, timeout, ccb, + ident_buf, &hpasize); + atahpa_print(ident_buf, hpasize, 1); cam_freeccb(ccb); free(ident_buf); @@ -2889,12 +2795,14 @@ atahpa(struct cam_device *device, int retry_count, int if (error == 0) { error = atahpa_set_max(device, retry_count, timeout, ccb, is48bit, maxsize, persist); - if (error == 0 && quiet == 0) { - /* redo identify to get new lba values */ - error = ata_do_identify(device, retry_count, - timeout, ccb, - &ident_buf); - atahpa_print(ident_buf, hpasize, 1); + if (error == 0) { + if (quiet == 0) { + /* redo identify to get new values */ + error = ata_do_identify(device, + retry_count, timeout, ccb, + &ident_buf); + atahpa_print(ident_buf, hpasize, 1); + } /* Hint CAM to reprobe the device. */ reprobe(device); } @@ -3010,10 +2918,11 @@ ataama(struct cam_device *device, int retry_count, int } if (action == ATA_AMA_ACTION_PRINT) { - error = ata_get_native_max(device, retry_count, timeout, ccb, + nativesize = 0; + if (ident_buf->support2 & ATA_SUPPORT_AMAX_ADDR) + ata_get_native_max(device, retry_count, timeout, ccb, &nativesize); - if (error == 0) - ataama_print(ident_buf, nativesize, 1); + ataama_print(ident_buf, nativesize, 1); cam_freeccb(ccb); free(ident_buf); @@ -3034,11 +2943,14 @@ ataama(struct cam_device *device, int retry_count, int if (error == 0) { error = ataama_set(device, retry_count, timeout, ccb, maxsize); - if (error == 0 && quiet == 0) { - /* redo identify to get new lba values */ - error = ata_do_identify(device, retry_count, - timeout, ccb, &ident_buf); - ataama_print(ident_buf, nativesize, 1); + if (error == 0) { + if (quiet == 0) { + /* redo identify to get new values */ + error = ata_do_identify(device, + retry_count, timeout, ccb, + &ident_buf); + ataama_print(ident_buf, nativesize, 1); + } /* Hint CAM to reprobe the device. */ reprobe(device); } @@ -5552,16 +5464,21 @@ build_ata_cmd(union ccb *ccb, uint32_t retry_count, ui return (retval); } +/* + * Returns: 0 -- success, 1 -- error, 2 -- lba truncated, + * 4 -- count truncated, 6 -- lba and count truncated. + */ int get_ata_status(struct cam_device *dev, union ccb *ccb, uint8_t *error, uint16_t *count, uint64_t *lba, uint8_t *device, uint8_t *status) { - int retval = 0; + int retval; switch (ccb->ccb_h.func_code) { case XPT_SCSI_IO: { uint8_t opcode; int error_code = 0, sense_key = 0, asc = 0, ascq = 0; + u_int sense_len; /* * In this case, we have SCSI ATA PASS-THROUGH command, 12 @@ -5573,20 +5490,17 @@ get_ata_status(struct cam_device *dev, union ccb *ccb, opcode = ccb->csio.cdb_io.cdb_bytes[0]; if ((opcode != ATA_PASS_12) && (opcode != ATA_PASS_16)) { - retval = 1; warnx("%s: unsupported opcode %02x", __func__, opcode); - goto bailout; + return (1); } retval = scsi_extract_sense_ccb(ccb, &error_code, &sense_key, &asc, &ascq); /* Note: the _ccb() variant returns 0 for an error */ - if (retval == 0) { - retval = 1; - goto bailout; - } else - retval = 0; + if (retval == 0) + return (1); + sense_len = ccb->csio.sense_len - ccb->csio.sense_resid; switch (error_code) { case SSD_DESC_CURRENT_ERROR: case SSD_DESC_DEFERRED_ERROR: { @@ -5597,13 +5511,12 @@ get_ata_status(struct cam_device *dev, union ccb *ccb, sense = (struct scsi_sense_data_desc *) &ccb->csio.sense_data; - desc_ptr = scsi_find_desc(sense, ccb->csio.sense_len - - ccb->csio.sense_resid, SSD_DESC_ATA); + desc_ptr = scsi_find_desc(sense, sense_len, + SSD_DESC_ATA); if (desc_ptr == NULL) { cam_error_print(dev, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); - retval = 1; - goto bailout; + return (1); } desc = (struct scsi_sense_ata_ret_desc *)desc_ptr; @@ -5635,22 +5548,47 @@ get_ata_status(struct cam_device *dev, union ccb *ccb, } case SSD_CURRENT_ERROR: case SSD_DEFERRED_ERROR: { -#if 0 - struct scsi_sense_data_fixed *sense; -#endif + uint64_t val; + /* - * XXX KDM need to support fixed sense data. + * In my understanding of SAT-5 specification, saying: + * "without interpreting the contents of the STATUS", + * this should not happen if CK_COND was set, but it + * does at least for some devices, so try to revert. */ - warnx("%s: Fixed sense data not supported yet", - __func__); - retval = 1; - goto bailout; - break; /*NOTREACHED*/ + if ((sense_key == SSD_KEY_ABORTED_COMMAND) && + (asc == 0) && (ascq == 0)) { + *status = ATA_STATUS_ERROR; + *error = ATA_ERROR_ABORT; + *device = 0; + *count = 0; + *lba = 0; + return (0); + } + + if ((sense_key != SSD_KEY_RECOVERED_ERROR) || + (asc != 0x00) || (ascq != 0x1d)) + return (1); + + val = 0; + scsi_get_sense_info(&ccb->csio.sense_data, sense_len, + SSD_DESC_INFO, &val, NULL); + *error = (val >> 24) & 0xff; + *status = (val >> 16) & 0xff; + *device = (val >> 8) & 0xff; + *count = val & 0xff; + + val = 0; + scsi_get_sense_info(&ccb->csio.sense_data, sense_len, + SSD_DESC_COMMAND, &val, NULL); + *lba = ((val >> 16) & 0xff) | (val & 0xff00) | + ((val & 0xff) << 16); + + /* Report UPPER NONZERO bits as errors 2, 4 and 6. */ + return ((val >> 28) & 0x06); } default: - retval = 1; - goto bailout; - break; + return (1); } break; @@ -5658,11 +5596,11 @@ get_ata_status(struct cam_device *dev, union ccb *ccb, case XPT_ATA_IO: { struct ata_res *res; - /* - * In this case, we have an ATA command, and we need to - * fill in the requested values from the result register - * set. - */ + /* Only some statuses return ATA result register set. */ + if (cam_ccb_status(ccb) != CAM_REQ_CMP && + cam_ccb_status(ccb) != CAM_ATA_STATUS_ERROR) + return (1); + res = &ccb->ataio.res; *error = res->error; *status = res->status; @@ -5671,7 +5609,7 @@ get_ata_status(struct cam_device *dev, union ccb *ccb, *lba = (res->lba_high << 16) | (res->lba_mid << 8) | (res->lba_low); - if (res->flags & CAM_ATAIO_48BIT) { + if (ccb->ataio.cmd.flags & CAM_ATAIO_48BIT) { *count |= (res->sector_count_exp << 8); *lba |= ((uint64_t)res->lba_low_exp << 24) | ((uint64_t)res->lba_mid_exp << 32) | @@ -5682,11 +5620,9 @@ get_ata_status(struct cam_device *dev, union ccb *ccb, break; } default: - retval = 1; - break; + return (1); } -bailout: - return (retval); + return (0); } static void @@ -6284,7 +6220,7 @@ scsiformat(struct cam_device *device, int argc, char * if (reportonly) goto doreport; - if (quiet == 0) { + if (quiet == 0 && ycount == 0) { fprintf(stdout, "You are about to REMOVE ALL DATA from the " "following device:\n"); @@ -6525,66 +6461,78 @@ scsiformat_bailout: } static int -sanitize_wait_ata(struct cam_device *device, union ccb *ccb, int quiet) +sanitize_wait_ata(struct cam_device *device, union ccb *ccb, int quiet, + camcontrol_devtype devtype) { - struct ata_res *res; int retval; - cam_status status; + uint8_t error = 0, ata_device = 0, status = 0; + uint16_t count = 0; + uint64_t lba = 0; u_int val, perc; do { - retval = ata_do_cmd(device, - ccb, - /*retries*/1, - /*flags*/CAM_DIR_NONE, - /*protocol*/AP_PROTO_NON_DATA | AP_EXTEND, - /*ata_flags*/AP_FLAG_CHK_COND, - /*tag_action*/MSG_SIMPLE_Q_TAG, - /*command*/ATA_SANITIZE, - /*features*/0x00, /* SANITIZE STATUS EXT */ - /*lba*/0, - /*sector_count*/0, - /*data_ptr*/NULL, - /*dxfer_len*/0, - /*timeout*/10000, - /*is48bit*/1); - if (retval < 0) { - warn("error sending CAMIOCOMMAND ioctl"); - if (arglist & CAM_ARG_VERBOSE) { - cam_error_print(device, ccb, CAM_ESF_ALL, - CAM_EPF_ALL, stderr); - } + retval = build_ata_cmd(ccb, + /*retries*/ 0, + /*flags*/ CAM_DIR_NONE, + /*tag_action*/ MSG_SIMPLE_Q_TAG, + /*protocol*/ AP_PROTO_NON_DATA, + /*ata_flags*/ AP_FLAG_CHK_COND, + /*features*/ 0x00, /* SANITIZE STATUS EXT */ + /*sector_count*/ 0, + /*lba*/ 0, + /*command*/ ATA_SANITIZE, + /*auxiliary*/ 0, + /*data_ptr*/ NULL, + /*dxfer_len*/ 0, + /*cdb_storage*/ NULL, + /*cdb_storage_len*/ 0, + /*sense_len*/ SSD_FULL_SIZE, + /*timeout*/ 10000, + /*is48bit*/ 1, + /*devtype*/ devtype); + if (retval != 0) { + warnx("%s: build_ata_cmd() failed, likely " + "programmer error", __func__); return (1); } - status = ccb->ccb_h.status & CAM_STATUS_MASK; - if (status == CAM_REQ_CMP) { - res = &ccb->ataio.res; - if (res->sector_count_exp & 0x40) { - if (quiet == 0) { - val = (res->lba_mid << 8) + res->lba_low; - perc = 10000 * val; - fprintf(stdout, - "Sanitizing: %u.%02u%% (%d/%d)\r", - (perc / (0x10000 * 100)), - ((perc / 0x10000) % 100), - val, 0x10000); - fflush(stdout); - } - sleep(1); - } else if ((res->sector_count_exp & 0x80) == 0) { - warnx("Sanitize complete with an error. "); - return (1); - } else - break; + ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; + ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; + retval = cam_send_ccb(device, ccb); + if (retval != 0) { + warn("error sending SANITIZE STATUS EXT command"); + return (1); + } - } else if (status != CAM_REQ_CMP && status != CAM_REQUEUE_REQ) { - warnx("Unexpected CAM status %#x", status); - if (arglist & CAM_ARG_VERBOSE) - cam_error_print(device, ccb, CAM_ESF_ALL, - CAM_EPF_ALL, stderr); + retval = get_ata_status(device, ccb, &error, &count, &lba, + &ata_device, &status); + if (retval != 0) { + warnx("Can't get SANITIZE STATUS EXT status, " + "sanitize may still run."); + return (retval); + } + if (status & ATA_STATUS_ERROR) { + warnx("SANITIZE STATUS EXT failed, " + "sanitize may still run."); return (1); } + if (count & 0x4000) { + if (quiet == 0) { + val = lba & 0xffff; + perc = 10000 * val; + fprintf(stdout, + "Sanitizing: %u.%02u%% (%d/%d)\r", + (perc / (0x10000 * 100)), + ((perc / 0x10000) % 100), + val, 0x10000); + fflush(stdout); + } + sleep(1); + } else if ((count & 0x8000) == 0) { + warnx("Sanitize complete with an error. "); + return (1); + } else + break; } while (1); return (0); } @@ -6864,7 +6812,7 @@ sanitize(struct cam_device *device, int argc, char **a } } - if (quiet == 0) { + if (quiet == 0 && ycount == 0) { fprintf(stdout, "You are about to REMOVE ALL DATA from the " "following device:\n"); @@ -6992,7 +6940,7 @@ sanitize(struct cam_device *device, int argc, char **a retry_count, /*flags*/CAM_DIR_NONE, /*protocol*/AP_PROTO_NON_DATA | AP_EXTEND, - /*ata_flags*/AP_FLAG_CHK_COND, + /*ata_flags*/0, /*tag_action*/MSG_SIMPLE_Q_TAG, /*command*/ATA_SANITIZE, /*features*/feature, @@ -7049,7 +6997,7 @@ doreport: if (dt == CC_DT_SCSI) { error = sanitize_wait_scsi(device, ccb, task_attr, quiet); } else if (dt == CC_DT_ATA || dt == CC_DT_SATL) { - error = sanitize_wait_ata(device, ccb, quiet); + error = sanitize_wait_ata(device, ccb, quiet, dt); } else error = 1; if (error == 0 && quiet == 0) @@ -8737,56 +8685,63 @@ bailout: static int atapm_proc_resp(struct cam_device *device, union ccb *ccb) { - struct ata_res *res; + uint8_t error = 0, ata_device = 0, status = 0; + uint16_t count = 0; + uint64_t lba = 0; + int retval; - res = &ccb->ataio.res; - if (res->status & ATA_STATUS_ERROR) { - if (arglist & CAM_ARG_VERBOSE) { - cam_error_print(device, ccb, CAM_ESF_ALL, - CAM_EPF_ALL, stderr); - printf("error = 0x%02x, sector_count = 0x%04x, " - "device = 0x%02x, status = 0x%02x\n", - res->error, res->sector_count, - res->device, res->status); - } + retval = get_ata_status(device, ccb, &error, &count, &lba, &ata_device, + &status); + if (retval == 1) { + if (arglist & CAM_ARG_VERBOSE) { + cam_error_print(device, ccb, CAM_ESF_ALL, + CAM_EPF_ALL, stderr); + } + warnx("Can't get ATA command status"); + return (retval); + } - return (1); - } + if (status & ATA_STATUS_ERROR) { + cam_error_print(device, ccb, CAM_ESF_ALL, + CAM_EPF_ALL, stderr); + return (1); + } - if (arglist & CAM_ARG_VERBOSE) { - fprintf(stdout, "%s%d: Raw native check power data:\n", - device->device_name, device->dev_unit_num); - /* res is 4 byte aligned */ - dump_data((uint16_t*)(uintptr_t)res, sizeof(struct ata_res)); + printf("%s%d: ", device->device_name, device->dev_unit_num); + switch (count) { + case 0x00: + printf("Standby mode\n"); + break; + case 0x01: + printf("Standby_y mode\n"); + break; + case 0x40: + printf("NV Cache Power Mode and the spindle is spun down or spinning down\n"); + break; + case 0x41: + printf("NV Cache Power Mode and the spindle is spun up or spinning up\n"); + break; + case 0x80: + printf("Idle mode\n"); + break; + case 0x81: + printf("Idle_a mode\n"); + break; + case 0x82: + printf("Idle_b mode\n"); + break; + case 0x83: + printf("Idle_c mode\n"); + break; + case 0xff: + printf("Active or Idle mode\n"); + break; + default: + printf("Unknown mode 0x%02x\n", count); + break; + } - printf("error = 0x%02x, sector_count = 0x%04x, device = 0x%02x, " - "status = 0x%02x\n", res->error, res->sector_count, - res->device, res->status); - } - - printf("%s%d: ", device->device_name, device->dev_unit_num); - switch (res->sector_count) { - case 0x00: - printf("Standby mode\n"); - break; - case 0x40: - printf("NV Cache Power Mode and the spindle is spun down or spinning down\n"); - break; - case 0x41: - printf("NV Cache Power Mode and the spindle is spun up or spinning up\n"); - break; - case 0x80: - printf("Idle mode\n"); - break; - case 0xff: - printf("Active or Idle mode\n"); - break; - default: - printf("Unknown mode 0x%02x\n", res->sector_count); - break; - } - - return (0); + return (0); } static int