/* * Given a list of supported mode pages, determine if the given page is present. */ static boolean_t mode_page_present(uchar_t *pgdata, uint_t pgdatalen, uchar_t pagecode) { uint_t i = 0; struct mode_page *pg; boolean_t found = B_FALSE; /* * The mode page list contains all mode pages supported by the device, * one after the other. */ while (i < pgdatalen) { pg = (struct mode_page *)&pgdata[i]; if (pg->code == pagecode) { found = B_TRUE; break; } i += MODESENSE_PAGE_LEN(pg); } return (found); }
static int uscsi_mode_sense(int fd, int page_code, int page_control, caddr_t page_data, int page_size, struct scsi_ms_header *header) { caddr_t mode_sense_buf; struct mode_header *hdr; struct mode_page *pg; int nbytes; struct uscsi_cmd ucmd; union scsi_cdb cdb; int status; int maximum; char rqbuf[255]; /* * Allocate a buffer for the mode sense headers * and mode sense data itself. */ nbytes = sizeof (struct block_descriptor) + sizeof (struct mode_header) + page_size; nbytes = page_size; if ((mode_sense_buf = malloc((uint_t)nbytes)) == NULL) { return (-1); } /* * Build and execute the uscsi ioctl */ (void) memset(mode_sense_buf, 0, nbytes); (void) memset((char *)&ucmd, 0, sizeof (ucmd)); (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); cdb.scc_cmd = SCMD_MODE_SENSE; FORMG0COUNT(&cdb, (uchar_t)nbytes); cdb.cdb_opaque[2] = page_control | page_code; ucmd.uscsi_cdb = (caddr_t)&cdb; ucmd.uscsi_cdblen = CDB_GROUP0; ucmd.uscsi_bufaddr = mode_sense_buf; ucmd.uscsi_buflen = nbytes; ucmd.uscsi_flags |= USCSI_SILENT; ucmd.uscsi_flags |= USCSI_READ; ucmd.uscsi_timeout = 30; ucmd.uscsi_flags |= USCSI_RQENABLE; if (ucmd.uscsi_rqbuf == NULL) { ucmd.uscsi_rqbuf = rqbuf; ucmd.uscsi_rqlen = sizeof (rqbuf); ucmd.uscsi_rqresid = sizeof (rqbuf); } ucmd.uscsi_rqstatus = IMPOSSIBLE_SCSI_STATUS; status = ioctl(fd, USCSICMD, &ucmd); if (status || ucmd.uscsi_status != 0) { free(mode_sense_buf); return (-1); } /* * Verify that the returned data looks reasonabled, * find the actual page data, and copy it into the * user's buffer. Copy the mode_header and block_descriptor * into the header structure, which can then be used to * return the same data to the drive when issuing a mode select. */ hdr = (struct mode_header *)mode_sense_buf; (void) memset((caddr_t)header, 0, sizeof (struct scsi_ms_header)); if (hdr->bdesc_length != sizeof (struct block_descriptor) && hdr->bdesc_length != 0) { free(mode_sense_buf); return (-1); } (void) memcpy((caddr_t)header, mode_sense_buf, (int) (sizeof (struct mode_header) + hdr->bdesc_length)); pg = (struct mode_page *)((ulong_t)mode_sense_buf + sizeof (struct mode_header) + hdr->bdesc_length); if (pg->code != page_code) { free(mode_sense_buf); return (-1); } /* * Accept up to "page_size" bytes of mode sense data. * This allows us to accept both CCS and SCSI-2 * structures, as long as we request the greater * of the two. */ maximum = page_size - sizeof (struct mode_page) - hdr->bdesc_length; if (((int)pg->length) > maximum) { free(mode_sense_buf); return (-1); } (void) memcpy(page_data, (caddr_t)pg, MODESENSE_PAGE_LEN(pg)); free(mode_sense_buf); return (0); }