Mercurial > illumos > illumos-gate
changeset 3652:fe555d5eb825
PSARC 2006/410 ATA Update FW support
6275400 x86: ATA drive firmware download facility
author | yt160523 |
---|---|
date | Wed, 14 Feb 2007 19:20:08 -0800 |
parents | 4f213d35e5f9 |
children | b023d36e83d9 |
files | usr/src/uts/common/sys/dkio.h usr/src/uts/intel/io/dktp/controller/ata/ata_common.c usr/src/uts/intel/io/dktp/controller/ata/ata_common.h usr/src/uts/intel/io/dktp/controller/ata/ata_disk.c usr/src/uts/intel/io/dktp/controller/ata/ata_disk.h usr/src/uts/intel/io/dktp/dcdev/dadk.c |
diffstat | 6 files changed, 512 insertions(+), 24 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/uts/common/sys/dkio.h Wed Feb 14 17:53:56 2007 -0800 +++ b/usr/src/uts/common/sys/dkio.h Wed Feb 14 19:20:08 2007 -0800 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -400,6 +400,76 @@ #endif #endif /* _MULTI_DATAMODEL */ +/* + * The ioctl is used to fetch disk's device type, vendor ID, + * model number/product ID, firmware revision and serial number together. + * + * Currently there are two device types - DKD_ATA_TYPE which means the + * disk is driven by cmdk/ata or dad/uata driver, and DKD_SCSI_TYPE + * which means the disk is driven by sd/scsi hba driver. + */ +#define DKIOC_GETDISKID (DKIOC|46) + +/* These two labels are for dkd_dtype of dk_disk_id_t */ +#define DKD_ATA_TYPE 0x01 /* ATA disk or legacy mode SATA disk */ +#define DKD_SCSI_TYPE 0x02 /* SCSI disk or native mode SATA disk */ + +#define DKD_ATA_MODEL 40 /* model number length */ +#define DKD_ATA_FWVER 8 /* firmware revision length */ +#define DKD_ATA_SERIAL 20 /* serial number length */ + +#define DKD_SCSI_VENDOR 8 /* vendor ID length */ +#define DKD_SCSI_PRODUCT 16 /* product ID length */ +#define DKD_SCSI_REVLEVEL 4 /* revision level length */ +#define DKD_SCSI_SERIAL 12 /* serial number length */ + +/* + * The argument type for DKIOC_GETDISKID ioctl. + */ +typedef struct dk_disk_id { + uint_t dkd_dtype; + union { + struct { + char dkd_amodel[DKD_ATA_MODEL]; /* 40 bytes */ + char dkd_afwver[DKD_ATA_FWVER]; /* 8 bytes */ + char dkd_aserial[DKD_ATA_SERIAL]; /* 20 bytes */ + } ata_disk_id; + struct { + char dkd_svendor[DKD_SCSI_VENDOR]; /* 8 bytes */ + char dkd_sproduct[DKD_SCSI_PRODUCT]; /* 16 bytes */ + char dkd_sfwver[DKD_SCSI_REVLEVEL]; /* 4 bytes */ + char dkd_sserial[DKD_SCSI_SERIAL]; /* 12 bytes */ + } scsi_disk_id; + } disk_id; +} dk_disk_id_t; + +/* + * The ioctl is used to update the firmware of device. + */ +#define DKIOC_UPDATEFW (DKIOC|47) + +/* The argument type for DKIOC_UPDATEFW ioctl */ +typedef struct dk_updatefw { + caddr_t dku_ptrbuf; /* pointer to firmware buf */ + uint_t dku_size; /* firmware buf length */ + uint8_t dku_type; /* firmware update type */ +} dk_updatefw_t; + +#ifdef _SYSCALL32 +typedef struct dk_updatefw_32 { + caddr32_t dku_ptrbuf; /* pointer to firmware buf */ + uint_t dku_size; /* firmware buf length */ + uint8_t dku_type; /* firmware update type */ +} dk_updatefw_32_t; +#endif /* _SYSCALL32 */ + +/* + * firmware update type - temporary or permanent use + */ +#define FW_TYPE_TEMP 0x0 /* temporary use */ +#define FW_TYPE_PERM 0x1 /* permanent use */ + + #ifdef __cplusplus } #endif
--- a/usr/src/uts/intel/io/dktp/controller/ata/ata_common.c Wed Feb 14 17:53:56 2007 -0800 +++ b/usr/src/uts/intel/io/dktp/controller/ata/ata_common.c Wed Feb 14 19:20:08 2007 -0800 @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -146,8 +146,6 @@ */ int ata_capability_data = FALSE; -#define ATAPRT(fmt) ghd_err fmt - /* * DMA selection message pointers */
--- a/usr/src/uts/intel/io/dktp/controller/ata/ata_common.h Wed Feb 14 17:53:56 2007 -0800 +++ b/usr/src/uts/intel/io/dktp/controller/ata/ata_common.h Wed Feb 14 19:20:08 2007 -0800 @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -64,7 +64,10 @@ */ #define MAX_28BIT_CAPACITY 0xfffffff - +/* + * Largest sector count allowed for device firmware file in one command. + */ +#define MAX_FWFILE_SIZE_ONECMD 0xffff /* * ata-options property configuration bits @@ -72,7 +75,7 @@ #define ATA_OPTIONS_DMA 0x01 - +#define ATAPRT(fmt) ghd_err fmt /* ad_flags (per-drive) */ @@ -375,6 +378,7 @@ #define ATA_ID_REM_DRV 0x80 #define ATA_ID_COMPACT_FLASH 0x848a #define ATA_ID_CF_TO_ATA 0x040a +#define ATA_ID_INCMPT 0x0004 /* Identify Drive: common capability bits - word 49 */ @@ -412,6 +416,7 @@ /* Identify Drive: ai_majorversion (word 80) */ +#define ATAC_MAJVER_8 0x0100 /* ATA/ATAPI-8 version supported */ #define ATAC_MAJVER_6 0x0040 /* ATA/ATAPI-6 version supported */ #define ATAC_MAJVER_4 0x0010 /* ATA/ATAPI-4 version supported */
--- a/usr/src/uts/intel/io/dktp/controller/ata/ata_disk.c Wed Feb 14 17:53:56 2007 -0800 +++ b/usr/src/uts/intel/io/dktp/controller/ata/ata_disk.c Wed Feb 14 19:20:08 2007 -0800 @@ -117,6 +117,13 @@ static int ata_copy_dk_ioc_string(intptr_t arg, char *source, int length, int flag); static void ata_set_write_cache(ata_ctl_t *ata_ctlp, ata_drv_t *ata_drvp); +static int ata_disk_update_fw(gtgt_t *gtgtp, ata_ctl_t *ata_ctlp, + ata_drv_t *ata_drvp, caddr_t fwfile, uint_t size, + uint8_t type, int flag); +static int ata_disk_set_feature_spinup(ata_ctl_t *ata_ctlp, + ata_drv_t *ata_drvp, ata_pkt_t *ata_pktp); +static int ata_disk_id_update(ata_ctl_t *ata_ctlp, + ata_drv_t *ata_drvp, ata_pkt_t *ata_pktp); /* @@ -127,6 +134,9 @@ uint_t ata_disk_set_mult_wait = 4 * 1000000; int ata_disk_do_standby_timer = TRUE; +/* timeout value for device update firmware */ +int ata_disk_updatefw_time = 60; + /* * ata_write_cache == 1 force write cache on. * ata_write_cache == 0 do not modify write cache. firmware defaults kept. @@ -942,10 +952,18 @@ gtgt_t *gtgtp = (gtgt_t *)ctl_data; ata_ctl_t *ata_ctlp = GTGTP2ATAP(gtgtp); ata_drv_t *ata_drvp = GTGTP2ATADRVP(gtgtp); - int rc; + int rc, rc2; struct tgdk_geom tgdk; int wce; struct ata_id *aidp = &ata_drvp->ad_id; + dk_updatefw_t updatefw; +#ifdef _MULTI_DATAMODEL + dk_updatefw_32_t updatefw32; +#endif + dk_disk_id_t dk_disk_id; + char buf[80]; + int i; + ADBG_TRACE(("ata_disk_ioctl entered, cmd = %d\n", cmd)); @@ -976,7 +994,7 @@ sizeof (aidp->ai_model), flag); return (rc); - /* copy the model number into the caller's buffer */ + /* copy the serial number into the caller's buffer */ case DIOCTL_GETSERIAL: rc = ata_copy_dk_ioc_string(arg, aidp->ai_drvser, sizeof (aidp->ai_drvser), @@ -1039,6 +1057,155 @@ gtgtp); break; + case DKIOC_UPDATEFW: + + /* + * Call DOWNLOAD MICROCODE command to update device + * firmware. + * + * return value: + * normal 0 Download microcode success + * error EFAULT Bad address + * ENXIO No such device or address + * EINVAL Invalid argument + * ENOMEM Not enough core + * ENOTSUP Operation not supported + * EIO I/O error + * EPERM Not owner + */ + + /* + * The following code deals with handling 32-bit request + * in 64-bit kernel. + */ +#ifdef _MULTI_DATAMODEL + if (ddi_model_convert_from(flag & FMODELS) == + DDI_MODEL_ILP32) { + if (ddi_copyin((void *)arg, &updatefw32, + sizeof (dk_updatefw_32_t), flag)) + return (EFAULT); + + updatefw.dku_ptrbuf = + (caddr_t)(uintptr_t)updatefw32.dku_ptrbuf; + updatefw.dku_size = updatefw32.dku_size; + updatefw.dku_type = updatefw32.dku_type; + } else { + if (ddi_copyin((void *)arg, &updatefw, + sizeof (dk_updatefw_t), flag)) + return (EFAULT); + } +#else + if (ddi_copyin((void *)arg, &updatefw, + sizeof (dk_updatefw_t), flag)) + return (EFAULT); +#endif + rc = ata_disk_update_fw(gtgtp, ata_ctlp, ata_drvp, + updatefw.dku_ptrbuf, updatefw.dku_size, + updatefw.dku_type, flag); + + /* + * According to ATA8-ACS spec, the new microcode should + * become effective immediately after the transfer of the + * last data segment has completed, so here we will call + * IDENTIFY DEVICE command immediately to update + * ata_id content when success. + */ + if (rc == 0) { + rc2 = ata_queue_cmd(ata_disk_id_update, NULL, + ata_ctlp, ata_drvp, gtgtp); + if (rc2 != TRUE) { + return (ENXIO); + } else { + /* + * Check whether the content of the IDENTIFY + * DEVICE data is incomplete, if yes, it's + * because the device supports the Power-up + * in Standby feature set, and we will first + * check word 2, and then decide whether need + * to call set feature to spin-up the device, + * and then call IDENTIFY DEVICE command again. + */ + aidp = &ata_drvp->ad_id; + if (aidp->ai_config & ATA_ID_INCMPT) { + if (aidp->ai_resv0 == 0x37c8 || + aidp->ai_resv0 == 0x738c) { + /* Spin-up the device */ + (void) ata_queue_cmd( + ata_disk_set_feature_spinup, + NULL, + ata_ctlp, + ata_drvp, + gtgtp); + } + + /* Try to update ata_id again */ + rc2 = ata_queue_cmd( + ata_disk_id_update, + NULL, + ata_ctlp, + ata_drvp, + gtgtp); + if (rc2 != TRUE) { + return (ENXIO); + } else { + aidp = &ata_drvp->ad_id; + if (aidp->ai_config & + ATA_ID_INCMPT) + return (ENXIO); + } + } + + /* + * Dump the drive information. + */ + ATAPRT(("?\tUpdate firmware of %s device at " + "targ %d, lun %d lastlun 0x%x\n", + (ATAPIDRV(ata_drvp) ? "ATAPI":"IDE"), + ata_drvp->ad_targ, ata_drvp->ad_lun, + aidp->ai_lastlun)); + + (void) strncpy(buf, aidp->ai_model, + sizeof (aidp->ai_model)); + buf[sizeof (aidp->ai_model)] = '\0'; + for (i = sizeof (aidp->ai_model) - 1; + buf[i] == ' '; i--) + buf[i] = '\0'; + ATAPRT(("?\tmodel %s\n", buf)); + + (void) strncpy(buf, aidp->ai_fw, + sizeof (aidp->ai_fw)); + buf[sizeof (aidp->ai_fw)] = '\0'; + for (i = sizeof (aidp->ai_fw) - 1; + buf[i] == ' '; i--) + buf[i] = '\0'; + ATAPRT(("?\tfw %s\n", buf)); + } + } + return (rc); + + case DKIOC_GETDISKID: + bzero(&dk_disk_id, sizeof (dk_disk_id_t)); + + dk_disk_id.dkd_dtype = DKD_ATA_TYPE; + + /* Get the model number */ + (void) strncpy(dk_disk_id.disk_id.ata_disk_id.dkd_amodel, + aidp->ai_model, sizeof (aidp->ai_model)); + + /* Get the firmware revision */ + (void) strncpy(dk_disk_id.disk_id.ata_disk_id.dkd_afwver, + aidp->ai_fw, sizeof (aidp->ai_fw)); + + /* Get the serial number */ + (void) strncpy(dk_disk_id.disk_id.ata_disk_id.dkd_aserial, + aidp->ai_drvser, sizeof (aidp->ai_drvser)); + + if (ddi_copyout(&dk_disk_id, (void *)arg, + sizeof (dk_disk_id_t), flag)) + return (EFAULT); + else + return (0); + default: ADBG_WARN(("ata_disk_ioctl: unsupported cmd 0x%x\n", cmd)); return (ENOTTY); @@ -1749,19 +1916,33 @@ return (FALSE); } - /* - * We use different methods for loading the task file - * registers, depending on whether the disk - * uses LBA or CHS addressing and whether 48-bit - * extended addressing is to be used. - */ - if (!(ata_drvp->ad_drive_bits & ATDH_LBA)) - ata_disk_load_regs_chs(ata_pktp, ata_drvp); - else if (ata_drvp->ad_flags & AD_EXT48) - ata_disk_load_regs_lba48(ata_pktp, ata_drvp); - else - ata_disk_load_regs_lba28(ata_pktp, ata_drvp); - ddi_put8(io_hdl1, ata_ctlp->ac_feature, 0); + if (ata_pktp->ap_cmd == ATC_LOAD_FW) { + + /* the sector count is 16 bits wide */ + ddi_put8(io_hdl1, ata_ctlp->ac_count, ata_pktp->ap_count); + ddi_put8(io_hdl1, ata_ctlp->ac_sect, ata_pktp->ap_count >> 8); + ddi_put8(io_hdl1, ata_ctlp->ac_lcyl, ata_pktp->ap_startsec); + ddi_put8(io_hdl1, ata_ctlp->ac_hcyl, + ata_pktp->ap_startsec >> 8); + + /* put subcommand for DOWNLOAD MICROCODE */ + ddi_put8(io_hdl1, ata_ctlp->ac_feature, ata_pktp->ap_bcount); + } else { + + /* + * We use different methods for loading the task file + * registers, depending on whether the disk + * uses LBA or CHS addressing and whether 48-bit + * extended addressing is to be used. + */ + if (!(ata_drvp->ad_drive_bits & ATDH_LBA)) + ata_disk_load_regs_chs(ata_pktp, ata_drvp); + else if (ata_drvp->ad_flags & AD_EXT48) + ata_disk_load_regs_lba48(ata_pktp, ata_drvp); + else + ata_disk_load_regs_lba28(ata_pktp, ata_drvp); + ddi_put8(io_hdl1, ata_ctlp->ac_feature, 0); + } /* * Always make certain interrupts are enabled. It's been reported @@ -2946,3 +3127,216 @@ } } } + +/* + * Call set feature to spin-up the device. + */ +static int +ata_disk_set_feature_spinup( + ata_ctl_t *ata_ctlp, + ata_drv_t *ata_drvp, + ata_pkt_t *ata_pktp) +{ + int rc; + + ADBG_TRACE(("ata_disk_set_feature_spinup entered\n")); + + rc = ata_set_feature(ata_ctlp, ata_drvp, 0x07, 0); + if (!rc) + ata_pktp->ap_flags |= AP_ERROR; + + return (ATA_FSM_RC_FINI); +} + +/* + * Update device ata_id content - IDENTIFY DEVICE command. + */ +static int +ata_disk_id_update( + ata_ctl_t *ata_ctlp, + ata_drv_t *ata_drvp, + ata_pkt_t *ata_pktp) +{ + ddi_acc_handle_t io_hdl1 = ata_ctlp->ac_iohandle1; + caddr_t ioaddr1 = ata_ctlp->ac_ioaddr1; + ddi_acc_handle_t io_hdl2 = ata_ctlp->ac_iohandle2; + caddr_t ioaddr2 = ata_ctlp->ac_ioaddr2; + struct ata_id *aidp = &ata_drvp->ad_id; + int rc; + + ADBG_TRACE(("ata_disk_id_update entered\n")); + + /* + * select the appropriate drive and LUN + */ + ddi_put8(io_hdl1, (uchar_t *)ioaddr1 + AT_DRVHD, + ata_drvp->ad_drive_bits); + ATA_DELAY_400NSEC(io_hdl2, ioaddr2); + + /* + * make certain the drive is selected, and wait for not busy + */ + if (!ata_wait(io_hdl2, ioaddr2, ATS_DRDY, ATS_BSY, 5 * 1000000)) { + ADBG_ERROR(("ata_disk_id_update: select failed\n")); + ata_pktp->ap_flags |= AP_ERROR; + return (ATA_FSM_RC_FINI); + } + + rc = ata_disk_id(io_hdl1, ioaddr1, io_hdl2, ioaddr2, aidp); + + if (!rc) { + ata_pktp->ap_flags |= AP_ERROR; + } else { + swab(aidp->ai_drvser, aidp->ai_drvser, + sizeof (aidp->ai_drvser)); + swab(aidp->ai_fw, aidp->ai_fw, + sizeof (aidp->ai_fw)); + swab(aidp->ai_model, aidp->ai_model, + sizeof (aidp->ai_model)); + } + + return (ATA_FSM_RC_FINI); +} + +/* + * Update device firmware. + */ +static int +ata_disk_update_fw(gtgt_t *gtgtp, ata_ctl_t *ata_ctlp, + ata_drv_t *ata_drvp, caddr_t fwfile, + uint_t size, uint8_t type, int flag) +{ + ata_pkt_t *ata_pktp; + gcmd_t *gcmdp = NULL; + caddr_t fwfile_memp = NULL, tmp_fwfile_memp; + uint_t total_sec_count, sec_count, start_sec = 0; + uint8_t cmd_type; + int rc; + + /* + * First check whether DOWNLOAD MICROCODE command is supported + */ + if (!(ata_drvp->ad_id.ai_cmdset83 & 0x1)) { + ADBG_ERROR(("drive doesn't support download " + "microcode command\n")); + return (ENOTSUP); + } + + switch (type) { + case FW_TYPE_TEMP: + cmd_type = ATCM_FW_TEMP; + break; + + case FW_TYPE_PERM: + cmd_type = ATCM_FW_PERM; + break; + + default: + return (EINVAL); + } + + /* Temporary subcommand is obsolete in ATA/ATAPI-8 version */ + if (cmd_type == ATCM_FW_TEMP) { + if (ata_drvp->ad_id.ai_majorversion & ATAC_MAJVER_8) { + ADBG_ERROR(("Temporary use is obsolete in " + "ATA/ATAPI-8 version\n")); + return (ENOTSUP); + } + } + + total_sec_count = size >> SCTRSHFT; + if (total_sec_count > MAX_FWFILE_SIZE_ONECMD) { + if (cmd_type == ATCM_FW_TEMP) { + ADBG_ERROR(("firmware size: %x sectors is too large\n", + total_sec_count)); + return (EINVAL); + } else { + ADBG_WARN(("firmware size: %x sectors is larger than" + " one command, need to use the multicommand" + " subcommand\n", total_sec_count)); + + cmd_type = ATCM_FW_MULTICMD; + if (!(ata_drvp->ad_id.ai_padding2[15] & 0x10)) { + ADBG_ERROR(("This drive doesn't support " + "the multicommand subcommand\n")); + return (ENOTSUP); + } + } + } + + fwfile_memp = kmem_zalloc(size, KM_SLEEP); + + if (ddi_copyin(fwfile, fwfile_memp, size, flag)) { + ADBG_ERROR(("ata_disk_update_fw copyin failed\n")); + rc = EFAULT; + goto done; + } + + tmp_fwfile_memp = fwfile_memp; + + for (; total_sec_count > 0; ) { + if ((gcmdp == NULL) && !(gcmdp = + ghd_gcmd_alloc(gtgtp, sizeof (*ata_pktp), TRUE))) { + ADBG_ERROR(("ata_disk_update_fw alloc failed\n")); + rc = ENOMEM; + goto done; + } + + /* set the back ptr from the ata_pkt to the gcmd_t */ + ata_pktp = GCMD2APKT(gcmdp); + ata_pktp->ap_gcmdp = gcmdp; + ata_pktp->ap_hd = ata_drvp->ad_drive_bits; + ata_pktp->ap_bytes_per_block = ata_drvp->ad_bytes_per_block; + + /* use PIO mode to update disk firmware */ + ata_pktp->ap_start = ata_disk_start_pio_out; + ata_pktp->ap_intr = ata_disk_intr_pio_out; + ata_pktp->ap_complete = NULL; + + ata_pktp->ap_cmd = ATC_LOAD_FW; + /* use ap_bcount to set subcommand code */ + ata_pktp->ap_bcount = (size_t)cmd_type; + ata_pktp->ap_pciide_dma = FALSE; + ata_pktp->ap_sg_cnt = 0; + + sec_count = min(total_sec_count, MAX_FWFILE_SIZE_ONECMD); + ata_pktp->ap_flags = 0; + + ata_pktp->ap_count = sec_count; + ata_pktp->ap_startsec = start_sec; + ata_pktp->ap_v_addr = tmp_fwfile_memp; + ata_pktp->ap_resid = sec_count << SCTRSHFT; + + /* add it to the queue, and use POLL mode */ + rc = ghd_transport(&ata_ctlp->ac_ccc, gcmdp, gcmdp->cmd_gtgtp, + ata_disk_updatefw_time, TRUE, NULL); + + if (rc != TRAN_ACCEPT) { + /* this should never, ever happen */ + rc = ENOTSUP; + goto done; + } + + if (ata_pktp->ap_flags & AP_ERROR) { + if (ata_pktp->ap_error & ATE_ABORT) { + rc = ENOTSUP; + } else + rc = EIO; + goto done; + + } else { + total_sec_count -= sec_count; + tmp_fwfile_memp += sec_count << SCTRSHFT; + start_sec += sec_count; + } + } + + rc = 0; +done: + if (gcmdp != NULL) + ghd_gcmd_free(gcmdp); + + kmem_free(fwfile_memp, size); + + return (rc); +}
--- a/usr/src/uts/intel/io/dktp/controller/ata/ata_disk.h Wed Feb 14 17:53:56 2007 -0800 +++ b/usr/src/uts/intel/io/dktp/controller/ata/ata_disk.h Wed Feb 14 19:20:08 2007 -0800 @@ -2,7 +2,7 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). + * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE @@ -20,7 +20,7 @@ */ /* - * Copyright 2002 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -50,6 +50,7 @@ #define ATC_SETPARAM 0x91 /* set parameters command */ #define ATC_ID_DEVICE 0xec /* IDENTIFY DEVICE command */ #define ATC_ACK_MC 0xdb /* acknowledge media change */ +#define ATC_LOAD_FW 0x92 /* download microcode */ /* ATA extended (48 bit) disk commands */ #define ATC_RDSEC_EXT 0x24 /* read sector */ #define ATC_RDMULT_EXT 0x29 /* read multiple */ @@ -65,6 +66,13 @@ /* enabled if bit is CLEARED!!! */ #define ATCM_LONGMODE 0x02 /* Use Long Mode (get/send data & ECC) */ +/* + * subcommand for DOWNLOAD MICROCODE command + */ +#define ATCM_FW_TEMP 0x01 /* immediate, temporary use */ +#define ATCM_FW_MULTICMD 0x03 /* immediate and future use */ +#define ATCM_FW_PERM 0x07 /* immediate and future use */ + #ifdef DADKIO_RWCMD_READ #define RWCMDP(pktp) ((struct dadkio_rwcmd *)((pktp)->cp_bp->b_back)) #endif
--- a/usr/src/uts/intel/io/dktp/dcdev/dadk.c Wed Feb 14 17:53:56 2007 -0800 +++ b/usr/src/uts/intel/io/dktp/dcdev/dadk.c Wed Feb 14 19:20:08 2007 -0800 @@ -37,6 +37,8 @@ #include <sys/dktp/cm.h> #include <sys/vtoc.h> #include <sys/dkio.h> +#include <sys/policy.h> +#include <sys/priv.h> #include <sys/dktp/dadev.h> #include <sys/dktp/fctypes.h> @@ -794,6 +796,17 @@ return (EINVAL); } } + case DKIOC_UPDATEFW: + + /* + * Require PRIV_ALL privilege to invoke DKIOC_UPDATEFW + * to protect the firmware update from malicious use + */ + if (PRIV_POLICY(cred_p, PRIV_ALL, B_FALSE, EPERM, NULL) != 0) + return (EPERM); + else + return (CTL_IOCTL(dadkp->dad_ctlobjp, cmd, arg, flag)); + case DKIOCFLUSHWRITECACHE: { struct buf *bp;