1139743Simp/*- 239212Sgibbs * Generic utility routines for the Common Access Method layer. 339212Sgibbs * 439212Sgibbs * Copyright (c) 1997 Justin T. Gibbs. 539212Sgibbs * All rights reserved. 639212Sgibbs * 739212Sgibbs * Redistribution and use in source and binary forms, with or without 839212Sgibbs * modification, are permitted provided that the following conditions 939212Sgibbs * are met: 1039212Sgibbs * 1. Redistributions of source code must retain the above copyright 1139212Sgibbs * notice, this list of conditions, and the following disclaimer, 1239212Sgibbs * without modification, immediately at the beginning of the file. 1339212Sgibbs * 2. The name of the author may not be used to endorse or promote products 1439212Sgibbs * derived from this software without specific prior written permission. 1539212Sgibbs * 1639212Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1739212Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1839212Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1939212Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2039212Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2139212Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2239212Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2339212Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2439212Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2539212Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2639212Sgibbs * SUCH DAMAGE. 2739212Sgibbs */ 28116161Sobrien 29116161Sobrien#include <sys/cdefs.h> 30116161Sobrien__FBSDID("$FreeBSD$"); 31116161Sobrien 3239212Sgibbs#include <sys/param.h> 3374840Sken#ifdef _KERNEL 3474840Sken#include <sys/systm.h> 3589114Smsmith#include <sys/kernel.h> 3689114Smsmith#include <sys/sysctl.h> 3774840Sken#else /* _KERNEL */ 3874840Sken#include <stdlib.h> 3974840Sken#include <stdio.h> 40216088Sken#include <string.h> 41194189Sed#include <camlib.h> 4274840Sken#endif /* _KERNEL */ 4374840Sken 4439212Sgibbs#include <cam/cam.h> 4574840Sken#include <cam/cam_ccb.h> 4674840Sken#include <cam/scsi/scsi_all.h> 47216088Sken#include <cam/scsi/smp_all.h> 4874840Sken#include <sys/sbuf.h> 4939212Sgibbs 5074840Sken#ifdef _KERNEL 5174840Sken#include <sys/libkern.h> 52195534Sscottl#include <cam/cam_queue.h> 5374840Sken#include <cam/cam_xpt.h> 54219028Snetchild 55219028SnetchildFEATURE(scbus, "SCSI devices support"); 56219028Snetchild 5774840Sken#endif 5874840Sken 5974840Skenstatic int camstatusentrycomp(const void *key, const void *member); 6074840Sken 6174840Skenconst struct cam_status_entry cam_status_table[] = { 6274840Sken { CAM_REQ_INPROG, "CCB request is in progress" }, 6374840Sken { CAM_REQ_CMP, "CCB request completed without error" }, 6474840Sken { CAM_REQ_ABORTED, "CCB request aborted by the host" }, 6574840Sken { CAM_UA_ABORT, "Unable to abort CCB request" }, 6674840Sken { CAM_REQ_CMP_ERR, "CCB request completed with an error" }, 67210779Sbcr { CAM_BUSY, "CAM subsystem is busy" }, 6874840Sken { CAM_REQ_INVALID, "CCB request was invalid" }, 6974840Sken { CAM_PATH_INVALID, "Supplied Path ID is invalid" }, 7074840Sken { CAM_DEV_NOT_THERE, "Device Not Present" }, 7174840Sken { CAM_UA_TERMIO, "Unable to terminate I/O CCB request" }, 7274840Sken { CAM_SEL_TIMEOUT, "Selection Timeout" }, 7374840Sken { CAM_CMD_TIMEOUT, "Command timeout" }, 7474840Sken { CAM_SCSI_STATUS_ERROR, "SCSI Status Error" }, 7574840Sken { CAM_MSG_REJECT_REC, "Message Reject Reveived" }, 7674840Sken { CAM_SCSI_BUS_RESET, "SCSI Bus Reset Sent/Received" }, 7774840Sken { CAM_UNCOR_PARITY, "Uncorrectable parity/CRC error" }, 7874840Sken { CAM_AUTOSENSE_FAIL, "Auto-Sense Retrieval Failed" }, 7974840Sken { CAM_NO_HBA, "No HBA Detected" }, 8074840Sken { CAM_DATA_RUN_ERR, "Data Overrun error" }, 8174840Sken { CAM_UNEXP_BUSFREE, "Unexpected Bus Free" }, 8274840Sken { CAM_SEQUENCE_FAIL, "Target Bus Phase Sequence Failure" }, 8374840Sken { CAM_CCB_LEN_ERR, "CCB length supplied is inadequate" }, 8474840Sken { CAM_PROVIDE_FAIL, "Unable to provide requested capability" }, 8574840Sken { CAM_BDR_SENT, "SCSI BDR Message Sent" }, 8674840Sken { CAM_REQ_TERMIO, "CCB request terminated by the host" }, 8774840Sken { CAM_UNREC_HBA_ERROR, "Unrecoverable Host Bus Adapter Error" }, 8874840Sken { CAM_REQ_TOO_BIG, "The request was too large for this host" }, 8974840Sken { CAM_REQUEUE_REQ, "Unconditionally Re-queue Request", }, 90195534Sscottl { CAM_ATA_STATUS_ERROR, "ATA Status Error" }, 91216088Sken { CAM_SCSI_IT_NEXUS_LOST,"Initiator/Target Nexus Lost" }, 92216088Sken { CAM_SMP_STATUS_ERROR, "SMP Status Error" }, 9374840Sken { CAM_IDE, "Initiator Detected Error Message Received" }, 9474840Sken { CAM_RESRC_UNAVAIL, "Resource Unavailable" }, 9574840Sken { CAM_UNACKED_EVENT, "Unacknowledged Event by Host" }, 9674840Sken { CAM_MESSAGE_RECV, "Message Received in Host Target Mode" }, 9774840Sken { CAM_INVALID_CDB, "Invalid CDB received in Host Target Mode" }, 9874840Sken { CAM_LUN_INVALID, "Invalid Lun" }, 9974840Sken { CAM_TID_INVALID, "Invalid Target ID" }, 10074840Sken { CAM_FUNC_NOTAVAIL, "Function Not Available" }, 10174840Sken { CAM_NO_NEXUS, "Nexus Not Established" }, 10274840Sken { CAM_IID_INVALID, "Invalid Initiator ID" }, 10374840Sken { CAM_CDB_RECVD, "CDB Received" }, 10474840Sken { CAM_LUN_ALRDY_ENA, "LUN Already Enabled for Target Mode" }, 10574840Sken { CAM_SCSI_BUSY, "SCSI Bus Busy" }, 10674840Sken}; 10774840Sken 10874840Skenconst int num_cam_status_entries = 10974840Sken sizeof(cam_status_table)/sizeof(*cam_status_table); 11074840Sken 11189114Smsmith#ifdef _KERNEL 11289114SmsmithSYSCTL_NODE(_kern, OID_AUTO, cam, CTLFLAG_RD, 0, "CAM Subsystem"); 113248922Ssmh 114248922Ssmh#ifndef CAM_DEFAULT_SORT_IO_QUEUES 115248922Ssmh#define CAM_DEFAULT_SORT_IO_QUEUES 1 11689114Smsmith#endif 11789114Smsmith 118248922Ssmhint cam_sort_io_queues = CAM_DEFAULT_SORT_IO_QUEUES; 119248922SsmhTUNABLE_INT("kern.cam.sort_io_queues", &cam_sort_io_queues); 120248922SsmhSYSCTL_INT(_kern_cam, OID_AUTO, sort_io_queues, CTLFLAG_RWTUN, 121248922Ssmh &cam_sort_io_queues, 0, "Sort IO queues to try and optimise disk access patterns"); 122248922Ssmh#endif 123248922Ssmh 12439212Sgibbsvoid 12539212Sgibbscam_strvis(u_int8_t *dst, const u_int8_t *src, int srclen, int dstlen) 12639212Sgibbs{ 12739212Sgibbs 12839552Sgibbs /* Trim leading/trailing spaces, nulls. */ 12939212Sgibbs while (srclen > 0 && src[0] == ' ') 13039212Sgibbs src++, srclen--; 13139552Sgibbs while (srclen > 0 13239552Sgibbs && (src[srclen-1] == ' ' || src[srclen-1] == '\0')) 13339212Sgibbs srclen--; 13439212Sgibbs 13539212Sgibbs while (srclen > 0 && dstlen > 1) { 13639212Sgibbs u_int8_t *cur_pos = dst; 13739212Sgibbs 13839212Sgibbs if (*src < 0x20 || *src >= 0x80) { 13939212Sgibbs /* SCSI-II Specifies that these should never occur. */ 14039212Sgibbs /* non-printable character */ 14139212Sgibbs if (dstlen > 4) { 14239212Sgibbs *cur_pos++ = '\\'; 14339212Sgibbs *cur_pos++ = ((*src & 0300) >> 6) + '0'; 14439212Sgibbs *cur_pos++ = ((*src & 0070) >> 3) + '0'; 14539212Sgibbs *cur_pos++ = ((*src & 0007) >> 0) + '0'; 14639212Sgibbs } else { 14739212Sgibbs *cur_pos++ = '?'; 14839212Sgibbs } 14939212Sgibbs } else { 15039212Sgibbs /* normal character */ 15139212Sgibbs *cur_pos++ = *src; 15239212Sgibbs } 15339212Sgibbs src++; 15439212Sgibbs srclen--; 15539212Sgibbs dstlen -= cur_pos - dst; 15639212Sgibbs dst = cur_pos; 15739212Sgibbs } 15839212Sgibbs *dst = '\0'; 15939212Sgibbs} 16039212Sgibbs 16139212Sgibbs/* 16239212Sgibbs * Compare string with pattern, returning 0 on match. 16339212Sgibbs * Short pattern matches trailing blanks in name, 16439212Sgibbs * wildcard '*' in pattern matches rest of name, 16539212Sgibbs * wildcard '?' matches a single non-space character. 16639212Sgibbs */ 16739212Sgibbsint 16839212Sgibbscam_strmatch(const u_int8_t *str, const u_int8_t *pattern, int str_len) 16939212Sgibbs{ 17039212Sgibbs 17139212Sgibbs while (*pattern != '\0'&& str_len > 0) { 17239212Sgibbs 17339212Sgibbs if (*pattern == '*') { 17439212Sgibbs return (0); 17539212Sgibbs } 17639212Sgibbs if ((*pattern != *str) 17739212Sgibbs && (*pattern != '?' || *str == ' ')) { 17839212Sgibbs return (1); 17939212Sgibbs } 18039212Sgibbs pattern++; 18139212Sgibbs str++; 18239212Sgibbs str_len--; 18339212Sgibbs } 184199178Smav while (str_len > 0 && *str == ' ') { 185199178Smav str++; 18639212Sgibbs str_len--; 187199178Smav } 188199178Smav if (str_len > 0 && *str == 0) 189199178Smav str_len = 0; 19039212Sgibbs 19139212Sgibbs return (str_len); 19239212Sgibbs} 19339212Sgibbs 19439212Sgibbscaddr_t 19539212Sgibbscam_quirkmatch(caddr_t target, caddr_t quirk_table, int num_entries, 19639212Sgibbs int entry_size, cam_quirkmatch_t *comp_func) 19739212Sgibbs{ 19839212Sgibbs for (; num_entries > 0; num_entries--, quirk_table += entry_size) { 19939212Sgibbs if ((*comp_func)(target, quirk_table) == 0) 20039212Sgibbs return (quirk_table); 20139212Sgibbs } 20239212Sgibbs return (NULL); 20339212Sgibbs} 20474840Sken 20574840Skenconst struct cam_status_entry* 20674840Skencam_fetch_status_entry(cam_status status) 20774840Sken{ 20874840Sken status &= CAM_STATUS_MASK; 20974840Sken return (bsearch(&status, &cam_status_table, 21074840Sken num_cam_status_entries, 21174840Sken sizeof(*cam_status_table), 21274840Sken camstatusentrycomp)); 21374840Sken} 21474840Sken 21574840Skenstatic int 21674840Skencamstatusentrycomp(const void *key, const void *member) 21774840Sken{ 21874840Sken cam_status status; 21974840Sken const struct cam_status_entry *table_entry; 22074840Sken 22174840Sken status = *(const cam_status *)key; 22274840Sken table_entry = (const struct cam_status_entry *)member; 22374840Sken 22474840Sken return (status - table_entry->status_code); 22574840Sken} 22674840Sken 22774840Sken 22874840Sken#ifdef _KERNEL 22974840Skenchar * 23074840Skencam_error_string(union ccb *ccb, char *str, int str_len, 23174840Sken cam_error_string_flags flags, 23274840Sken cam_error_proto_flags proto_flags) 23374840Sken#else /* !_KERNEL */ 23474840Skenchar * 23574840Skencam_error_string(struct cam_device *device, union ccb *ccb, char *str, 23674840Sken int str_len, cam_error_string_flags flags, 23774840Sken cam_error_proto_flags proto_flags) 23874840Sken#endif /* _KERNEL/!_KERNEL */ 23974840Sken{ 24074840Sken char path_str[64]; 24174840Sken struct sbuf sb; 24274840Sken 24374840Sken if ((ccb == NULL) 24474840Sken || (str == NULL) 24574840Sken || (str_len <= 0)) 24674840Sken return(NULL); 24774840Sken 24874840Sken if (flags == CAM_ESF_NONE) 24974840Sken return(NULL); 25074840Sken 25174840Sken switch (ccb->ccb_h.func_code) { 252198849Smav case XPT_ATA_IO: 253198849Smav switch (proto_flags & CAM_EPF_LEVEL_MASK) { 254198849Smav case CAM_EPF_NONE: 255198849Smav break; 256198849Smav case CAM_EPF_ALL: 257198849Smav case CAM_EPF_NORMAL: 258198849Smav proto_flags |= CAM_EAF_PRINT_RESULT; 259198849Smav /* FALLTHROUGH */ 260198849Smav case CAM_EPF_MINIMAL: 261198849Smav proto_flags |= CAM_EAF_PRINT_STATUS; 262198849Smav /* FALLTHROUGH */ 263198849Smav default: 264198849Smav break; 265198849Smav } 266198849Smav break; 26774840Sken case XPT_SCSI_IO: 26874840Sken switch (proto_flags & CAM_EPF_LEVEL_MASK) { 26974840Sken case CAM_EPF_NONE: 27074840Sken break; 27174840Sken case CAM_EPF_ALL: 27274840Sken case CAM_EPF_NORMAL: 27374840Sken proto_flags |= CAM_ESF_PRINT_SENSE; 27474840Sken /* FALLTHROUGH */ 27574840Sken case CAM_EPF_MINIMAL: 27674840Sken proto_flags |= CAM_ESF_PRINT_STATUS; 277115562Sphk /* FALLTHROUGH */ 27874840Sken default: 27974840Sken break; 28074840Sken } 28174840Sken break; 282216088Sken case XPT_SMP_IO: 283216088Sken switch (proto_flags & CAM_EPF_LEVEL_MASK) { 284216088Sken case CAM_EPF_NONE: 285216088Sken break; 286216088Sken case CAM_EPF_ALL: 287216088Sken proto_flags |= CAM_ESMF_PRINT_FULL_CMD; 288216088Sken /* FALLTHROUGH */ 289216088Sken case CAM_EPF_NORMAL: 290216088Sken case CAM_EPF_MINIMAL: 291216088Sken proto_flags |= CAM_ESMF_PRINT_STATUS; 292216088Sken /* FALLTHROUGH */ 293216088Sken default: 294216088Sken break; 295216088Sken } 296216088Sken break; 29774840Sken default: 29874840Sken break; 29974840Sken } 30074840Sken#ifdef _KERNEL 30174840Sken xpt_path_string(ccb->csio.ccb_h.path, path_str, sizeof(path_str)); 30274840Sken#else /* !_KERNEL */ 30374840Sken cam_path_string(device, path_str, sizeof(path_str)); 30474840Sken#endif /* _KERNEL/!_KERNEL */ 30574840Sken 30674840Sken sbuf_new(&sb, str, str_len, 0); 30774840Sken 30874840Sken if (flags & CAM_ESF_COMMAND) { 30974840Sken sbuf_cat(&sb, path_str); 31074840Sken switch (ccb->ccb_h.func_code) { 311198849Smav case XPT_ATA_IO: 312198849Smav ata_command_sbuf(&ccb->ataio, &sb); 313198849Smav sbuf_printf(&sb, "\n"); 314198849Smav break; 31574840Sken case XPT_SCSI_IO: 31674840Sken#ifdef _KERNEL 31774840Sken scsi_command_string(&ccb->csio, &sb); 31874840Sken#else /* !_KERNEL */ 31974840Sken scsi_command_string(device, &ccb->csio, &sb); 32074840Sken#endif /* _KERNEL/!_KERNEL */ 32174840Sken sbuf_printf(&sb, "\n"); 32274840Sken break; 323216088Sken case XPT_SMP_IO: 324216088Sken smp_command_sbuf(&ccb->smpio, &sb, path_str, 79 - 325216088Sken strlen(path_str), (proto_flags & 326216088Sken CAM_ESMF_PRINT_FULL_CMD) ? 79 : 0); 327216088Sken sbuf_printf(&sb, "\n"); 328216088Sken break; 32974840Sken default: 33074840Sken break; 33174840Sken } 33274840Sken } 33374840Sken 33474840Sken if (flags & CAM_ESF_CAM_STATUS) { 33574840Sken cam_status status; 33674840Sken const struct cam_status_entry *entry; 33774840Sken 33874840Sken sbuf_cat(&sb, path_str); 33974840Sken 34074840Sken status = ccb->ccb_h.status & CAM_STATUS_MASK; 34174840Sken 34274840Sken entry = cam_fetch_status_entry(status); 34374840Sken 34474840Sken if (entry == NULL) 345203108Smav sbuf_printf(&sb, "CAM status: Unknown (%#x)\n", 34674840Sken ccb->ccb_h.status); 34774840Sken else 348203108Smav sbuf_printf(&sb, "CAM status: %s\n", 34974840Sken entry->status_text); 35074840Sken } 35174840Sken 35274840Sken if (flags & CAM_ESF_PROTO_STATUS) { 35374840Sken 35474840Sken switch (ccb->ccb_h.func_code) { 355198849Smav case XPT_ATA_IO: 356198849Smav if ((ccb->ccb_h.status & CAM_STATUS_MASK) != 357198849Smav CAM_ATA_STATUS_ERROR) 358198849Smav break; 359198849Smav if (proto_flags & CAM_EAF_PRINT_STATUS) { 360198849Smav sbuf_cat(&sb, path_str); 361198849Smav ata_status_sbuf(&ccb->ataio, &sb); 362198849Smav sbuf_printf(&sb, "\n"); 363198849Smav } 364198849Smav if (proto_flags & CAM_EAF_PRINT_RESULT) { 365198849Smav sbuf_cat(&sb, path_str); 366198849Smav ata_res_sbuf(&ccb->ataio, &sb); 367198849Smav sbuf_printf(&sb, "\n"); 368198849Smav } 369198849Smav 370198849Smav break; 37174840Sken case XPT_SCSI_IO: 37274840Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != 37374840Sken CAM_SCSI_STATUS_ERROR) 37474840Sken break; 37574840Sken 37674840Sken if (proto_flags & CAM_ESF_PRINT_STATUS) { 37774840Sken sbuf_cat(&sb, path_str); 378203108Smav sbuf_printf(&sb, "SCSI status: %s\n", 37974840Sken scsi_status_string(&ccb->csio)); 38074840Sken } 38174840Sken 38274840Sken if ((proto_flags & CAM_ESF_PRINT_SENSE) 38374840Sken && (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND) 38474840Sken && (ccb->ccb_h.status & CAM_AUTOSNS_VALID)) { 38574840Sken 38674840Sken#ifdef _KERNEL 38774840Sken scsi_sense_sbuf(&ccb->csio, &sb, 38874840Sken SSS_FLAG_NONE); 38974840Sken#else /* !_KERNEL */ 39074840Sken scsi_sense_sbuf(device, &ccb->csio, &sb, 39174840Sken SSS_FLAG_NONE); 39274840Sken#endif /* _KERNEL/!_KERNEL */ 39374840Sken } 39474840Sken break; 395216088Sken case XPT_SMP_IO: 396216088Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != 397216088Sken CAM_SMP_STATUS_ERROR) 398216088Sken break; 399216088Sken 400216088Sken if (proto_flags & CAM_ESF_PRINT_STATUS) { 401216088Sken sbuf_cat(&sb, path_str); 402216088Sken sbuf_printf(&sb, "SMP status: %s (%#x)\n", 403216088Sken smp_error_desc(ccb->smpio.smp_response[2]), 404216088Sken ccb->smpio.smp_response[2]); 405216088Sken } 406216088Sken /* There is no SMP equivalent to SCSI sense. */ 407216088Sken break; 40874840Sken default: 40974840Sken break; 41074840Sken } 41174840Sken } 41274840Sken 41374840Sken sbuf_finish(&sb); 41474840Sken 41574840Sken return(sbuf_data(&sb)); 41674840Sken} 41774840Sken 41874840Sken#ifdef _KERNEL 41974840Sken 42074840Skenvoid 42174840Skencam_error_print(union ccb *ccb, cam_error_string_flags flags, 42274840Sken cam_error_proto_flags proto_flags) 42374840Sken{ 42474840Sken char str[512]; 42574840Sken 42674840Sken printf("%s", cam_error_string(ccb, str, sizeof(str), flags, 42774840Sken proto_flags)); 42874840Sken} 42974840Sken 43074840Sken#else /* !_KERNEL */ 43174840Sken 43274840Skenvoid 43374840Skencam_error_print(struct cam_device *device, union ccb *ccb, 43474840Sken cam_error_string_flags flags, cam_error_proto_flags proto_flags, 43574840Sken FILE *ofile) 43674840Sken{ 43774840Sken char str[512]; 43874840Sken 43974840Sken if ((device == NULL) || (ccb == NULL) || (ofile == NULL)) 44074840Sken return; 44174840Sken 44274840Sken fprintf(ofile, "%s", cam_error_string(device, ccb, str, sizeof(str), 44374840Sken flags, proto_flags)); 44474840Sken} 44574840Sken 44674840Sken#endif /* _KERNEL/!_KERNEL */ 447116350Snjl 448116350Snjl/* 449116350Snjl * Common calculate geometry fuction 450116350Snjl * 451116350Snjl * Caller should set ccg->volume_size and block_size. 452116350Snjl * The extended parameter should be zero if extended translation 453116350Snjl * should not be used. 454116350Snjl */ 455116350Snjlvoid 456116350Snjlcam_calc_geometry(struct ccb_calc_geometry *ccg, int extended) 457116350Snjl{ 458116350Snjl uint32_t size_mb, secs_per_cylinder; 459116350Snjl 460157854Smjacob if (ccg->block_size == 0) { 461157854Smjacob ccg->ccb_h.status = CAM_REQ_CMP_ERR; 462157854Smjacob return; 463157854Smjacob } 464157854Smjacob size_mb = (1024L * 1024L) / ccg->block_size; 465157854Smjacob if (size_mb == 0) { 466157854Smjacob ccg->ccb_h.status = CAM_REQ_CMP_ERR; 467157854Smjacob return; 468157854Smjacob } 469157854Smjacob size_mb = ccg->volume_size / size_mb; 470116350Snjl if (size_mb > 1024 && extended) { 471116350Snjl ccg->heads = 255; 472116350Snjl ccg->secs_per_track = 63; 473116350Snjl } else { 474116350Snjl ccg->heads = 64; 475116350Snjl ccg->secs_per_track = 32; 476116350Snjl } 477116350Snjl secs_per_cylinder = ccg->heads * ccg->secs_per_track; 478157854Smjacob if (secs_per_cylinder == 0) { 479157854Smjacob ccg->ccb_h.status = CAM_REQ_CMP_ERR; 480157854Smjacob return; 481157854Smjacob } 482116350Snjl ccg->cylinders = ccg->volume_size / secs_per_cylinder; 483116350Snjl ccg->ccb_h.status = CAM_REQ_CMP; 484116350Snjl} 485