1 /*- 2 * Copyright (c) 2011 Sandvine Incorporated. All rights reserved. 3 * Copyright (c) 2002-2011 Andre Albsmeier <andre@albsmeier.net> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer, 11 * without modification, immediately at the beginning of the file. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 /* 29 * This software is derived from Andre Albsmeier's fwprog.c which contained 30 * the following note: 31 * 32 * Many thanks goes to Marc Frajola <marc@terasolutions.com> from 33 * TeraSolutions for the initial idea and his programme for upgrading 34 * the firmware of I*M DDYS drives. 35 */ 36 37 /* 38 * BEWARE: 39 * 40 * The fact that you see your favorite vendor listed below does not 41 * imply that your equipment won't break when you use this software 42 * with it. It only means that the firmware of at least one device type 43 * of each vendor listed has been programmed successfully using this code. 44 * 45 * The -s option simulates a download but does nothing apart from that. 46 * It can be used to check what chunk sizes would have been used with the 47 * specified device. 48 */ 49 50 #include <sys/cdefs.h> 51 __FBSDID("$FreeBSD$"); 52 53 #include <sys/types.h> 54 #include <sys/stat.h> 55 56 #include <err.h> 57 #include <fcntl.h> 58 #include <stdio.h> 59 #include <stdlib.h> 60 #include <string.h> 61 #include <unistd.h> 62 63 #include <cam/scsi/scsi_all.h> 64 #include <cam/scsi/scsi_message.h> 65 #include <camlib.h> 66 67 #include "camcontrol.h" 68 69 #define CMD_TIMEOUT 50000 /* 50 seconds */ 70 71 typedef enum { 72 VENDOR_HITACHI, 73 VENDOR_HP, 74 VENDOR_IBM, 75 VENDOR_PLEXTOR, 76 VENDOR_QUANTUM, 77 VENDOR_SEAGATE, 78 VENDOR_UNKNOWN 79 } fw_vendor_t; 80 81 struct fw_vendor { 82 fw_vendor_t type; 83 const char *pattern; 84 int max_pkt_size; 85 u_int8_t cdb_byte2; 86 u_int8_t cdb_byte2_last; 87 int inc_cdb_buffer_id; 88 int inc_cdb_offset; 89 }; 90 91 static const struct fw_vendor vendors_list[] = { 92 {VENDOR_HITACHI, "HITACHI", 0x8000, 0x05, 0x05, 1, 0}, 93 {VENDOR_HP, "HP", 0x8000, 0x07, 0x07, 0, 1}, 94 {VENDOR_IBM, "IBM", 0x8000, 0x05, 0x05, 1, 0}, 95 {VENDOR_PLEXTOR, "PLEXTOR", 0x2000, 0x04, 0x05, 0, 1}, 96 {VENDOR_QUANTUM, "QUANTUM", 0x2000, 0x04, 0x05, 0, 1}, 97 {VENDOR_SEAGATE, "SEAGATE", 0x8000, 0x07, 0x07, 0, 1}, 98 {VENDOR_UNKNOWN, NULL, 0x0000, 0x00, 0x00, 0, 0} 99 }; 100 101 static const struct fw_vendor *fw_get_vendor(struct cam_device *cam_dev); 102 static char *fw_read_img(const char *fw_img_path, 103 const struct fw_vendor *vp, int *num_bytes); 104 static int fw_download_img(struct cam_device *cam_dev, 105 const struct fw_vendor *vp, char *buf, int img_size, 106 int sim_mode, int verbose, int retry_count, int timeout); 107 108 /* 109 * Find entry in vendors list that belongs to 110 * the vendor of given cam device. 111 */ 112 static const struct fw_vendor * 113 fw_get_vendor(struct cam_device *cam_dev) 114 { 115 char vendor[SID_VENDOR_SIZE + 1]; 116 const struct fw_vendor *vp; 117 118 if (cam_dev == NULL) 119 return (NULL); 120 cam_strvis((u_char *)vendor, (u_char *)cam_dev->inq_data.vendor, 121 sizeof(cam_dev->inq_data.vendor), sizeof(vendor)); 122 for (vp = vendors_list; vp->pattern != NULL; vp++) { 123 if (!cam_strmatch((const u_char *)vendor, 124 (const u_char *)vp->pattern, strlen(vendor))) 125 break; 126 } 127 return (vp); 128 } 129 130 /* 131 * Allocate a buffer and read fw image file into it 132 * from given path. Number of bytes read is stored 133 * in num_bytes. 134 */ 135 static char * 136 fw_read_img(const char *fw_img_path, const struct fw_vendor *vp, int *num_bytes) 137 { 138 int fd; 139 struct stat stbuf; 140 char *buf; 141 off_t img_size; 142 int skip_bytes = 0; 143 144 if ((fd = open(fw_img_path, O_RDONLY)) < 0) { 145 warn("Could not open image file %s", fw_img_path); 146 return (NULL); 147 } 148 if (fstat(fd, &stbuf) < 0) { 149 warn("Could not stat image file %s", fw_img_path); 150 goto bailout1; 151 } 152 if ((img_size = stbuf.st_size) == 0) { 153 warnx("Zero length image file %s", fw_img_path); 154 goto bailout1; 155 } 156 if ((buf = malloc(img_size)) == NULL) { 157 warnx("Could not allocate buffer to read image file %s", 158 fw_img_path); 159 goto bailout1; 160 } 161 /* Skip headers if applicable. */ 162 switch (vp->type) { 163 case VENDOR_SEAGATE: 164 if (read(fd, buf, 16) != 16) { 165 warn("Could not read image file %s", fw_img_path); 166 goto bailout; 167 } 168 if (lseek(fd, 0, SEEK_SET) == -1) { 169 warn("Unable to lseek"); 170 goto bailout; 171 } 172 if ((strncmp(buf, "SEAGATE,SEAGATE ", 16) == 0) || 173 (img_size % 512 == 80)) 174 skip_bytes = 80; 175 break; 176 default: 177 break; 178 } 179 if (skip_bytes != 0) { 180 fprintf(stdout, "Skipping %d byte header.\n", skip_bytes); 181 if (lseek(fd, skip_bytes, SEEK_SET) == -1) { 182 warn("Could not lseek"); 183 goto bailout; 184 } 185 img_size -= skip_bytes; 186 } 187 /* Read image into a buffer. */ 188 if (read(fd, buf, img_size) != img_size) { 189 warn("Could not read image file %s", fw_img_path); 190 goto bailout; 191 } 192 *num_bytes = img_size; 193 return (buf); 194 bailout: 195 free(buf); 196 bailout1: 197 close(fd); 198 *num_bytes = 0; 199 return (NULL); 200 } 201 202 /* 203 * Download firmware stored in buf to cam_dev. If simulation mode 204 * is enabled, only show what packet sizes would be sent to the 205 * device but do not sent any actual packets 206 */ 207 static int 208 fw_download_img(struct cam_device *cam_dev, const struct fw_vendor *vp, 209 char *buf, int img_size, int sim_mode, int verbose, int retry_count, 210 int timeout) 211 { 212 struct scsi_write_buffer cdb; 213 union ccb *ccb; 214 int pkt_count = 0; 215 u_int32_t pkt_size = 0; 216 char *pkt_ptr = buf; 217 u_int32_t offset; 218 int last_pkt = 0; 219 220 if ((ccb = cam_getccb(cam_dev)) == NULL) { 221 warnx("Could not allocate CCB"); 222 return (1); 223 } 224 scsi_test_unit_ready(&ccb->csio, 0, NULL, MSG_SIMPLE_Q_TAG, 225 SSD_FULL_SIZE, 5000); 226 /* Disable freezing the device queue. */ 227 ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 228 if (cam_send_ccb(cam_dev, ccb) < 0) { 229 warnx("Error sending test unit ready"); 230 if (verbose) 231 cam_error_print(cam_dev, ccb, CAM_ESF_ALL, 232 CAM_EPF_ALL, stderr); 233 cam_freeccb(ccb); 234 return(1); 235 } 236 if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 237 warnx("Device is not ready"); 238 if (verbose) 239 cam_error_print(cam_dev, ccb, CAM_ESF_ALL, 240 CAM_EPF_ALL, stderr); 241 cam_freeccb(ccb); 242 return (1); 243 } 244 pkt_size = vp->max_pkt_size; 245 if (verbose || sim_mode) { 246 fprintf(stdout, 247 "--------------------------------------------------\n"); 248 fprintf(stdout, 249 "PktNo. PktSize BytesRemaining LastPkt\n"); 250 fprintf(stdout, 251 "--------------------------------------------------\n"); 252 } 253 /* Download single fw packets. */ 254 do { 255 if (img_size <= vp->max_pkt_size) { 256 last_pkt = 1; 257 pkt_size = img_size; 258 } 259 if (verbose || sim_mode) 260 fprintf(stdout, "%3u %5u (0x%05X) %7u (0x%06X) " 261 "%d\n", pkt_count, pkt_size, pkt_size, 262 img_size - pkt_size, img_size - pkt_size, 263 last_pkt); 264 bzero(&cdb, sizeof(cdb)); 265 cdb.opcode = WRITE_BUFFER; 266 cdb.control = 0; 267 /* Parameter list length. */ 268 scsi_ulto3b(pkt_size, &cdb.length[0]); 269 offset = vp->inc_cdb_offset ? (pkt_ptr - buf) : 0; 270 scsi_ulto3b(offset, &cdb.offset[0]); 271 cdb.byte2 = last_pkt ? vp->cdb_byte2_last : vp->cdb_byte2; 272 cdb.buffer_id = vp->inc_cdb_buffer_id ? pkt_count : 0; 273 /* Zero out payload of ccb union after ccb header. */ 274 bzero((u_char *)ccb + sizeof(struct ccb_hdr), 275 sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 276 /* Copy previously constructed cdb into ccb_scsiio struct. */ 277 bcopy(&cdb, &ccb->csio.cdb_io.cdb_bytes[0], 278 sizeof(struct scsi_write_buffer)); 279 /* Fill rest of ccb_scsiio struct. */ 280 if (!sim_mode) { 281 cam_fill_csio(&ccb->csio, /* ccb_scsiio */ 282 retry_count, /* retries */ 283 NULL, /* cbfcnp */ 284 CAM_DIR_OUT | CAM_DEV_QFRZDIS, /* flags */ 285 CAM_TAG_ACTION_NONE, /* tag_action */ 286 (u_char *)pkt_ptr, /* data_ptr */ 287 pkt_size, /* dxfer_len */ 288 SSD_FULL_SIZE, /* sense_len */ 289 sizeof(struct scsi_write_buffer), /* cdb_len */ 290 timeout ? timeout : CMD_TIMEOUT); /* timeout */ 291 /* Execute the command. */ 292 if (cam_send_ccb(cam_dev, ccb) < 0) { 293 warnx("Error writing image to device"); 294 if (verbose) 295 cam_error_print(cam_dev, ccb, CAM_ESF_ALL, 296 CAM_EPF_ALL, stderr); 297 goto bailout; 298 } 299 } 300 /* Prepare next round. */ 301 pkt_count++; 302 pkt_ptr += pkt_size; 303 img_size -= pkt_size; 304 } while(!last_pkt); 305 if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 306 if (verbose) 307 cam_error_print(cam_dev, ccb, CAM_ESF_ALL, 308 CAM_EPF_ALL, stderr); 309 goto bailout; 310 } 311 cam_freeccb(ccb); 312 return (0); 313 bailout: 314 cam_freeccb(ccb); 315 return (1); 316 } 317 318 int 319 fwdownload(struct cam_device *device, int argc, char **argv, 320 char *combinedopt, int verbose, int retry_count, int timeout) 321 { 322 const struct fw_vendor *vp; 323 char *fw_img_path = NULL; 324 char *buf; 325 int img_size; 326 int c; 327 int sim_mode = 0; 328 int confirmed = 0; 329 330 while ((c = getopt(argc, argv, combinedopt)) != -1) { 331 switch (c) { 332 case 's': 333 sim_mode = 1; 334 confirmed = 1; 335 break; 336 case 'f': 337 fw_img_path = optarg; 338 break; 339 case 'y': 340 confirmed = 1; 341 break; 342 default: 343 break; 344 } 345 } 346 347 if (fw_img_path == NULL) 348 errx(1, 349 "you must specify a firmware image file using -f option"); 350 351 vp = fw_get_vendor(device); 352 if (vp == NULL || vp->type == VENDOR_UNKNOWN) 353 errx(1, "Unsupported device"); 354 355 buf = fw_read_img(fw_img_path, vp, &img_size); 356 if (buf == NULL) 357 goto fail; 358 359 if (!confirmed) { 360 fprintf(stdout, "You are about to download firmware image (%s)" 361 " into the following device:\n", 362 fw_img_path); 363 if (scsidoinquiry(device, argc, argv, combinedopt, 0, 364 5000) != 0) { 365 warnx("Error sending inquiry"); 366 goto fail; 367 } 368 fprintf(stdout, "\nIt may damage your drive. "); 369 if (!get_confirmation()) 370 goto fail; 371 } 372 if (sim_mode) 373 fprintf(stdout, "Running in simulation mode\n"); 374 375 if (fw_download_img(device, vp, buf, img_size, sim_mode, verbose, 376 retry_count, timeout) != 0) { 377 fprintf(stderr, "Firmware download failed\n"); 378 goto fail; 379 } else 380 fprintf(stdout, "Firmware download successful\n"); 381 382 free(buf); 383 return (0); 384 fail: 385 if (buf != NULL) 386 free(buf); 387 return (1); 388 } 389 390